- Add crossedArmsDetector using 2D landmarks normalized by shoulder width
- Either hand on opposite shoulder for 0.5s triggers start/pause/resume (toggle)
- Remove arms-out from pause, resume, and calibration-start roles
- Add CalibrationMachine.resume() method, engine drives all transitions
- Update all UI text (GestureOverlay, Tutorial, GamePage) for new gesture
- Show debug overlay in /debug with live distances and threshold
- Show body centroid tracking dot before game starts
- Remove sticky drawDebug3D canvas overlay from usePoseLoop
- Add 'nose' draw mode for pre-game tracking indicator
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Delete REFACTOR.md, add PAUSE_SIGNAL.md for pause gesture rework planning
- Fix vertically flipped FRONT/SIDE 3D views (remove incorrect Y negation)
- Hide landmarks with visibility < 0.3 and exclude from auto-scale
- Show step graphs before calibration completes (use raw position as baseline)
- Add 4th debug view showing 2D normalized landmarks
- Expose landmarks2D from usePoseLoop
- Flip step graph Y axis to match intuitive direction
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Shows front (X·Y), side (Z·Y), and top (X·Z) projections of MediaPipe
world landmarks on the /debug page to evaluate 3D estimation quality.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Delete 22 song folders that lack YouTube audio (unused in UI).
Remove audio.ogg from the 4 remaining YouTube-backed songs.
Remove stray Get Lucky MP3 from public root.
Simplify song-data.ts to only the 4 playable songs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Show "Tap to choose files" instead of drag & drop text on mobile
- Hide zip drop hint on small screens
- Stack options and actions vertically on mobile
- Shrink song banner thumbnails, font sizes, and spacing
- Full-width add button on mobile
- Larger touch targets for checkboxes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Skip YouTube attribution and player in both the song selector preview
and the game page when playing a custom (non-YouTube) track.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replaces native title attributes with CSS ::after tooltips that appear
instantly on hover, with a help cursor to signal interactivity.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Show required files (audio + chart) vs optional (images) explicitly,
and mention zip support as a separate line.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Users can upload their own StepMania song bundles via drag & drop (individual
files or .zip archives) from the song selector. Tracks are parsed, displayed
in the carousel alongside built-in songs, and optionally persisted to the
browser using the Origin Private File System (OPFS). Difficulty selection and
arrow simplification are configurable per track.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
With only 4 songs, the carousel tried to show 5 positions, causing
the same song to appear twice (e.g. far-left and far-right wrapping
to the same index). Deduplicate display indices so each song only
renders once regardless of how many songs exist.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Clicking the YouTube player window shows a popup explaining why it's
there (music streamed from YouTube, ToS compliance). Spinner now uses
absolute positioning so it overlays the container instead of pushing
content aside.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Song select: spinner shown via yt-loading class, removed when PLAYING.
Game page: spinner shown via :empty pseudo-class while iframe loads.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Preview now uses YouTube IFrame API with a visible 240x135 player in the
top-left corner of the song select screen, matching the game page layout.
Falls back to local audio for songs without YouTube config.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Songs with youtubeVideoId now preview via YouTube IFrame API instead of
local .ogg files. Creates a hidden YouTube player, seeks to the preview
position (offset + 30s), and fades volume in/out on song change.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Filter SONGS export to only include songs with youtubeVideoId. All song
definitions remain in the source for future use. Vite plugin removes
non-YouTube song folders from dist after build so they aren't deployed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
For songs with YouTube config, a YT: ON/OFF button appears in the pause
menu next to KB. Toggling it recreates the audio player so you can
compare YouTube vs local audio during the same session.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Raw PCM cross-correlation fails on different masters/mixes (all candidates
have near-identical confidence). Chromaprint generates perceptual hashes
that are invariant to mastering, so the correct offset is always in the
top 2 candidates with clear separation. Still generates comparison WAVs
for ear verification since repetitive songs can have ambiguous top picks.
Requires fpcalc (chromaprint) on PATH in addition to ffmpeg.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Offsets verified by ear using comparison WAVs:
- Chop Suey: GK-DkHHAMIU offset 8.968s
- Just Dance: 5q7byFPTehs offset 0.062s
- Meet Me Halfway: -GY8MhHMxLM offset 6.973s
Also fix offset tool: handle video IDs starting with '-' via --yt flag,
skip negative/empty offset candidates in WAV generation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Correct offset from 66.389 to 0.207 (was matching repeated section).
The tool now generates stereo comparison WAV files (left=local,
right=YouTube) for each candidate so you can verify by ear.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
YouTube ToS requires the embedded player to be visible (min 200x200px).
Place it in the top-left corner at 240x135 with rounded corners and a
subtle border. Player fills its container and is non-interactive
(pointer-events: none) so it doesn't interfere with gameplay.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pause menu now has a KB button next to LOG. When enabled:
- Arrow keys feed steps directly into the game
- Calibration is bypassed so the game starts immediately
- Camera-based step detection and auto-pause are disabled
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace direct HTML5 Audio usage with an AudioPlayer abstraction that
supports both local audio files and YouTube IFrame Player API. Songs
can now specify a youtubeVideoId and youtubeOffset to stream audio
from YouTube instead of hosting audio files.
- AudioPlayer interface with LocalAudioPlayer and YouTubeAudioPlayer
- YouTube IFrame API type declarations and script loader
- Cross-correlation offset detection tool (tools/audio-offset/)
- Get Lucky configured with YouTube video 5NV6Rdv1a3I, offset 66.389s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
128 BPM, 2:09, from Oakridge ITG Cab 2011 Songpack 3.
Placed after Meet Me Halfway in the front section.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Beat It (Michael Jackson, 139 BPM) and Meet Me Halfway (Black Eyed
Peas, 130 BPM) added after Just Dance at the front. Horsestyle
(Unicorn On Ketamine, 200 BPM) and Heroine moved to the middle.
25 songs total.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Desktop unchanged (side-by-side layout). On mobile (<600px), shows
player + single tip with step counter and Next/Got It button.
Removed overflow scroll from overlay.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Player sits left, tips right. Stacks vertically on mobile (<600px).
Card wider (680px) to fit both comfortably.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
RecordingPlayer gains autoPlay, loop, showControls props.
Tutorial shows the stick figure demo on loop above the tips.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Recording now captures full MediaPipe data. simplifyRecording() picks
the 13 stick-figure landmarks with optional movement dedup and end trim.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Recording now captures only 13 landmarks (nose + shoulders/elbows/wrists
+ hips/knees/ankles). Player draws circle head, no palms/feet.
Test page loads bundled recording on mount.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
RecordingPlayer draws 2D skeleton from recorded frames with play/pause
and scrub controls. Test page at /recording-test loads JSON via file picker.
Also added download button to /record results.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>