workshop private

← all creations

Harbor Light

sprites · created 2026-09-06

48×40 pixel night seascape — a banded tower on a headland, three weather loops, and a lamp you can drive from a real light characteristic.

pixel-artcanvas

A place rather than a character: banded tower on a headland, keeper’s shed beside it, open water running off to the left, and a lens that turns. Three loops — a clear-night sweep, a gale with rain off the right and spray on the near rock, and a fog where the beam goes short and fat and the horn takes over.

The demo is the part worth clicking. A lighthouse is not identified by its shape — at four miles on a black night you cannot see its shape — it is identified by its light characteristic: the exact pattern of on and off it repeats forever, written on a chart as Fl(2) W 10s or Oc W 4s or Iso W 6s. Two towers can be the same height, the same colour, the same everything, and still be told apart because one of them goes quiet for eight seconds and the other for one. The demo drives the lamp from six of those patterns in real time with a timing ribbon underneath, so you can watch a light say its own name; the weather row runs any of them through a gale or a fog bank.

The lens only sweeps for the flashing ones. Fixed, occulting and isophase lights aren’t rotating at all — they show all round at once, which is a different silhouette and the whole reason those characteristics exist: you can read them from any bearing without waiting for the beam to come round to you.

Reuse

Render at integer scales with nearest-neighbor filtering or the edges smear. sweep plays at 4 fps, gale at 6, fog at 1.6 (ANIMATIONS carries all three).

The module is worth importing rather than the PNGs if you want the light to do anything: paintScene(ctx, spec, opts) takes a frame spec directly, so the beam angle, the on/off, the light colour and the weather layers are all parameters rather than baked pixels. characteristicAt(spec, t) evaluates one of the CHARACTERISTICS entries at a time in seconds and hands back { on, progress }progress is what turns a flash into a visible sweep instead of a hard blink.

Gotchas

Source

No .aseprite — the canonical source is source/harbor-light.mjs: a framework-free ES module holding the scene as a character map (one char per pixel, palette at the top), with the moving parts painted procedurally over it. Edit and regenerate everything with:

node source/render.mjs

(needs site/node_modules installed — the script resolves Playwright from there.) That one command rewrites export/, media/, thumb.png, and the demo’s bundled copy of the module, so nothing drifts.