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).
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user