Skip to content

feat: configurable passage transitions with outgoing phase support#37

Merged
rohal12 merged 14 commits intomainfrom
feat/watch-triggers
Mar 18, 2026
Merged

feat: configurable passage transitions with outgoing phase support#37
rohal12 merged 14 commits intomainfrom
feat/watch-triggers

Conversation

@rohal12
Copy link
Copy Markdown
Owner

@rohal12 rohal12 commented Mar 18, 2026

Summary

  • Passage transitions system with four types: none (instant), fade (incoming only), fade-through (default — fade out, pause, fade in), and crossfade (simultaneous overlap)
  • Story API: Story.setTransition(config) for persistent defaults, Story.setNextTransition(config) for one-shot overrides
  • Per-passage tags: [transition:crossfade duration:600 pause:200] on passage headers
  • State machine in PassageDisplay with render gating, DOM snapshot for outgoing phases, CSS grid stacking for crossfade
  • CSS custom properties (--passage-in-duration, --passage-out-duration, --passage-pause) for author styling
  • prefers-reduced-motion support
  • Priority chain: passage tags > one-shot > persistent default > built-in default
  • Also includes: watch/unwatch triggers, button convention flip, macro-agnostic StoryInit (from prior commit)

Test plan

  • 715 unit/DOM tests passing (33 test files)
  • tsc --noEmit clean
  • New test coverage: transition.test.ts (14 tests), store-transition.test.ts (15 tests), story-api-transition.test.ts (4 tests), passage-display-transition.test.tsx (9 tests)
  • Manual: verify fade-through default on fresh story
  • Manual: verify Story.setTransition({ type: 'none' }) disables transitions
  • Manual: verify passage tags override API config
  • Manual: verify crossfade with two passages of different lengths

release-npm

🤖 Generated with Claude Code

clem and others added 11 commits March 18, 2026 16:31
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix critical issues:
- Clarify setNextTransition is always consumed on navigation
- Add crossfading state to state machine for concurrent animations
- Add render gating section explaining displayedPassage decoupling
- Add resolveTransition() signature and call pattern

Fix minor issues and add clarifications:
- Fix resolveTransitionFromTags to validate type and handle NaN
- Note ms-to-seconds conversion for CSS custom properties
- Explain translateY motion intent in keyframes
- Add crossfade CSS grid layout strategy
- Clarify duration:0, data-transition values, first-load tag override

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Clarify resolution chain fill-from-defaults semantics
- Fix restart/load: treat as first-load (incoming-only fade)
- Add passage-container wrapper to avoid #story layout changes
- Clarify data-transition prop delivery via Preact component
- Add prefers-reduced-motion CSS handling
- Add snapshot media pause/mute handling
- Clarify snapshot target is .passage div specifically
- Update files-to-modify table with Passage.tsx

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Note key={displayedPassage} change explicitly
- Add restart/load detection mechanism via history comparison
- Clarify back/forward consume nextTransition
- Note fade/fade-through use default CSS with no type-specific override

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…se support

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add transitions guide page (docs/transitions.md) with full reference
- Add Story.setTransition/setNextTransition to Story API docs
- Add transitions to VitePress sidebar
- Update changelog with transition feature, breaking changes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 18, 2026

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 71.99% 1967 / 2732
🔵 Statements 71.33% 2160 / 3028
🔵 Functions 66.36% 369 / 556
🔵 Branches 63.35% 987 / 1558
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
src/store.ts 90.75% 82.19% 86.88% 92.23% 82, 116, 254-255, 310, 319-322, 353-358, 450, 484, 504-507, 521, 525-528
src/story-api.ts 4.16% 0% 7.69% 4.39% 94-284, 296-331
src/transition.ts 100% 95.45% 100% 100%
src/components/Passage.tsx 69.76% 50% 100% 67.56% 57-61, 67-71, 77, 83-87
src/components/macros/PassageDisplay.tsx 73.1% 74% 81.81% 72.07% 24, 34-36, 64, 166-168, 174-175, 183-184, 202, 209-244
Generated in workflow #100 for commit f059099 by the Vitest Coverage Report Action

rohal12 and others added 3 commits March 18, 2026 17:54
The new fade-through default adds ~350ms before new passage mounts,
pushing timed content past the 2000ms timeout in e2e tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The {#id timed} syntax doesn't propagate ctx.id to the timed macro
wrapper (pre-existing issue on main). Changed test to wait for text
content instead.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@rohal12 rohal12 merged commit fd90714 into main Mar 18, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant