storyink 0.3.2 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/spec.md CHANGED
@@ -156,15 +156,27 @@ asks for reduced motion** (`prefers-reduced-motion: reduce` is ignored).
156
156
  `"story": { "steps": "auto", "motion": "system" }` (or `storyink render --motion system`, tool
157
157
  `storyink_render` `motion`). Readers can always switch with the toolbar's **Motion** toggle (`M`).
158
158
 
159
+ ### Beats
160
+
161
+ A **beat** is one or more consecutive steps that read as a single change: `beatGroups(timeline)`.
162
+ A step joins the next when the next starts at the same time, or is chained straight on (`"+0"`,
163
+ within 50 ms of this step's end) and, without starting a chapter (`stop`), either adds no caption of
164
+ its own or reveals the box this step's pulse arrives at. So a pulse and the reveal of its target
165
+ are always one beat. A beat's **stop** is its last step's settled time: its reveals at full
166
+ opacity, its dots landed, counters at their value, its caption fully typed (`beatStops`). Beats
167
+ drive step moves (→ / ←), stepped (reduced-motion) playback, the scrubber's ticks (`beatTicks`)
168
+ and beat tiles (which may merge further to fit 12 tiles). Chapters (Shift+→ / ←) are the stops of
169
+ beats holding a `stop` (`beatChapters`).
170
+
159
171
  ### Reduced motion: "Play steps"
160
172
 
161
173
  When motion is reduced, the viewer doesn't animate; it **steps**. The page loads on the final frame
162
- with a static play button (no idle rings; `autoplay` is ignored). Play shows each step's
174
+ with a static play button (no idle rings; `autoplay` is ignored). Play shows each beat's
163
175
  **settled** state at once (reveals shown, its pulses landed and wires drawn, counters at their new
164
176
  value, the caption whole), holds it for its reading time (the caption's read time, otherwise
165
177
  1.5 s), then advances, and ends on the final frame. There are no pulses in flight, trails, rings,
166
- glows, flashes or tweens. Pause, ←/→ (Shift: chapters) and the scrubber move between settled steps
167
- (`#t=` is quantised to the step in effect); R restarts from step 1 without the tape rewind.
178
+ glows, flashes or tweens. Pause, ←/→ (Shift: chapters) and the scrubber move between settled beats
179
+ (`#t=` is quantised to the beat in effect); R restarts from step 1 without the tape rewind.
168
180
  Core: `steppedSchedule(timeline)`, `steppedTime(timeline, t)` and
169
181
  `storyState(scene, timeline, t, { stepped: true })`.
170
182
 
@@ -215,12 +227,36 @@ animated SVG (SMIL) has no follow camera.
215
227
  **Page contract:** `#t=<seconds|end>` seeks (paused), `#autoplay=0|1`, `#motion=full|reduced`,
216
228
  `#camera=follow|fit` (with `#t=`, `follow` shows the followed view),
217
229
  `#static=1` (runtime off, final frame), `#sheet=beats` (one tile per step + final frame).
218
- `window.__storyink = { ready, duration, steps: [{ id, label, t0, t1, stop? }], setTime(t), play(), pause(), replay(), state(), camera() }`;
230
+ `window.__storyink = { ready, duration, steps: [{ id, label, t0, t1, stop? }], setTime(t), play(), pause(), replay(), step(dir, chapter?), stepAnimated(), state(), camera() }`;
231
+ `step(1 | -1, chapter?)` is the animated step move below and returns a Promise that resolves when
232
+ the move ends (or is interrupted); `stepAnimated()` is the running move `{ dir, target }` or null.
233
+ `state()` reads the clock and mode directly (no render lag).
219
234
  `camera()` returns `{ mode, follow, k, x, y, goal, step, engaged, suspended, userK, viewport }`
220
235
  (a diagram point p is drawn at `x + (p.x − viewBox.x)·k`).
221
- Keys: space play/pause, ←/→ previous/next step (Shift: chapter), R replay, M motion, F follow,
236
+ Keys: space play/pause, →/← step moves (Shift: by chapter), R replay, M motion, F follow,
222
237
  0 fit, +/− zoom.
223
238
 
239
+ **Step moves (→ / ←).** In full motion the arrows animate instead of jumping:
240
+ - **→** plays forward at normal speed from the current time to the **next beat stop** (see Beats:
241
+ the dot lands *and* the box it reaches is revealed and settled, with the caption whole; or the
242
+ end) and pauses there. While playing, → becomes "advance one beat". **Shift+→** does the same
243
+ to the next chapter.
244
+ - **←** rewinds: time runs **backwards at 2×** (pulses fly back) to the **previous beat stop**, then
245
+ pauses, with a short bounce-free ease in and out (0.12 s, never below 0.3× so it always
246
+ arrives). No blur (the blur stays with R's tape rewind). **Shift+←** goes to the previous chapter.
247
+ - **Repeated presses** in the direction of a running move extend its target to the following
248
+ boundary; the opposite key reverses toward the boundary adjacent to the current time.
249
+ - **Space** pauses a move; the scrubber still seeks immediately; R is the tape-rewind replay.
250
+ - The follow camera follows moves like playback, backwards too.
251
+ - **Reduced motion** keeps instant jumps between settled beats.
252
+ Core: `beatStops`, `beatChapters`, `stepBoundary`, `stepMoveTarget`, `stepMoveSpeed`, `STEP_MOVE`.
253
+
254
+ **Wire geometry.** Everything animated along a wire (the pulse dot, its trail, the flight draw-on
255
+ spans, the SMIL trail route) uses `flattenPath(edge.d)`, a dense polyline of the drawn rounded
256
+ wire (quadratic corners sampled to < 0.1 px), never the route's corner points. Multi-hop routes
257
+ keep each hop's start, so the dot crosses the node straight between hops. `edge.length` is the
258
+ rounded wire's length.
259
+
224
260
  ## Animated SVG
225
261
 
226
262
  `storyink render x.json --animated-svg x.svg [--theme light|dark|both] [--once] [--font system|embed]`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "storyink",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "Diagram library, CLI and OpenCode v2 plugin: architecture, workflow, sequence, dataflow and lifecycle diagrams from JSON or Mermaid into standalone HTML and SVG, with optional storyboard animation.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",