The beat engine, keyboard controls and layer catalog (#41) - #64
Merged
Conversation
The keyboard becomes the primary driver. One pair of keys means the same thing all four days, and every state is one keypress from anywhere. The beat engine lives in state.js because the beat index is app state. `setBeat` resets every derived field before applying the beat, so no beat can depend on having passed through its predecessor -- which is what makes a beat render identically whether it was stepped into, stepped back to, or jumped at cold, and what forces the prefetch rule the spec keeps arriving at: a spine is installed complete or not at all. Ends never wrap; an out-of-range digit is a silent no-op rather than a clamp. Views are jumpable in any order and each remembers its own beat and layer set, so Flow & Cut stays parked on augmentation 3 while the instructor detours to answer a question. `R` is a full view reset -- beat 0, default layers, threat cleared -- leaving view and dataset untouched. The layer catalog is one global set with per-view entry states, never view-owned: the unit's strongest moments are cross-day mashups. The old single lane label splits into `caps` and `costrisk`, because Flow & Cut wants a capacity beside its flow and Cost & Risk wants cost and risk instead. All-layers-on is illegible in every scheme and is not a legal preset. The scaffold tier dims untouched lanes to 30% and owns opacity alone, made safe by the rule that an empty hot set means every lane is hot -- so the pristine network, whose subject is the graph itself, is never dimmed. Labels only on hot lanes falls out of that rather than being a special case. The token block gains the back-row smear as ONE authored quantity with a derivation per pattern. Two floors apply to every dashed mark and they are orthogonal: pitch (is it still broken?) is exactly independent of stroke weight, and presence (is it there?) is `weight x duty x opacity`. The failure mode is the whole argument for machine-checking them -- a dash that loses does not vanish, it becomes a dimmer solid line. The residual arc goes to stroke 4 / `22 18` and the min cut to `16 24`; the synthetic machinery and the removed lane stay under the presence floor deliberately, on a recorded and closed exemption list. tests/test_web_assets.py re-derives the 3.16 dashed-stroke floor from the smear rather than restating it, so retuning the room moves the floor instead of leaving a constant nobody can re-justify. Closes #41
Review findings on the beat engine, all three from the spec axis. `resolveBeat` rebuilt the layer set from the view's entry table alone, so `->` destroyed any pointer toggle. The spec spends the cross-day layer mashup -- Day 3's cut over Day 4's interdicted network, the unit's strongest moment -- on `R` and on nothing else; as built it survived zero beats. Layers are now resolved from three sources in order: the view's entry table, the beat's overrides, then the instructor's own toggles, which are recorded in `layerOverrides` and cleared by `R` alone. Rebuilding from all three every time keeps a beat idempotent including its layers, which resetting to bare defaults also did but at that price. A layer toggle re-resolves the layers alone rather than the whole beat, so a pinned lane survives a click on a layer button. The coarse controls now address units by ordinal rather than by the value in `beat.unit`. Reading the value assumed units numbered from zero with no gaps, and silently mis-jumped on both spines #42-#44 are expected to build -- an interdiction ladder whose k starts at 1, and a Pareto spine with duplicate detents collapsed out. Standards axis: the spine clamp and the "first beat of unit" contract each appeared twice; extracted to `clampToSpine` and `setUnitAt`. Also records two things so they are not rediscovered: why the promoted reverse arc's `24 15` is not in the token block (duty 0.615 is over this ticket's own authoring cap and it clears the pitch floor inside the closed form's error bar, so it ships with the mark that justifies it), and what the two-row anchor does to the label footprint -- +/-25 where it was +/-12, which clears every distance the anchor solve enforces and exceeds only the lane half-band that governs casings. Adds the flat `w >= 3.16` assertion the acceptance criteria state, beside the derived presence floor, on the same recorded exemption list.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #41.
The keyboard becomes the primary driver. One pair of keys means the same thing all four days, and every state is one keypress from anywhere. This ticket builds the beat engine, the view scaffolding and the layer catalog that the three view tickets (#42–#44) then fill in.
The beat engine
Lives in
state.js, because the beat index is app state and that module owns app state. A beat is a plain record —{unit, phase, label, apply}— and a view's ticket installs a whole spine throughsetSpine.setBeatclears every derived field before applying the beat, so no beat can depend on having passed through its predecessor. That is what makes a beat render identically whether it was stepped into, stepped back to, or jumped at cold — and it is what forces the prefetch rule the spec keeps arriving at: a spine is installed complete or not at all. A beat that had to fetch could not be synchronous, and a beat that is not synchronous cannot be stepped backwards through at speaking pace.Ends never wrap, and an out-of-range digit is a silent no-op rather than a clamp: a clamp moves the picture somewhere nobody asked for, mid-sentence.
The coarse controls address units by ordinal, not by the value in
beat.unit. The instructor says "go back to the second one", and what makes it the second one is its position in the story. Reading the value directly would mis-jump on both spine shapes #42–#44 are expected to build — an interdiction ladder whose k starts at 1, and a Pareto spine with duplicate detents collapsed out.Views are jumpable in any order and each remembers its own beat and hand toggles, so Flow & Cut stays parked on augmentation 3 while the instructor detours to answer a question.
The layer catalog
One global catalog with per-view entry states, never view-owned — the unit's strongest moments are cross-day mashups, and Day 3's cut over Day 4's interdicted network is Day 4's entire punchline.
Layers resolve from three sources in order: the view's entry table, the beat's overrides, then the instructor's own toggles. Rebuilding from all three on every beat is what keeps a beat idempotent including its layers, while leaving the hand toggles standing —
Ris the only thing that clears them, which is exactly where the spec spends that cost.The old single lane label splits into
capsandcostrisk, because Flow & Cut wants a capacity beside its flow and Cost & Risk wants cost and risk instead; one text carrying all three put two unasked-for numbers on screen in both. All-layers-on is illegible in every scheme and is not a legal preset.The scaffold tier
Untouched lanes dim to 30%, and this tier owns opacity — nothing else may use dimming as a channel, or two mechanisms compose into a lane at 9% nobody authored. Safe only because an empty hot set means every lane is hot, so the pristine network — the one picture whose subject is the graph itself — is never dimmed. Labels only on hot lanes falls out of that rather than being a special case.
The stroke model
The token block gains the back-row smear as one authored quantity with a derivation per pattern. Two floors apply to every dashed mark and they are orthogonal:
weight × duty × opacity, against 1 MAR at the 20/40 design observer.The failure mode is the whole argument for machine-checking them: a dash that loses does not vanish, it becomes a dimmer solid line — still there, still the right colour, saying the wrong thing.
Adopted values from #25 and #27: residual arc to stroke 4 /
22 18, min cut16 24, synthetic machinery and removed lane re-pitched to6 22. Those last two stay under the presence floor deliberately — the machinery is scaffolding and may fade, and removal's meaning rides on theXglyph — on a recorded and closed exemption list, so the question is not reopened a third time.tests/test_web_assets.pyre-derives the 3.16 dashed-stroke floor from the smear rather than restating it, so retuning the room moves the floor instead of leaving a constant nobody can re-justify. The recorded 3.16 is compared directionally against the 3.13 the model implies: a shade conservative is a rounding, a shade generous is a mark authored under the floor with a test agreeing.Verification
11 new tests, all under the repo's Python-or-nothing rule — no JS test runner, and the module inventory stays at seven. 311 pass.
Two judgement calls worth a reviewer's eye:
24 15is not in the token block. Its duty of 0.615 is over this ticket's own ≤ 0.6 authoring cap, and it clears the pitch floor by 1.008× — inside the closed form's own ~1% error bar, which is to say it is a value the rule cannot actually certify. It is also geometry-specific to an arc promoted to offset 22 with a hollow head. It ships with the mark that justifies it; recorded instyle.cssso Flow and Cut view (Days 2-3) #42 re-opens the question rather than rediscovering it.TandDland in #45; the beats themselves land in #42–#44.