Opening an exported song starts a fresh session from detection instead of resuming: cuts, discards and metadata do not carry over, so a re-cut never inherits decisions that have already shipped. --resume overrides it on edit, export and project. This reverses what was agreed in planning and written into docs/spec.md and CONTEXT.md, which promised resume-across-sessions and re-export. Both are corrected. The cost is deliberate and worth stating: changing the width cap or adding the SVG renderer later now means re-cutting each song by hand rather than regenerating every bundle from its project file. Export records the flag in bundle.write, so no caller can forget it. Also removed --refit and the Auto-fit buttons, which were added without being asked for and whose only purpose - migrating projects made before the content rectangle was proposed - disappears once exported projects start fresh. Reset now restores detection's proposal rather than the whole page: clearing to full width would undo the thing the rectangle exists for, so one button covers it. open_project() replaces four copies of load-or-detect across the CLI and the editor.
134 lines
6.4 KiB
Markdown
134 lines
6.4 KiB
Markdown
# noteman-slicer — Context
|
||
|
||
A local, single-user tool that turns a score PDF into the ordered slice images
|
||
noteman consumes, plus the navigation markers that sit on them. It automates the
|
||
mechanical part of noteman's ingestion boundary; it does not replace GIMP for
|
||
erasing previous-owner annotations.
|
||
|
||
## Language
|
||
|
||
**Score source**:
|
||
The original PDF as distributed to the choir. Either **vector** (engraved by a
|
||
notation program) or **raster** (a flatbed scan of a printed page).
|
||
_Avoid_: original, input file
|
||
|
||
**Source type**:
|
||
Whether a score source is vector or raster. Determined once per PDF, not per
|
||
page; the slicer detects it and asks the user to confirm before routing.
|
||
_Avoid_: mode, format
|
||
|
||
**Slice**:
|
||
The atomic visual unit of a song — one *system*, one full line of music across
|
||
all voices, typically 4–12 bars with lyrics intact. Same definition as noteman's.
|
||
Structurally, a region of a page bounded above and below by cuts: a page begins
|
||
as a single slice and each cut splits one slice into two, so slices always tile
|
||
the page with no gaps and no overlap. Rectangular when its cuts are straight,
|
||
and stepped when they are not — the slice image is then its bounding box with
|
||
everything outside the region transparent.
|
||
_Avoid_: segment, strip, row, band
|
||
|
||
**Discard**:
|
||
A flag on a slice meaning it produces no output. How headers, footers and blank
|
||
regions leave the song — they are slices that are simply not exported. Detection
|
||
pre-sets it on a page's top and bottom slice when they contain no system.
|
||
_Avoid_: delete, skip, exclude
|
||
|
||
**Slice image**:
|
||
The rendered artifact of a slice: lossless WebP, RGB pure black,
|
||
`alpha = 255 − luminance`, width capped at 1920px — paper is transparency, ink is
|
||
alpha. Display-ready as produced; nothing downstream reprocesses it. An SVG form
|
||
for vector sources is designed but deferred, which is why the geometry model is
|
||
renderer-agnostic.
|
||
_Avoid_: PNG, page image, tile
|
||
|
||
**Marker**:
|
||
A semantic tag placed on a slice for navigation. Vocabulary is noteman's enum
|
||
verbatim (`rehearsal_letter`, `section_label`, `segno`, `coda`, `fine`,
|
||
`repeat_start`, `repeat_end`, `volta`, `to_coda`, `ds_al_coda`, `ds_al_fine`,
|
||
`dc_al_coda`, `dc_al_fine`, `generic_jump`) and is shared coupling between the
|
||
two repos.
|
||
|
||
**Project**:
|
||
The persistent state of slicing one song: the source PDF it points at, its cuts,
|
||
discards, content rectangle, levels, staff-height overrides, markers and
|
||
metadata. Autosaved beside the PDF; the bundle is generated from it. One PDF,
|
||
one song, one project, one bundle — never a many-to-one in any direction.
|
||
|
||
**Spent** once its song has been exported: opening the PDF again begins a fresh
|
||
session from detection rather than resuming, so a re-cut never inherits
|
||
decisions that have already shipped.
|
||
_Avoid_: session, document, edit list
|
||
|
||
**Bundle**:
|
||
The single compressed file that is the *only* channel between the slicer and
|
||
noteman. There is no API call, no direct upload. Carries the slice images in
|
||
order, their markers, the original PDF and the song-level text metadata.
|
||
Rehearsal MIDI and MP3s are deliberately out of the first bundle and stay
|
||
noteman's upload chore until a later phase.
|
||
_Avoid_: export, package, upload
|
||
|
||
**Marker label**:
|
||
The free text some markers carry — `rehearsal_letter` ("C"), `section_label`
|
||
("CHORUS"), `volta` ("1."). All other types are bare tags.
|
||
|
||
**Jump source**:
|
||
A marker that sends the reader elsewhere — `to_coda`, `ds_al_coda`,
|
||
`ds_al_fine`, `dc_al_coda`, `dc_al_fine`, `generic_jump`. Every jump source
|
||
stores its **target slice explicitly**; none is resolved by type at read time.
|
||
Authoring the target costs one click on a slice already on screen, and in
|
||
exchange the bundle is self-describing — no "exactly one Coda per song" rule
|
||
living unenforced in two repos, and a score with two codas simply works.
|
||
_Avoid_: link, reference, pointer
|
||
|
||
**Cut**:
|
||
A boundary placed on a page that splits one slice into two. Modelled as a
|
||
**polyline** spanning the page from left edge to right edge, with two points —
|
||
a straight horizontal line — as the ordinary case. Extra vertices handle the
|
||
common publisher habit of printing a section label (`VERSE 1`, `INTRO`) in the
|
||
left margin at the same height as the previous system's lyrics: the cut steps
|
||
above the label on the left and below the lyrics on the right.
|
||
|
||
Placement along the boundary is forgiving — anywhere inside the whitespace yields
|
||
the same output, because trim crops to ink afterwards.
|
||
_Avoid_: split, divider, break, cut line
|
||
|
||
**Content rectangle**:
|
||
The region of a page that holds music. Set per PDF, adjustable per page, applied
|
||
before cutting. Everything outside it — scan-edge bands, spine shadows, margin
|
||
page numbers — is dropped. Handles margin junk structurally rather than
|
||
case-by-case, because margin junk is by definition outside the music.
|
||
_Avoid_: crop box, mask, margin
|
||
|
||
**Detection**:
|
||
Any automatic proposal the slicer makes — skew angle, cut positions, source
|
||
type, ink bounds. Detection is always a *suggestion*: the human confirms or
|
||
modifies every result before it is committed. Source quality varies too widely
|
||
for unattended processing to be trustworthy.
|
||
_Avoid_: auto-slicing, automatic mode
|
||
|
||
**Trim**:
|
||
Cropping a slice tight to its ink on all four sides, per slice. Normalises away
|
||
the left-margin drift between scanned pages, and flattens the engraved indent of
|
||
the first system — correct here, since the printed header it made room for is
|
||
stripped anyway. The viewer supplies margins with CSS padding.
|
||
|
||
**Staff height**:
|
||
The distance between a system's top and bottom staff line. The invariant a
|
||
reader perceives as "the notes are the same size", and therefore what slices are
|
||
normalised against — not their width. Falls out of the same row-darkness profile
|
||
used for cut detection. Manually overridable, since it is detected on the same
|
||
speckled scans where detection already struggles.
|
||
|
||
**Song scale**:
|
||
Two steps, both per song, never per slice. First every slice is normalised to a
|
||
common staff height, so a rescanned page or a re-engraved slice sits at the same
|
||
note size as its neighbours. Then the whole song is scaled uniformly so its
|
||
widest slice lands at 1920px — a ceiling, never a target: a song that comes out
|
||
narrower stays narrower, because upscaling a scan past its real resolution buys
|
||
softness and bytes and no detail.
|
||
|
||
**Right pad**:
|
||
The transparent space added to the right of every slice narrower than the widest,
|
||
bringing all slices in a song to the same width. Keeps the music the same size
|
||
and flush left; a short system simply ends earlier.
|