# Filters on models

> Outline and glow on 3D models, respecting depth. Space toggles filters; O toggles the outline.

Example `filters-3d`, running at https://nacatamalon.com/en/examples/filters-3d. The whole catalogue: https://nacatamalon.com/llms/examples.md.

Outline and glow on 3D models, respecting depth. Space toggles filters; O toggles the outline.

## Code

`index.ts`:

```ts
import { createGame } from 'nacatamalon';
import * as Settings from './settings';
import { Level } from './scenes/demo';

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

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

`components/coins.ts`:

```ts
import { createMesh, getColor, useCylinderGeometry } from 'nacatamalon';

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

export const Coins = () => {
    // A tray of coins lying on each other, each leaning its own way.
    const coin = useCylinderGeometry({
        radius: 0.5,
        height: 0.09
    });

    createMesh({
        geometry: useCylinderGeometry({
            radius: 4,
            height: 0.1
        }),
        tint: '#2a2f45',
        transform: {
            y: -0.2,
            scaleZ: 0.55
        }
    });

    for (let i = 0;i < 26;i++) {
        const column = i % 7;
        const row = Math.floor(i / 7);

        createMesh({
            geometry: coin,
            tint: getColor(Settings.COIN),
            transform: {
                x: -3 + column * 1 + (row % 2) * 0.5,
                y: 0.05 * (i % 3),
                z: -1.4 + row * 0.9,
                rotationX: 0.35 * Math.sin(i * 1.7),
                rotation: 0.4 * Math.cos(i * 2.3),
            },
        });
    }
};
```

`components/gem.ts`:

```ts
import { createMesh, getColor, useIcoSphereGeometry, useSelf, useTransform, useUpdate } from 'nacatamalon';
import { glow, outline, useFilter } from 'nacatamalon/effects';

export const Gem = ({ color, shine, z, speed, phase }: { color: string; shine: string; z: number; speed: number; phase: number; }) => {
    const gem = useIcoSphereGeometry({
        radius: 0.42,
        subdivisions: 0
    });

    const place = useTransform({
        x: 0,
        y: 0.1,
        z
    });

    const stone = createMesh({
        geometry: gem,
        tint: getColor(color)
    });

    const filter = useFilter({
        effects: [
            glow({
                color: shine,
                radius: 10
            }),
            outline({
                color: '#ffffff'
            })
        ]
    });

    filter.effects[1]!.enabled = false;
    filter.add(useSelf());

    useUpdate((_delta, elapsed) => {
        const time = phase + elapsed;

        place.x = Math.sin(time * speed) * 2.8;
        // Up and down through the coins, so they go in and come out again.
        place.y = 0.15 + Math.sin(time * speed * 2.3) * 0.25;
        stone.transform.rotationX = time;
        stone.transform.rotationY = time * 1.4;
    });

    return filter;
};
```

`scenes/demo.ts`:

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

import * as Settings from '../settings';
import { Coins } from '../components/coins';
import { Gem } from '../components/gem';

export const Level = () => {
    const camera = useCamera3d({
        projection: 'perspective',
        fov: 45,
        transform: {
            y: 4.2,
            z: 5.6
        }
    });

    camera.transform.rotationX = -0.62;
    useDirectionalLight({
        intensity: 1.2
    });

    useSpawn(Coins)();

    const filters = Settings.GEMS.map(props => useSpawn(Gem)(props).api);

    createText({
        text: 'SPACE  FILTERS    O  OUTLINE',
        tint: '#9aa7b4',
        transform: {
            x: 8,
            y: 8
        }
    });

    const keys = useKeyboard();

    useUpdate(() => {
        if (keys.justPressed(' ')) {
            for (const filter of filters) {
                filter.enabled = !filter.enabled;
            }
        }

        if (keys.justPressed('o')) {
            const line = filters[0]!.effects[1]!;

            line.enabled = !line.enabled;
        }
    });

    return createScene();
};
```

`settings.ts`:

```ts
export const WIDTH = 480;
export const HEIGHT = 270;
export const COIN = '#d9a520';
export const GEMS = [
    {
        color: '#e0306a',
        shine: '#ff4fa0',
        z: -0.9,
        speed: 0.7,
        phase: 0
    },
    {
        color: '#30c0e0',
        shine: '#6fe6ff',
        z: 0,
        speed: 0.5,
        phase: 2
    },
    {
        color: '#58d65b',
        shine: '#a8ff8a',
        z: 0.9,
        speed: 0.9,
        phase: 4
    },
];
```
