# 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.