Files
noteman-slicer/docs/adr/0002-raster-only-svg-renderer-deferred.md
T
Esa Kataja 46ae7e813a Replace the handoff notes with a durable spec and ADRs
The handoff was written as a message to relay information; several
decisions lived only there. Split into permanent homes:

- docs/spec.md — scope, geometry model, pipeline order, detection,
  levels, editor, project file, markers, bundle format, noteman's
  changes, reference values
- ADR 0002 — raster only in release 1; SVG slices measured at 40x WebP
  naive, 2.6x with a bounding-box cull, deferred on risk not size
- ADR 0003 — lossless WebP with levels and 16-level alpha; every lossy
  option and alternative format measured larger for line art
- ADR 0004 — detection proposes, the human disposes; no unattended mode
- ADR 0005 — PyMuPDF for all PDF access, accepting AGPL
- ADR 0006 — systems are found by vertical brackets, not row-darkness
  gaps, which miscount every page of a 6-voice score

Also from testing against the hardest score in the repertoire: scanned
PDFs carry their scan as an embedded image and must be extracted at
native resolution rather than re-rendered at 600 DPI, and per-page
deskew is mandatory (skew varies -2.6 to +1.2 within one PDF).
2026-07-28 22:05:09 +03:00

62 lines
2.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Raster only in release 1; the SVG renderer is deferred
Vector PDFs are most of the newer corpus, and keeping them vector all the way to
the viewer was an early goal — sheet music is line art, and SVG stays crisp at any
tablet zoom. We measured it before building it, and decided to **rasterize vector
sources like everything else in release 1** and revisit the SVG renderer once
real songs have been cut.
## The measurement
One real vector song, 6 pages, 65 systems, rendered both ways:
| Approach | Total | vs WebP |
|---|---|---|
| WebP slices (600 DPI → 1920, ink→alpha, lossless) | 1.19 MB | 1× |
| SVG, naive `viewBox` + `clipPath` | 26.0 MB | 40× |
| SVG, `set_cropbox` per band | 26.5 MB | 41× |
| SVG, bounding-box cull + glyph subset | 3.09 MB | 2.6× |
- **The naive cut is unusable.** A `viewBox` + `clipPath` slice contains the
entire page's geometry and merely hides eleven-twelfths of it.
- **`set_cropbox` does not help.** MuPDF renders full page content regardless of
the crop, so there is no free version of the cull.
- **The cull works.** PyMuPDF emits a `<defs>` glyph table (111 KB of a 256 KB
page) referenced by `<use transform="matrix(...)">`, plus body `<path>`
elements. Filter both by y-extent, then keep only the glyphs the survivors
reference. Roughly 50 lines, 15× improvement.
## Why defer, given the cull works
**Not size.** At 3.1 MB vs 1.2 MB per song — 225 MB vs 87 MB across a 73-song
corpus — both are nothing on a homelab. The measurement killed the lazy
implementation, not the idea.
What defers it is risk and missing evidence:
- The cull is **heuristic parsing**: glyph extents bounded at baseline ±14pt,
path extents read from raw `d` coordinates. It is over-inclusive by design, so
it fails safe — but "fails safe" still means a slice quietly carrying a
neighbour's slur, or a hairline dropped because the y-window was wrong on some
publisher's output. That needs eyeballing per song, a QA loop the raster path
doesn't have.
- Rendering 65 complex SVGs in a scrolling column may be slower than 65 WebPs.
Unmeasured.
- **The deciding question is unanswerable from here**: does 1920px WebP actually
feel insufficient when pinch-zooming on a tablet? Cutting real songs answers
it; more measurement doesn't.
Vector PDFs are also the *clean* case for the raster path — deskew is a no-op,
detection works best, there are no scan artefacts — so rasterizing them is not a
degraded fallback.
## Consequences
- The geometry model stays **renderer-agnostic**, in normalised page coordinates,
so adding the SVG renderer later is an output stage rather than a redesign.
- **Re-export from the project file** regenerates every song's bundle without
repeating human work, so songs cut before the SVG renderer exists are not
stranded.
- noteman needs no SVG support (`image/svg+xml`, `.svg` content type, CSP header
on SVG responses) until the renderer ships.