# Glow maps

> A second picture in the model file lights its windows and its sign: the sun goes down, the glow stays.

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

A model file can carry a **glow map**: a second picture, white where the surface gives off light of its own and black where it does not. `useLoadModel` reads it along with the colour picture, and the engine adds it after the lighting, so the code never sets a glow at all.

The sun goes down and comes back every twelve seconds. The bricks follow it; the windows, the doors and the sign stay exactly as bright, which at night is all that is left. `bloom` spreads them into the dark around them, the soft light of the GameCube and Xbox years, when consoles first drew a glow map in one pass.

## Code

`index.ts`:

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

import { WIDTH, HEIGHT } from './settings';
import { Street } from './scenes/demo';

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

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

`components/hotels.ts`:

```ts
import { createMaterial, createMesh, createModel, useLoadModel, usePlaneGeometry } from 'nacatamalon';

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

export const Hotels = () => {
    const hotel = useLoadModel({
        src: Settings.MODEL
    });

    createModel({
        model: hotel,
        transform: {
            x: -5.5,
            z: -1,
            rotationY: 0.5
        }
    });
    createModel({
        model: hotel,
        transform: {
            x: 0,
            z: -3,
            scaleY: 1.3
        }
    });
    createModel({
        model: hotel,
        transform: {
            x: 5.5,
            z: -1,
            rotationY: -0.5
        }
    });

    createMesh({
        geometry: usePlaneGeometry(),
        material: createMaterial({
            shader: 'mesh3d',
            tint: '#2b2a33'
        }),
        transform: {
            scaleX: 40,
            scaleZ: 30,
            z: -4
        },
    });
};
```

`scenes/demo.ts`:

```ts
import { createScene, useCamera3d, useDirectionalLight, useUpdate, useSpawn } from 'nacatamalon';
import { bloom, usePostProcess } from 'nacatamalon/effects';
import * as Settings from '../settings';

import { Hotels } from '../components/hotels';

export const Street = () => {
    useCamera3d(Settings.CAMERA);

    const sun = useDirectionalLight({
        color: '#fff1d6',
        intensity: 1,
        ambient: 0.4,
        transform: {
            rotationX: -0.7,
            rotationY: 0.5
        },
    });

    // The bright parts bleed into the dark around them: at night, only the glow is bright enough.
    usePostProcess(bloom({
        threshold: 0.75,
        intensity: 0.9,
        radius: 6
    }));

    useSpawn(Hotels)();
    // A day every twelve seconds: the sun goes down and comes back, and the windows never change.
    useUpdate((_delta, time) => {
        const day = 0.5 + 0.5 * Math.cos((time / Settings.DAY_LENGTH) * Math.PI * 2);

        sun.intensity = 0.04 + day * 1.06;
        sun.ambient = 0.03 + day * 0.4;
    });

    return createScene();
};
```

`settings.ts`:

```ts
export const WIDTH = 560;
export const HEIGHT = 400;
import type { TCamera3dOptions } from 'nacatamalon';

export const CAMERA = {
    projection: 'perspective',
    fov: 50,
    transform: {
        y: 5,
        z: 19,
        rotationX: -0.06
    }
} satisfies TCamera3dOptions;
export const MODEL = '/example-assets/assets/3d/gltf/hotel/hotel.gltf';
export const DAY_LENGTH = 12;
```
