# Ball Clock — `ball-clock@1.0.0`

Steel balls roll down twin rails, round the bend and up again. Loops perfectly.

A kinetic desk toy on a wooden board: steel balls roll one after another down a zig-zag of twin brass rails, gathering speed as they fall, drop round the bottom bend and are carried up the side to start again. The balls are spaced evenly round the closed track, so there is always a ball in every part of it. Choose the number of balls, the finish (steel, brass, copper, black), the board (walnut, oak, slate, white), how many laps a loop holds, the backdrop and whether the camera drifts.

- Kind: object; status: published; digest sha256:bc36459fdcea3d41e0e934c8576d1d318af127584a20da4b81e36d05ed9445d6
- Role: Object (3D, three.js): a hypnotic mechanical hero object for time, flow and rhythm content.
- Implementation: three; entry `src/ball-clock.js`
- Files: https://aipixelwizard.com/registry/ball-clock/1.0.0/<path> (`LICENSE`, `asset.json`, `demo.js`, `index.html`, `src/ball-clock.js`)
- Manifest JSON: https://aipixelwizard.com/api/v1/visuals/ball-clock/versions/1.0.0
- Runnable demo: https://aipixelwizard.com/registry/ball-clock/1.0.0/index.html (open over http; it imports sibling packages by relative path)
- Dependencies (exact): `three@0.185.1` (source) — Renderer, geometry and physical materials.; `chrome-material@1.1.0` (demo) — Studio environment light, backdrop and contact shadow.; `apw-runtime@1.0.0` (demo) — Demo harness.

## Exports
- `createBallClock({ balls?, metal?, board?, laps? }) => { group, setProgress(progress), dispose() }` — The board, rails and instanced balls as a group (8 wide, 9 tall, facing +z); add it with an environment map and a light.
- `METALS: { steel, brass, copper, black }` — Ball finishes.

## Parameters
- `balls` (integer 8–24, default 14) — Balls
- `metal` (select one of steel | brass | copper | black, default "steel") — Balls
- `board` (select one of walnut | oak | slate | white, default "walnut") — Board
- `laps` (integer 1–3, default 1) — Laps: Whole laps of the track each ball makes per loop.
- `background` (color, default "#1b2a3a") — Backdrop
- `orbit` (boolean, default true) — Camera drift

## Composition
- Inputs: Time within the loop; the balls, finish, board, laps, backdrop and camera drift.
- Outputs: A full frame rendered in 3D with soft shadows and a studio environment.
- Coordinates: The board is 9.4 × 10.4 in the xy plane facing +z, the track a closed spline inside it, .
- Lighting: A key light with a shadow map and the studio environment on the polished balls and brass rails.
- Timing: setProgress(progress) places every ball by table lookup; frames render in any order.
- Works with: chrome-material, orbit-camera, kinetic-title, number-reveal
- A ball's place is a table lookup on the track's cumulative travel time, where the speed grows as the ball falls (1.3 → 3.0) and is constant on the way up, so no simulation state is kept.
- The balls roll: each turns by the arc length it has travelled.

## Output and loop
- 1080×1080, 30 fps, 16 s, procedural
- Seamless loop: yes — The balls are spaced evenly round a closed track and each makes a whole number of laps per loop, with a speed that depends only on its height, so the pattern returns exactly; the camera drift is a sine of the loop.
- Verified 2026-10-05 in Chrome 154.0.8037.97 headless on Linux 7.0.0-38-generic (x64), Node 22.14.0 (WebGL 2 via SwiftShader (software)); deterministic: yes; loop check: Frame 0 vs end state (progress 1): mean |Δ| 0.0000, max |Δ| 0 of 255.

## Use it
New project: Create a WebGLRenderer with shadows and a studio environment (see chrome-material), add createBallClock().group and call clock.setProgress(progress) each frame.

Existing project: Copy src/ball-clock.js; add clock.group to your scene with an environment map and a shadow-casting light.

Reuse ideas:
- Time or flow title: Steel balls, walnut.
- Luxury desk-toy loop: Brass balls, slate.
- Cheerful product loop: Copper, white board.

## Limitations
- The balls follow a prescribed speed, not a physical simulation: they never bunch up or collide.
- There is no dial: the balls count nothing, they only circulate.

## License
MIT. Copyright (c) 2026 AI Pixel Wizard. Released under the MIT License. See LICENSE in this folder.

Provenance: Adapted from the owner's threejs-sketches/mechanical-kinetic/ball-clock (MIT) and rebuilt for AI Pixel Wizard in October 2026 as an original object: evenly spaced balls on a closed twin-rail track with a fall-speed table, rolling rotation and an exact loop.

