# Torch corridor

> Thirty-two lights a scene, eight a model: a corridor of torches lit all along, and a car with four lights of its own.

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

A scene holds thirty-two lights at a time, and each model is lit by the eight of them that reach it most, as the consoles of the era lit each thing they drew: a sun always, a lamp when its `range` touches the box around the model. So a corridor of twenty-four torches is lit all along, each stretch by its own.

The floor and the walls are made of pieces, so each piece takes the torches near it, and they are subdivided, because the light is worked out at the corners. The car is one object with four lights of its own: four calls in it, two headlights and two tail lights, each placed by its own `transform`, with no `useSpawn` for each.

## Code

`index.ts`:

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

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

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

`components/car.ts`:

```ts
import { createMesh, useCubeGeometry, usePointLight, useSpotLight, useTransform } from 'nacatamalon';

export const Car = () => {
    const place = useTransform({
        y: 0.5
    });

    createMesh({
        geometry: useCubeGeometry(),
        tint: '#c0392b',
        transform: {
            scaleX: 1.6,
            scaleY: 0.8,
            scaleZ: 3
        }
    });
    // A torch points down unless turned: these look ahead, a little down, at the road.
    useSpotLight({
        intensity: 2.5,
        range: 16,
        angle: 0.45,
        transform: {
            x: -0.6,
            z: -1.6,
            rotationX: -0.12
        }
    });
    useSpotLight({
        intensity: 2.5,
        range: 16,
        angle: 0.45,
        transform: {
            x: 0.6,
            z: -1.6,
            rotationX: -0.12
        }
    });
    usePointLight({
        color: 'red',
        intensity: 1.5,
        range: 1.5,
        transform: {
            x: -0.6,
            z: 1.6
        }
    });
    usePointLight({
        color: 'red',
        intensity: 1.5,
        range: 1.5,
        transform: {
            x: 0.6,
            z: 1.6
        }
    });

    // Where each light comes from: a glowing piece on the front and the back of the body.
    const lamp = useCubeGeometry();

    for (const x of [-0.55, 0.55]) {
        createMesh({
            geometry: lamp,
            tint: '#fff6d8',
            emissive: '#fff6d8',
            transform: {
                x,
                y: 0.1,
                z: -1.52,
                scaleX: 0.36,
                scaleY: 0.18,
                scaleZ: 0.06
            }
        });
        createMesh({
            geometry: lamp,
            tint: '#ff2020',
            emissive: '#ff2020',
            transform: {
                x,
                y: 0.1,
                z: 1.52,
                scaleX: 0.36,
                scaleY: 0.14,
                scaleZ: 0.06
            }
        });
    }

    return place;
};
```

`scenes/demo.ts`:

```ts
import { createMesh, createScene, getColor, useAmbientLight, useCamera3d, usePlaneGeometry, usePointLight, useSpawn, useUpdate, useSphereGeometry } from 'nacatamalon';
import * as Settings from '../settings';
import { Car } from '../components/car';

export const Corridor = () => {
    // Inside the corridor, behind the car, following it.
    const camera = useCamera3d({
        projection: 'perspective',
        fov: 70,
        transform: {
            y: 2.2,
            z: 7,
            rotationX: -0.12
        }
    });

    useAmbientLight({
        intensity: 0.08,
        color: '#203060'
    });

    // The floor and the walls in pieces, each lit by the torches near it; and subdivided, because
    // the light is worked out at the corners.
    // A corner every half step: the closer the corners, the smoother a moving light slides across.
    const ground = usePlaneGeometry({
        width: 8,
        depth: Settings.PIECE,
        widthSegments: 16,
        depthSegments: 8
    });

    // A wall is the same plane stood on its side, facing in.
    const wall = usePlaneGeometry({
        width: 4,
        depth: Settings.PIECE,
        widthSegments: 8,
        depthSegments: 8
    });

    for (let z = 0;z > -Settings.LENGTH;z -= Settings.PIECE) {
        createMesh({
            geometry: ground,
            tint: '#555566',
            transform: {
                z: z - Settings.PIECE / 2
            }
        });
        createMesh({
            geometry: wall,
            tint: '#6b5a4a',
            transform: {
                x: -4,
                y: 2,
                z: z - Settings.PIECE / 2,
                rotation: -Math.PI / 2
            }
        });
        createMesh({
            geometry: wall,
            tint: '#6b5a4a',
            transform: {
                x: 4,
                y: 2,
                z: z - Settings.PIECE / 2,
                rotation: Math.PI / 2
            }
        });
    }

    // The torches, along both walls, warm and cold by turns. Lamps of the scene: a call each.
    const flame = useSphereGeometry({
        radius: 0.15
    });

    for (let i = 0;i < Settings.TORCHES;i++) {
        const x = i % 2 === 0 ? -3.7 : 3.7;
        const z = -2 - i * (Settings.LENGTH / Settings.TORCHES);
        const color = i % 4 < 2 ? '#ff9a3c' : '#5ab0ff';

        usePointLight({
            color,
            intensity: 1.6,
            range: 6,
            transform: {
                x,
                y: 2.5,
                z
            }
        });
        createMesh({
            geometry: flame,
            tint: getColor(color),
            emissive: getColor(color),
            transform: {
                x,
                y: 2.5,
                z
            }
        });
    }

    const car = useSpawn(Car)().api;

    useUpdate((_delta, time) => {
        // Down the corridor and round again, the camera behind it.
        car.z = -((time * 8) % (Settings.LENGTH - 6));
        camera.transform.z = car.z + 7;
    });

    return createScene();
};
```

`settings.ts`:

```ts
export const WIDTH = 480;
export const HEIGHT = 320;
export const LENGTH = 96;
export const PIECE = 4;
export const TORCHES = 24;
```
