Statefully Documentation

Media Player

Audio/video player with play, pause, and loading states

Try It

Load media, then play, pause, and stop. The Ready state has nested playback states (Stopped, Playing, Paused).

Media Player State Machine

State Diagram

Idle*
Loading
Ready+3
Error

Preview

State Specification

Spec
Idle *
	load -> Loading
Loading
	ready -> Ready
	error -> Error
Ready
	Stopped *
		play -> Playing
	Playing
		pause -> Paused
		stop -> Stopped
		end -> Stopped
	Paused
		play -> Playing
		stop -> Stopped
Error
	retry -> Loading
	dismiss -> Idle

Prototype Code

Prototype
[Idle]
  div.player style="max-width: 300px; padding: 24px; text-align: center; border: 1px solid #eee;":
    p style="color: #666; margin-bottom: 16px;": "No media loaded"
    button @click=load style="padding: 12px 24px;": "Load Media"

[Loading]
  div.player style="max-width: 300px; padding: 24px; text-align: center; border: 1px solid #eee;":
    p: "Loading..."

[Stopped]
  div.player style="max-width: 300px; padding: 24px; text-align: center; border: 1px solid #eee;":
    div.progress style="height: 4px; background: #eee; margin-bottom: 16px;":
      div style="width: 0%; height: 100%; background: #000;":
    p style="margin-bottom: 16px;": "0:00 / 3:45"
    button @click=play style="padding: 12px 24px; background: #000; color: #fff;": "Play"

[Playing]
  div.player style="max-width: 300px; padding: 24px; text-align: center; border: 1px solid #eee;":
    div.progress style="height: 4px; background: #eee; margin-bottom: 16px;":
      div style="width: 40%; height: 100%; background: #000;":
    p style="margin-bottom: 16px;": "1:30 / 3:45"
    div.buttons style="display: flex; gap: 8px; justify-content: center;":
      button @click=stop style="padding: 12px 24px; border: 1px solid #ccc;": "Stop"
      button @click=pause style="padding: 12px 24px; background: #000; color: #fff;": "Pause"

[Paused]
  div.player style="max-width: 300px; padding: 24px; text-align: center; border: 1px solid #eee;":
    div.progress style="height: 4px; background: #eee; margin-bottom: 16px;":
      div style="width: 40%; height: 100%; background: #000;":
    p style="margin-bottom: 16px;": "1:30 / 3:45 (Paused)"
    div.buttons style="display: flex; gap: 8px; justify-content: center;":
      button @click=stop style="padding: 12px 24px; border: 1px solid #ccc;": "Stop"
      button @click=play style="padding: 12px 24px; background: #000; color: #fff;": "Resume"

[Error]
  div.player style="max-width: 300px; padding: 24px; text-align: center; border: 1px solid #ef4444;":
    p style="color: #ef4444; margin-bottom: 16px;": "Failed to load media"
    div.buttons style="display: flex; gap: 8px; justify-content: center;":
      button @click=dismiss style="padding: 12px 24px; border: 1px solid #ccc;": "Cancel"
      button @click=retry style="padding: 12px 24px; background: #000; color: #fff;": "Retry"

Key Concepts

  • Loading states - Idle → Loading → Ready flow
  • Nested playback - Ready contains Stopped/Playing/Paused
  • Error recovery - Loading can fail, with retry option
  • Natural end - Playing can transition to Stopped when media ends
  • State preservation - Paused remembers position, Stop resets