---
name: list-to-living-tool
description: Use when turning a printed or pasted list of real-world events or places (a newspaper listing, a PDF schedule, a photo of a noticeboard) into a shareable map-and-calendar web tool. Covers scoping, transcription with counts, location verification against an authoritative register and aerial imagery, profiling on the target device, and planning for source revisions. Triggers on "make a map of this list", "turn this schedule into a tool", "where can I go this weekend".
---

# From a list to a living tool

A method for turning a photographed or pasted list of dated, located things
into a small web tool people actually use. Distilled from building
Réttir 2026 (153 Icelandic sheep and horse round-ups) from two phone photos
of a newspaper page. The write-up is at
https://clockwork.is/blog/rettir-2026.

The brief that governs every decision: **the idea is to use it.** Judge each
change by usability and shareability, not by features added.

## 1. Scope in three questions, then ship the ugly version

Before transcribing anything, ask exactly these, one line each:

1. Interface language(s)? Place names stay in the source language regardless.
2. Which sub-categories are in or out? (In Réttir: sheep only, horses later.)
3. Which two or three filters matter? Offer: date or range, region,
   distance from a starting point, weekend-only, has-a-time.

Then build a **single self-contained HTML file** first. No framework, no
build. It is testable on a phone in minutes and shareable as a file. Port
to the site only after the user has tapped through it and reported back.

## 2. Transcribe with counts, and state what is approximate

- Report counts at every step: entries, distinct dates, per region. The user
  can sanity-check counts against the page; they cannot check 150 rows.
- Keep the source's own caveats (times may change for weather) in the UI.
- **Say in the first reply what is estimated.** If coordinates are placed by
  farm or district, say so, and carry a `precision` field on every record:
  `exact | approximate | unknown`, plus a plain-language `note` of what the
  coordinate actually points at. That field is what step 4 is built on. The
  original build stated the approximation on day one and had forgotten it by
  day eight; the field is how you stop that.

## 3. Test like a user, report symptoms

When the user reports "it stutters", "it jumps", "I can't see the range",
find the cause. Do not ask them to diagnose. Read their words as symptoms:

- "ticks / stutter when dragging" → something restarts a transition every
  frame, or script drives an animation that CSS should.
- "jumps on scroll" → an element toggles position or size at a threshold.
- "flash on load" → the page is assembled in JS; render it on the server.
- "list disappeared" → a hidden element's `display` outranks the `hidden`
  attribute, or a virtualised list has wrong height estimates.

Fix the cause, then say what the cause was in one sentence.

## 4. Verify every location against the world, in this order

Never publish a coordinate you generated as a driving destination. Verify:

1. **Precision audit.** Count decimal places. Coordinates that all end at
   two decimals were rounded to the kilometre by someone; treat them as
   guesses.
2. **Authoritative register.** Find the national place-name or feature
   register (for Iceland: Landmælingar Íslands, `IS_50V` place-name WFS,
   `nafnberi='rétt'`; its `heimild` field often cites the same list you
   started from, which resolves same-name duplicates). Pull the _entire_
   feature class once (hundreds of rows) and do radius and same-name
   searches against it locally. A negative result from the full set is
   real; a negative result from name guesses is not.
3. **Fan out.** Split records into batches of 10 to 15 and run parallel
   subagents, each returning `found | approximate | not-found` with the
   coordinate, the source, and a one-line description of what the point is.
   Ask each agent to report any reusable discriminator it finds; merge those
   into the instructions for the remaining batches.
4. **Aerial confirmation.** Fetch imagery for every placed point (Esri World
   Imagery export, 300 m across, then 800 and 1500 if nothing shows). The
   target has a shape; describe it to the agent (a rétt: round or
   rectangular enclosure with radiating compartments at the end of a
   track). Classify `pen-at-point | pen-nearby | no-pen | unclear`. Expect a
   quarter to fail. Re-check failures against the register's second points
   for the same name; that rescued a third of them.
5. **Surface what is left.** Anything not `exact` gets a visible, tappable
   marker in the list that says what the coordinate is and offers a search
   by the place's own name instead of your point. Write a review document
   listing every unresolved record with candidates and imagery links, so a
   human can finish it.

## 5. Profile on the device that matters

- Numbers from a headless browser at DPR 1 understate paint by roughly 7x
  on a phone at DPR 2.6. Measure at the target viewport **and pixel
  ratio**.
- `requestAnimationFrame` gaps are blind to rasterisation, which happens
  off the main thread. Use CDP `Tracing` and read Paint and RasterTask.
- Build a `?perf` frame meter into the page (median, p95, worst, frames
  over 33 ms, viewport and DPR) so the user can read numbers off their own
  phone and paste a screenshot.
- Things that cost far more than they look: many translucent overlapping
  shapes (dimmed pins), `will-change` on a large element that moves,
  SVG `<text>` under a transform, a transition restarted every frame while
  a slider is dragged (track under the finger, ease on release).
- When the user asks to undo an optimisation for looks, measure what each
  one costs and let them choose with the number in front of them.
- Render on the server so the page carries all the data with scripts off,
  and take over the DOM rather than rebuilding it.

## 6. Plan for the source to change

- The list will be revised. Keep the transcription as data with a
  `source` and `revision` field, and diff against the new issue: dates
  moved, entries added, entries respelled (do not count those as new).
- Anything derived from the count (share card, intro copy) needs a
  generator committed next to it and a note saying which constant must
  agree.
- Licences on photographs: render attribution into the image itself, and
  state share-alike consequences in a README before choosing.

## Checklist

- [ ] Three scoping answers recorded
- [ ] Single-file version tapped through by the user on a phone
- [ ] Every record has `precision` and `note`
- [ ] Decimal-place audit done
- [ ] Register pulled in full; same-name and radius search run
- [ ] Aerial sweep of every placed point, results committed
- [ ] Unresolved records visible in the UI and listed in a review doc
- [ ] Profiled at target viewport and DPR with paint tracing
- [ ] Server-rendered; works with scripts off
- [ ] Revision diff procedure written down
