Files
noteman-slicer/CONTEXT.md
T
Esa Kataja b6847a06ee Treat a project as spent once its song has been exported
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.
2026-07-28 23:49:03 +03:00

134 lines
6.4 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.
# 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 412 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.