Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .changes/playback-speed-tiers.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "type": "user-facing", "releaseNoteId": "release:0.24.0" }
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@ All notable Loop Studio releases, newest first. Behavioral changes are pinned
in versioned spec documents (see the [README](README.md#technical-reference));
this file is the narrative history, not the contract.

## v0.24.0 — 2026-10-09

Playback speed changes what a step draws (issue #330, the last of three), and the phone gets a speed choice of its own, as [`docs/simulation-playback.md`](docs/simulation-playback.md) §PB6.1 and [`docs/mobile.md`](docs/mobile.md) §MV4 describe.

- **Three speed tiers.** At 400 ms a step or slower, the round marker travels with its `+N` beside it, as before. From 200 to 399 ms it travels and `+N` appears when it arrives. Below 200 ms the moved path flashes, then the marker appears at the end with `+N`. The tier is read when a step starts, so changing the speed during a step changes its pace but not what it draws; the next step takes the new tier.
- **Step always draws the full movement,** whatever the speed is set to.
- **Playback speed on the phone.** More → Playback speed offers Slow (1 s a step), Normal (0.6 s, the default), Fast (0.3 s) and Very fast (0.12 s); the current one is checked. There is still no seed in the phone's run bar.
- **Fewer moving markers on the phone.** A phone shows at most 12 marker-and-badge pairs a step — the first 12 of the same stable order as the desktop's 24 — and no departure ring; every other move keeps its path highlight and arrival cue. This is fixed when a step starts, so rotating the phone mid-step makes nothing in that step appear or disappear.
- Reduced motion and the far-zoomed map view keep their forms, unchanged.

**No migration.** Engine, RNG, files, share links, digests and simulation results are unchanged; the speed is still not saved. A current limit, measured: a step with about 300 simultaneous moves draws slowly (roughly 70–200 ms a frame on a desktop development build), before this change as after it. Twelve release-note and phone strings in 18 languages, 16 of them without native review. The informational `meta.tool` string is now `loop-studio/0.24.0`.

## v0.23.0 — 2026-10-09

Playback shows what happens inside the nodes (issue #330, second of three): a Pool lights up as its first marker arrives, and a Converter shows a conversion mark while its markers move, as [`docs/simulation-playback.md`](docs/simulation-playback.md) §PB4.7 describes.
Expand Down
28 changes: 15 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,19 @@ Additional feature-specific design documents (localization, mobile, module
system, large-graph readability, simulation playback, edge routing, data
import, …) live under [`docs/`](docs/).

## Latest — v0.23.0
## Latest — v0.24.0

Playback speed changes what a step draws, and the phone gets a speed choice of its own.

- **Three speed tiers**: at 0.4 s a step or slower the marker travels with its `+N`; faster,
`+N` appears when it arrives; below 0.2 s the path flashes and the marker appears at its
end; Step always shows the full movement
- **Playback speed on the phone**: More → Playback speed offers Slow, Normal, Fast and Very
fast
- **Fewer moving markers on the phone**: at most 12 a step, and no departure ring; every
other move keeps its highlighted path and arrival

## v0.23.0

Playback shows what happens inside the nodes: a Pool lights up as a marker arrives, and a
Converter shows that it converts.
Expand Down Expand Up @@ -181,18 +193,8 @@ language search no longer zooms the page in.
zoom the page in and leave it zoomed; every phone text field is now large enough that it
does not

## v0.21.3

A fix release: the edit lock is exact, and its button shows the state.

- **A new document starts unlocked**, and every other one brings its own lock and an empty
undo history, so Undo never goes back into the previous document
- **While locked, nothing edits the document**: the palette, Insert module, Undo, Redo and
the data import wait; selecting, viewing, running and exporting stay available
- **The lock button reads at a glance**: an open padlock when you can edit, a closed,
highlighted one when editing is locked

See [`CHANGELOG.md`](CHANGELOG.md) for the full notes of these releases, v0.21.2 (values
See [`CHANGELOG.md`](CHANGELOG.md) for the full notes of these releases, v0.21.3 (the edit
lock is exact, and its button shows the state), v0.21.2 (values
and detail rows sit inside their node), v0.21.1 (Focus
mode dims the connections too), v0.21.0 (compact
nodes, so more of a large graph fits in view), v0.20.0 (flow
Expand Down
21 changes: 18 additions & 3 deletions docs/mobile.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,23 @@ The mobile layout is unaffected — it is always view-only regardless of the fie
full-width at the breakpoint, with **real** `padding-bottom:
env(safe-area-inset-bottom)` (MV7).
- Keeps **Reset / Step / Play·Pause**, the **Monte Carlo** button, and the
`step N` counter. The speed slider and seed field are **not rendered** on
mobile (view/run uses defaults; a power user is on desktop).
`step N` counter. The speed slider and seed field are **not rendered** in the
bar (view/run uses defaults; a power user is on desktop).
- **Playback speed (issue #330 PR 3, v0.24.0) — §MV4 reopened narrowly.** A
stepped choice in the More sheet, never a slider in the bar: `⋯ → Playback
speed` opens a sub-sheet with **Slow** (1000 ms a step), **Normal** (600, the
default), **Fast** (300) and **Very fast** (120), the current one pressed
(`aria-pressed`); a choice sets the same session-only `speedMs` as the
desktop slider and closes the sheets. Each speed falls in exactly one tier of
`docs/simulation-playback.md` §PB6.1. A speed the desktop slider set that is
none of the four leaves none pressed. There is still **no run seed** in the
bar; the Monte Carlo dialog keeps its base seed.
- **Fewer moving elements on the phone.** Every phone speed draws its tier with
the phone display profile (`docs/simulation-playback.md` §PB6.1): at most 12
token-and-badge pairs a step (the first 12 of the desktop's stable order) and
no departure ring; past the 12 a move keeps its path highlight and arrival
cue. Fixed when a step starts, so a rotation mid-step changes nothing in that
step. Reduced motion and L0 keep their contracts.
- 44 px minimum touch targets.
- **Its height is measured, not assumed** (issue #303). The bar wraps to a
second row below about 390 px and, at 390 px, in six languages; the
Expand Down Expand Up @@ -485,7 +500,7 @@ opening. Its mobile placement rules:
| MV-D4 | simulation-input Inspector tabs | **read-only on mobile** in this cut; any future live sim-input editing is a separate, separately-gated decision |
| MV-D5 | document replacement | Import / Template **allowed**, but **confirm-before-replace** (MV3b), reusing the existing atomic `loadDoc()` path |
| MV-D6 | layout switch | **never** mutates the doc / undo history / latch (MV3c); desktop width fully restores the editing UI |
| MV-D7 | run bar | fixed bottom: Reset / Step / Play·Pause / Monte Carlo + `step N`; **no** speed slider or seed field |
| MV-D7 | run bar | fixed bottom: Reset / Step / Play·Pause / Monte Carlo + `step N`; **no** speed slider or seed field; the four-step Playback speed lives under `⋯` (§MV4, issue #330 PR 3) |
| MV-D8 | Timeline | collapsible bottom sheet, collapsed by default |
| MV-D9 | secondary actions | a `More` menu (Share / Import / Export / Templates / Theme / stamp); palette + undo/redo + New not rendered |
| MV-D10 | MiniMap | **not rendered** on mobile — and, on desktop, hidden when the canvas pane is smaller than ~640 × 380 px (`Canvas.tsx` `minimapFits`), where the fixed ~202 × 152 overlay would dominate rather than help |
Expand Down
44 changes: 44 additions & 0 deletions docs/simulation-playback.md
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,50 @@ step count, event lists, beat order, or which `to` is committed. Two runs at
different speeds from the same seed commit byte-identical `SimState` at every step
and identical series.

**The speed tiers (issue #330 PR 3, v0.24.0).** What a step DRAWS depends on its
beat, in three tiers with exact boundaries on the continuous desktop slider
(120 … 2400 ms, `src/store/playbackTier.ts`):

| tier | beat | the round token | `+N` |
|---|---|---|---|
| **full** | ≥ 400 ms | travels its path (§PB4) | beside it, moving with it |
| **fast** | 200 … 399 ms | travels its path | only from its arrive beat, beside it at the end |
| **very fast** | < 200 ms | does not travel: the moved path flashes (`.pb-path--flash`) from the edge's onset to its arrive beat, then the token appears at the end | with the token, at the arrive beat |

- The tier is read **once, when a step starts**, and travels with the
transition (`transition.tier`). A speed change during a step re-rates that
step's clock (§PB6.2) but changes its tier only from the next step.
- **Step** (the button) always draws the **full** tier, whatever the slider says.
- Everything else is the same in every tier: the onsets (§PBO2), the depart and
arrive cues, the Gate path, the 24 pairs and what lies past them (§PB4.5), the
own-label rule (judged on what is on screen: the token alone while `+N` is
not shown), Focus mode, the Pool pulse and the conversion mark (§PB4.7, at
the same arrival moment). State-connection beads are not tiered.
- Reduced motion ignores the tier (§PB9). L0 elides the token in every tier
(§PB4.4).
- The phone's four speeds (`docs/mobile.md` §MV4) fall one in each of full
(1000 and 600 ms), fast (300) and very fast (120).
- **The display profile, fixed per step like the tier** (`transition.profile`).
In the mobile view/run layout (`src/ui/media.ts`) a step uses the **phone**
profile: at most **12** token-and-badge pairs — the FIRST 12 of the same
stable order as the desktop 24 (§PB4.5), so a phone pair is always a desktop
pair — and **no departure ring** (the `emit` burst, §PBO3). Every move past
the 12 keeps its path highlight (the Gate path included) and its arrival cue,
as past the 24; the arrival rings, the chosen pairs' `+N`, the Pool pulse and
the conversion mark are unchanged. Step draws the full tier with the phone
profile's 12 and no departure ring. The profile is read when the step
starts, so rotating or resizing the screen during a step makes nothing in
that step appear or disappear; the next step takes the new layout. Under
reduced motion the profile is `desktop` (the static form of §PB9 and its 24
are unchanged), and L0 keeps its contract: no token, the path pulse for the
pairs of the step's budget.
- **A current limit, measured (not addressed here):** a step with about 300
simultaneous moves runs at roughly 70–200 ms a frame on a desktop dev build,
on `main` before this change as after it; hiding the Pool pulse or the
connection cues does not change it, so it is the per-frame cost of updating
that many moving connections, not a cue. The bundled Templates (largest
≈ 40 moves a step) stay near 17 ms median.

**PB6.2 — speed change mid-transition: recompute the remaining phases only.**
Progress is held as `τ ∈ [0,1]`, never as an absolute end-timestamp. On a change
at frame time `t₀` with current `τ₀`:
Expand Down
5 changes: 5 additions & 0 deletions docs/visual-language.md
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,11 @@ byte-identical across L2/L1/L0 (§VL12.5).
inside it, which fades after the step. Under reduced motion both are held
static for the committed step; in forced colours the pulse is a 2 px
system-colour line instead of a tint.
- **Playback speed tiers, issue #330 PR 3 (v0.24.0)**
(`docs/simulation-playback.md` §PB6.1): at 400 ms a step or slower the token
travels with its `+N`; from 200 to 399 ms it travels and `+N` shows on
arrival; below 200 ms the moved path flashes and the token appears at the end
with `+N`. Step always draws the full form; reduced motion is unchanged.
- Motion never conveys information that isn't also in a static frame.

---
Expand Down
8 changes: 5 additions & 3 deletions e2e/mobile.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1783,7 +1783,8 @@ test.describe('sheet row secondary label contrast (§MV5 / WCAG 1.4.3)', () => {
}
await escapeSheet(page, which)
}
expect(checked, 'the walk must reach every text sub-label: 5 More + 5 Templates + 4 enabled Export').toBe(14)
// issue #330 PR 3 — More gained the Playback speed row (its sub names the speed)
expect(checked, 'the walk must reach every text sub-label: 6 More + 5 Templates + 4 enabled Export').toBe(15)
expect(bad, 'hovered secondary labels below 4.5:1').toEqual([])
})

Expand All @@ -1808,9 +1809,10 @@ test.describe('sheet row secondary label contrast (§MV5 / WCAG 1.4.3)', () => {
}
await escapeSheet(page, which)
}
// the four submenu rows carry their affordance IN the sub-label, so they
// the five submenu rows carry their affordance IN the sub-label, so they
// are covered by the same contract rather than by the row's own text
expect(markers.sort(), 'the ▸ markers are part of this contract').toEqual(['Export', 'Filters', 'Help', 'Templates'])
// (issue #330 PR 3: + Playback speed)
expect(markers.sort(), 'the ▸ markers are part of this contract').toEqual(['Export', 'Filters', 'Help', 'Playback speed', 'Templates'])
expect(bad, 'focused secondary labels below 4.5:1').toEqual([])
})

Expand Down
Loading
Loading