Add design docs: glossary, ADR 0001, and project scaffolding
Records the outcome of the design review that reworked the original handoff notes: - CONTEXT.md — ubiquitous language for the slicer (slice, cut, discard, content rectangle, trim, song scale, bundle, project, jump source) - docs/adr/0001 — the slicer owns all image processing and the bundle is the only channel to noteman; noteman's sharp pipeline goes away - pyproject renamed to noteman-slicer - .gitignore keeps scores and bundles out of the repo (copyright, size)
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
# The slicer owns all image processing; the bundle is the only channel to noteman
|
||||
|
||||
The slicer was originally scoped to share the work with noteman: it would cut the
|
||||
pages, upload them to `POST /api/admin/songs/:id/slices`, and noteman's sharp
|
||||
pipeline would trim, downscale and convert ink to alpha on arrival. We decided
|
||||
instead that the slicer produces finished, display-ready artifacts and hands them
|
||||
over as a single zip; noteman does no image manipulation beyond what plain HTML
|
||||
and CSS do at runtime, and there is no API between the two tools.
|
||||
|
||||
## Considered options
|
||||
|
||||
**Split the work (rejected).** Slicer cuts, noteman normalises. This was the
|
||||
existing shape and needed no changes on either side. It failed on inspection:
|
||||
noteman's `normalizeSlice` calls sharp's `removeAlpha()` before its luminance
|
||||
pass, and `removeAlpha()` discards the alpha channel rather than compositing it
|
||||
over white — so any transparency the slicer produced would flatten to black ink.
|
||||
A polygon-masked slice would have arrived as a solid black rectangle. More
|
||||
fundamentally, the split put trim, downscale and encoding rules in two repos and
|
||||
two languages, where they must agree exactly and nothing checks that they do.
|
||||
|
||||
**Slicer produces final pixels, noteman stores them (chosen).**
|
||||
|
||||
**Direct POST with a bypass flag (rejected).** Keeps the API but adds a
|
||||
content-sniff or flag to skip normalisation. Preserves the two-language
|
||||
duplication it was meant to remove, and needs an admin token in a local script.
|
||||
|
||||
## Consequences
|
||||
|
||||
Several rules that read as arbitrary in the slicer's code are only explicable
|
||||
from here:
|
||||
|
||||
- The slicer owns **trim, staff-height normalisation, the 1920px ceiling, right
|
||||
padding, levels and the ink→alpha conversion.** Nothing downstream can rescue
|
||||
a faint scan or rehabilitate a bad crop, so the slicer's output is final.
|
||||
- **Scale is normalised on staff height, not width**, and derived once per song.
|
||||
A per-slice factor would change note size line to line down a continuous
|
||||
scroll; a width-based factor breaks the moment a slice comes from a different
|
||||
source (a rescanned page, or a re-engraved replacement system).
|
||||
- **noteman must delete its sharp pipeline** and accept a bundle instead. Until
|
||||
that lands, the slicer produces artifacts nothing consumes.
|
||||
- **The bundle is a versioned contract**, not an internal format. Two separately
|
||||
maintained repos now agree on: the marker enum, slice ordering, and the shape
|
||||
of `song.json`. That coupling is deliberately kept as small as possible —
|
||||
which is why every jump source stores its target slice explicitly rather than
|
||||
relying on an unwritten "exactly one Coda per song" resolution rule.
|
||||
- **The split is reversible only in one direction.** Re-adding server-side
|
||||
processing means re-deriving all of the above; going further the other way
|
||||
(more processing in the slicer) is free.
|
||||
Reference in New Issue
Block a user