# Console colours

> consoleColor puts a colour on a console's steps where it is chosen, so dither leaves it flat and still patterns a gradient.

Example `console-color`, running at https://nacatamalon.com/en/examples/console-color. The whole catalogue: https://nacatamalon.com/llms/examples.md.

`dither()` leaves a colour that is on one of its steps flat and puts its pattern on everything in between, which is what a gradient is. A screen effect only sees pixels, so it cannot tell a tile meant to be flat from a sky meant to be dithered.

`consoleColor(colour, POST_EFFECTS.COLOR_LEVELS.genesis)` puts the colour on the steps where it is chosen: the tiles come out flat, and the sky still gets the pattern. The fewer steps a console had, the further the flat colour lands from the one asked for. `POST_EFFECTS.COLOR_LEVELS` has the Master System, Mega Drive, PC Engine, Game Gear, SNES, PlayStation, Saturn, Nintendo 64, Dreamcast and GameCube.

Click the preview first so it hears the keyboard. C changes console, from a Master System's 4 steps to a GameCube's 64. D switches the dither off and on, to see both rows look alike underneath.

## Code

`index.ts`:

```ts
import { createGame } from 'nacatamalon';

import * as Settings from './settings';
import { Scene } from './scenes/demo';

const game = createGame('#app', {
    width: Settings.WIDTH,
    height: Settings.HEIGHT,
    scaling: 'integer',
});

// Declare Scenes
game({
    Scene
});
```

`components/comparison.ts`:

```ts
import { consoleColor, createSprite, createText, getColor, useKeyboard, useUpdate, useSpawn } from 'nacatamalon';

import { dither, usePostProcess } from 'nacatamalon/effects';
import * as Settings from '../settings';

import { Sky } from './sky';

export const Comparison = () => {
    const keyboard = useKeyboard();
    let current = 1;

    const pattern = usePostProcess(dither({
        levels: Settings.CONSOLES[current].levels
    }));

    useSpawn(Sky)();

    const label = (text: string, y: number) => createText({
        text,
        anchor: {
            x: 0.5,
            y: 0
        },
        transform: {
            x: Settings.WIDTH / 2,
            y
        }
    });

    const title = label('', 8);

    label('AS WRITTEN', 30);
    label('consoleColor()', 100);

    const status = label('', 160);

    const flat = Settings.COLOURS.map((colour, i) => {
        const x = 64 + i * 48;

        createSprite({
            width: 32,
            height: 32,
            tint: getColor(colour),
            transform: {
                x,
                y: 64
            }
        });

        return createSprite({
            width: 32,
            height: 32,
            transform: {
                x,
                y: 134
            }
        });
    });

    // The dither and the bottom row's colours both follow the console chosen.
    const show = () => {
        const { name, levels } = Settings.CONSOLES[current];

        pattern.uniforms.levels = levels;
        flat.forEach((tile, i) => {
            tile.tint = consoleColor(Settings.COLOURS[i], levels);
        });
        title.text = name;
        status.text = 'C: CONSOLE  D: DITHER ' + (pattern.enabled ? 'ON' : 'OFF');
    };

    show();

    useUpdate(() => {
        if (keyboard.justPressed('c')) {
            current = (current + 1) % Settings.CONSOLES.length;
            show();
        }

        if (keyboard.justPressed('d')) {
            pattern.enabled = !pattern.enabled;
            show();
        }
    });
};
```

`components/sky.ts`:

```ts
import { createSprite } from 'nacatamalon';
import { createPixels, createPixelTexture, fillGradient } from 'nacatamalon/pixels';

import * as Settings from '../settings';

export const Sky = () => {
    // The sky: a smooth gradient painted in code.
    const sky = createPixels(Settings.WIDTH, Settings.HEIGHT);

    fillGradient(sky, {
        colors: ['#0a0820', '#3d1d5c', '#6a2a5e']
    });
    createSprite({
        width: Settings.WIDTH,
        height: Settings.HEIGHT,
        texture: createPixelTexture(sky),
        anchor: {
            x: 0,
            y: 0
        }
    });
};
```

`scenes/demo.ts`:

```ts
import { createScene, useSpawn } from 'nacatamalon';

import { Comparison } from '../components/comparison';

export const Scene = () => {
    useSpawn(Comparison)();

    return createScene();
};
```

`settings.ts`:

```ts
import { POST_EFFECTS } from 'nacatamalon/effects';

export const WIDTH = 320;
export const HEIGHT = 180;
export const COLOURS = ['#e8423f', '#3f7ee8', '#46c25a', '#f2c230', '#b04fd1'];

// Consoles that kept the same steps share a line: they look the same here.
export const CONSOLES = [
    {
        name: 'MASTER SYSTEM (4)',
        levels: POST_EFFECTS.COLOR_LEVELS.masterSystem
    },
    {
        name: 'MEGA DRIVE, PC ENGINE (8)',
        levels: POST_EFFECTS.COLOR_LEVELS.genesis
    },
    {
        name: 'GAME GEAR (16)',
        levels: POST_EFFECTS.COLOR_LEVELS.gameGear
    },
    {
        name: 'SNES PS1 SATURN N64 DC (32)',
        levels: POST_EFFECTS.COLOR_LEVELS.snes
    },
    {
        name: 'GAMECUBE (64)',
        levels: POST_EFFECTS.COLOR_LEVELS.gameCube
    },
];
```
