# Lighthouse on a cliff at dusk, notes

One file does the work: `index.html`. Open it by double clicking, no server, no build.

## How it is built

The artwork is defined once, in a hidden `<defs>` block at the end of the document:

- `symbol#lighthouse` holds the whole picture in a `0 0 600 800` viewBox, 34 shapes.
- `g#lamp` holds the light itself, 3 shapes (two beam wedges plus the lamp core). It is a
  separate layer so it can be painted above the sky and the cliff while still never crossing
  the tower: the wedges start at the lantern mouth, x 130 and x 162.
- `symbol#grid` is a page overlay, not part of the illustration: one path, a 40 unit lattice.

Each of the four frames is `<svg viewBox="0 0 600 800">` plus three `<use>` references, so the
geometry is never typed twice and every size is provably the same vector.

Two things that had to be measured rather than assumed:

- A CSS animation declared on a class **inside** a symbol does not run in the `<use>` shadow
  tree, verified in Chromium (five identical frames over 4.5 s). So `@keyframes flash` is applied
  to the `<use class="lamp">` element in the document tree, where it does run.
- `vector-effect="non-scaling-stroke"` did not survive the `<symbol>` viewport either, so the
  lattice carries a per frame `--gw` instead: 1.4, 2.8, 5.6, 11.2 user units, which is the same
  1.2 CSS px hairline at 512, 256, 128 and 64.
- A frame sized `width:min(512px,100%)` inside an auto width flex item collapsed to the 300 px
  SVG default. The width now sits on the `<figure>` (`width:min(var(--w),100%)`) where the
  percentage resolves against the flex container. Measured boxes: 512x683, 256x341, 128x171,
  64x85.

## The drawing, in paint order (37 shapes)

| # | shape | element |
| --- | --- | --- |
| 1 to 5 | sky bands, indigo to ember, horizon at y 534 | 5 rects |
| 6 to 8 | stars | 3 circles |
| 9 | sun, r 54, sunk 18 units under the horizon | circle |
| 10 to 11 | cloud bars, one behind the tower, one across the sun | 2 rects |
| 12 | far headland | polygon |
| 13 to 14 | sea and its light edge | 2 rects |
| 15 to 17 | the sun's road on the water | 3 rects |
| 18 to 21 | wave dashes | 4 rects |
| 22 to 23 | cliff, cut in facets, plus the rock in the corner | 2 polygons |
| 24 | tower, 56 units at the base, 32 at the throat | path |
| 25 to 26 | two bands, taper matched to the tower | 2 polygons |
| 27 | window | circle |
| 28 | door | path |
| 29 to 32 | gallery, glass, roof, finial | rect, rect, polygon, circle |
| 33 to 34 | birds, one stroke each | 2 paths |
| 35 to 37 | beam seaward, beam inland, lamp core | 2 polygons, 1 rect |

Palette, sky down to water: `#191740 #332358 #6b3160 #b04a58 #e8804f #ffdda0 #f6d79e #e9dcc4
#a4445c #2b2153 #2a2444 #120f26`. No gradient, no filter, no clipping path: the only strokes in
the artwork are the two birds. The only transparency anywhere is the flash animation on the lamp
layer.

## Requirement list

- Pure HTML, CSS, JavaScript and SVG, nothing else. **DONE.** 0 `<script>` tags, so zero JavaScript.
  No library, no framework, no package manager, no CDN, no web font, no icon set, no bitmap, no
  base64, no `fetch`. Page is 11.9 kB, the vector definition is 3.1 kB.
- Opens by double clicking from disk, no server, no build step. **DONE.** Verified in Chromium
  over `file://`, console empty.
- Responsive. **DONE.** The four frames sit on one bottom aligned shelf while they fit, then wrap;
  each frame is capped at 100 percent of the column. No horizontal overflow measured at 1440,
  900 and 390 px wide.
- Works with JavaScript disabled where content is content. **DONE.** The page contains no
  JavaScript at all; with scripting blocked and animations frozen, the specimen row is identical
  at the byte level (33,311 PNG bytes either way).
- Real focus order. **DONE.** One focusable control, the `#lattice` checkbox, in reading order
  before the frames, with a `<label for>` and a `:focus-visible` ring. The repeated frames are
  `aria-hidden`, only the first carries the image label.
- Honours `prefers-reduced-motion`. **DONE.** With no preference: 4 running animations, lamp
  opacity 1 down to 0.53 on a 6.5 s cycle. Under reduce: `document.getAnimations()` is empty and
  opacity stays 1.
- No console errors. **DONE.** Zero messages in every run, including the toggled and narrow states.
- Poster like, geometric, flat colours. **DONE.** 3:4 canvas, straight banded sky, faceted cliff,
  solid fills throughout. The beams are opaque wedges rather than translucent light: at this
  contrast, an alpha beam over a dark sky mixes to grey, which is why they were made flat.
- Forty shapes or fewer. **DONE.** 37, table above. The optional construction lattice is one more
  path and is off by default.
- Shown at three or four sizes. **DONE.** Four: 512, 256, 128 and 64 px, halving, each labelled
  with the use it stands for.
- Aim at a demanding designer, restraint over effects. **DONE, with one honest caveat.** One idea
  per frame: a light giving a character. The lattice toggle is the only extra, and it is an
  inspection tool rather than an effect.
