From 4c358d157e65071a290cb96716823c32cb6bd8d3 Mon Sep 17 00:00:00 2001 From: Eric Wagoner Date: Sun, 23 Aug 2026 16:39:56 -0400 Subject: [PATCH] The saved clip is the whole reel, and it travels as MP4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hitting record used to capture from wherever the reel stood — at the end, the auto-stop fired a beat later and saved one second of the final frame. Recording now rewinds to the top and rolls the whole reel. And the container asks for MP4 (H.264) first, the format every phone and platform plays, keeping WebM only where the browser cannot mux it; the extension follows the container. Co-Authored-By: Claude Fable 5 --- packages/web/src/Replay.svelte | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/web/src/Replay.svelte b/packages/web/src/Replay.svelte index 4b6ffbf..d0d72be 100644 --- a/packages/web/src/Replay.svelte +++ b/packages/web/src/Replay.svelte @@ -258,6 +258,10 @@ if (recorder) { recorder.stop(); return; } const cv = stageEl?.querySelector("canvas"); if (!cv) return; + // Recording means capturing the WHOLE reel: rewind to the top and + // roll. (Hitting record at the end used to auto-stop a beat later — + // a one-second clip of the final frame.) + idx = 0; const comp = document.createElement("canvas"); comp.width = 1280; comp.height = 720; @@ -287,17 +291,23 @@ compRaf = requestAnimationFrame(drawComp); }; compRaf = requestAnimationFrame(drawComp); - const mime = MediaRecorder.isTypeSupported("video/webm;codecs=vp9") - ? "video/webm;codecs=vp9" : "video/webm"; + // MP4 travels everywhere (iMessage, QuickTime, every platform); + // WebM is the fallback where the browser can't mux it. + const mime = [ + "video/mp4;codecs=avc1.42E01E", "video/mp4", + "video/webm;codecs=vp9", "video/webm", + ].find((m) => MediaRecorder.isTypeSupported(m)) ?? "video/webm"; + const container = mime.startsWith("video/mp4") ? "video/mp4" : "video/webm"; + const ext = container === "video/mp4" ? "mp4" : "webm"; const rec = new MediaRecorder(comp.captureStream(60), { mimeType: mime }); const chunks: Blob[] = []; rec.ondataavailable = (e) => { if (e.data.size) chunks.push(e.data); }; rec.onstop = () => { cancelAnimationFrame(compRaf); - const url = URL.createObjectURL(new Blob(chunks, { type: "video/webm" })); + const url = URL.createObjectURL(new Blob(chunks, { type: container })); const a = document.createElement("a"); a.href = url; - a.download = `wizwar-moves-${steps[0]?.seq ?? 0}-${steps[steps.length - 1]?.seq ?? 0}.webm`; + a.download = `wizwar-moves-${steps[0]?.seq ?? 0}-${steps[steps.length - 1]?.seq ?? 0}.${ext}`; a.click(); setTimeout(() => URL.revokeObjectURL(url), 2000); recorder = null;