kasuti: don't autoplay on completion; default GIF to 0.5× pace
- Completion now fires confetti and leaves both fabrics on the final tour (replayIdx = totalStitches, paused). The user drives the replay from the control strip. - Exported GIF frames render at 400 ms each (vs 200 ms on-screen) with a 1200 ms hold on the first and last frame — half speed by default, easier to follow when a platform auto-loops the preview. https://claude.ai/code/session_01KNdXjQczMCRGMK7K3Qderw
This commit is contained in:
parent
bd4f073cac
commit
0378978b1f
1 changed files with 9 additions and 7 deletions
|
|
@ -974,9 +974,10 @@ const KasutiEmbroidery: React.FC = () => {
|
||||||
|
|
||||||
const encoder = GIFEncoder();
|
const encoder = GIFEncoder();
|
||||||
const totalFrames = stitches.length + 1;
|
const totalFrames = stitches.length + 1;
|
||||||
// Timings: slightly longer hold on the first and last frames.
|
// Export at 0.5× the on-screen replay pace — easier to follow in a loop
|
||||||
const frameDelayMs = 200;
|
// and friendlier when the GIF auto-plays in a social-media preview.
|
||||||
const holdDelayMs = 900;
|
const frameDelayMs = 400;
|
||||||
|
const holdDelayMs = 1200;
|
||||||
|
|
||||||
for (let k = 0; k <= stitches.length; k++) {
|
for (let k = 0; k <= stitches.length; k++) {
|
||||||
const stitchesUpTo = stitches.slice(0, k);
|
const stitchesUpTo = stitches.slice(0, k);
|
||||||
|
|
@ -1023,19 +1024,20 @@ const KasutiEmbroidery: React.FC = () => {
|
||||||
patternId,
|
patternId,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// On first completion: confetti + kick off an autoplay replay from step 0.
|
// On first completion: confetti + leave both fabrics showing the final tour.
|
||||||
|
// Replay stays paused until the user presses play or scrubs the slider.
|
||||||
// When the tour is un-completed (undo/reset/pattern change), tear down replay.
|
// When the tour is un-completed (undo/reset/pattern change), tear down replay.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (completed && !celebratedRef.current) {
|
if (completed && !celebratedRef.current) {
|
||||||
celebratedRef.current = true;
|
celebratedRef.current = true;
|
||||||
confetti({ particleCount: 180, spread: 90, origin: { y: 0.6 } });
|
confetti({ particleCount: 180, spread: 90, origin: { y: 0.6 } });
|
||||||
setReplayIdx(0);
|
setReplayIdx(stitches.length);
|
||||||
setReplayPlaying(true);
|
setReplayPlaying(false);
|
||||||
} else if (!completed) {
|
} else if (!completed) {
|
||||||
setReplayIdx(0);
|
setReplayIdx(0);
|
||||||
setReplayPlaying(false);
|
setReplayPlaying(false);
|
||||||
}
|
}
|
||||||
}, [completed]);
|
}, [completed, stitches.length]);
|
||||||
|
|
||||||
// Hydrate from ?replay=... on mount. Runs once client-side; if the payload
|
// Hydrate from ?replay=... on mount. Runs once client-side; if the payload
|
||||||
// parses and the pattern is known (preset or carried inline), rebuild the
|
// parses and the pattern is known (preset or carried inline), rebuild the
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue