# Console palettes

> One picture held to the colours of three machines with snapToPalette, the cells over the limit marked by checkColorLimit.

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

The colours of three machines come with the engine, in `BUILTIN.PALETTES`. `snapToPalette` moves every pixel of a picture to the nearest of them, and `checkColorLimit` says which cells use more colours than a machine could: here, each 8 by 8 with more than four is marked in red.

Click the preview first so it hears the keyboard. Space sends the whole screen through `paletteMatch` with the Game Boy's colours, from `useLoadPalette({ src: 'nacatamalon:gameBoy' })`, with no file.

## Code

`index.ts`:

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

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

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

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

`art/landscape.ts`:

```ts
import { createPixels, fillCircle, fillGradient, fillRect } from 'nacatamalon/pixels';

export const createLandscape = () => {
    const art = createPixels(64, 48);

    fillGradient(art, {
        colors: ['#1b1464', '#c2388b', '#ffb347']
    });
    fillCircle(art, 44, 16, 9, '#fff3b0');
    fillRect(art, 0, 36, 64, 12, '#1f6f54');
    fillCircle(art, 14, 40, 10, '#2fa36b');

    return art;
};
```

`components/card.ts`:

```ts
import { createSprite, createText } from 'nacatamalon';
import { checkColorLimit, clonePixels, createPixelTexture, fillRect, snapToPalette } from 'nacatamalon/pixels';

import * as Settings from '../settings';
import type { TPixels } from 'nacatamalon/pixels';

export const Card = ({ name, colors, at, art }: { name: string; colors: readonly string[]|null; at: number; art: TPixels; }) => {
    const picture = clonePixels(art);

    if (colors !== null) {
        snapToPalette(picture, colors);
    }

    // Read before marking, so the marks are not counted as colours.
    const over = checkColorLimit(picture, {
        cell: 8,
        colors: Settings.LIMIT
    });

    const marked = clonePixels(picture);

    for (const cell of over) {
        fillRect(marked, cell.x, cell.y, cell.width, 1, '#ff0040');
        fillRect(marked, cell.x, cell.y, 1, cell.height, '#ff0040');
    }

    const x = 8 + (at % 2) * 76;
    const y = 16 + Math.floor(at / 2) * 74;

    createSprite({
        texture: createPixelTexture(marked),
        anchor: {
            x: 0,
            y: 0
        },
        transform: {
            x,
            y
        }
    });
    createText({
        text: name,
        transform: {
            x,
            y: y - 10
        },
        tint: '#ffffff'
    });
    createText({
        text: over.length + ' OVER',
        transform: {
            x,
            y: y + 50
        },
        tint: '#a0a8c0'
    });
};
```

`scenes/demo.ts`:

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

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

import { createLandscape } from '../art/landscape';
import { Card } from '../components/card';

export const Gallery = () => {
    const art = createLandscape();

    Settings.PICTURES.forEach((picture, at) => useSpawn(Card)({
        ...picture,
        at,
        art
    }));

    const screen = usePostProcess({
        ...paletteMatch({
            dither: 0.02
        }),
        palette: useLoadPalette({
            src: 'nacatamalon:gameBoy'
        })
    });

    screen.enabled = false;

    const keys = useKeyboard();

    useUpdate(() => {
        if (keys.justPressed(' ')) {
            screen.enabled = !screen.enabled;
        }
    });

    return createScene();
};
```

`settings.ts`:

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

export const WIDTH = 148;
export const HEIGHT = 156;
export const LIMIT = 4;
export const PICTURES = [
    {
        name: 'AS DRAWN',
        colors: null
    },
    {
        name: 'NES',
        colors: BUILTIN.PALETTES.nes
    },
    {
        name: 'GAME BOY',
        colors: BUILTIN.PALETTES.gameBoy
    },
    {
        name: 'C64',
        colors: BUILTIN.PALETTES.c64
    },
];
```
