Professional Scripted product demos with GSAP with Claude

vein051 pts0 comments

Scripted product demos with GSAP instead of video | Sugam Panthi Sugam Panthi<br>DaylightStatus:plated

We inject it into the BlogPostIsland as a serialised HTML string so the<br>RichMarkdown island can display it with all its interactive features<br>(copy buttons, mermaid, image blocks, etc.).

Alternatively, we render Content as static HTML via a hidden div and pass<br>the raw markdown string. We pass the raw markdown from entry.body for<br>full RichMarkdown support.<br>--> rotations[i],\n stagger: 0.07,\n duration: 0.46,\n}, \"addClick+=0.16\");\n```\n\nList items use a tighter stagger, 60ms, because they are simpler shapes arriving in sequence rather than objects being placed.\n\nThe most counterintuitive rule: after every major action, do nothing. After the cards appear, there is 1.4 seconds of dead time before the cursor moves again. After the overlay appears, it sits for a full second. Viewers need time to register what changed. Removing the pauses makes the animation faster but incomprehensible.\n\nThe typed text uses `ease: \"none\"`, constant speed. This is one of the rare cases where linear motion is correct. Eased typing looks like someone accelerating through a sentence.\n\n## The loop trap\n\nThe first time the animation looped, every card was already visible. The overlay was still showing. The cursor was in the wrong position. The timeline's end state became the second loop's start state.\n\nThe fix is a reset block at timeline position 0 that explicitly restores every animated property:\n\n```javascript\ntl.add(() => {\n gsap.set(cursor, { x: CURSOR_START.x, y: CURSOR_START.y, scale: 1 });\n gsap.set(cards, { autoAlpha: 0, y: 26, scale: 0.82, rotation: 0 });\n gsap.set(overlay, { autoAlpha: 0, scale: 0.96, y: 10 });\n gsap.set(typed, { textContent: \"\" });\n}, 0);\n```\n\nMiss one property and you see it immediately on the second loop. I missed `rotation` the first time and the cards snapped to their tilted positions before animating. A subtle jump that took twenty minutes to find.\n\n## The architecture that makes this maintainable\n\nThe production version at [costumary.com](https://www.costumary.com) is 1,800 lines across five files:\n\n```\nfilm-script.ts → data: scenes, cursor paths, timings\nfilm-primitives.tsx → DOM: frame, sidebar, cursor SVG\nfilm-panels.tsx → DOM: each tab's content\nfilm-demo.tsx → GSAP: the entire choreography\nanimation-provider.tsx → React context: play/pause/restart\n```\n\nGSAP code lives in exactly one file. Everything else is inert markup with `data-film-*` attributes. A designer can rearrange the reference board without touching the timeline. The timeline targets elements by data attribute using `gsap.utils.selector(root)`, so React refs do not need to thread through component boundaries.\n\nThe demo in this article follows the same separation in miniature: every animated element has a `data-demo-*` attribute, and a single `useGSAP` hook contains the entire choreography.\n\nResponsive scaling is a CSS transform from a fixed design width. The container holds the aspect ratio, the film renders at full size and scales down. Same proportions, same cursor positions, same timing at every viewport width. No media queries.\n\n## And you can get crazy with it\n\nThree designers, one canvas, nobody waiting for a turn.\n\n```gsap-board-demo\n```\n\n## When this makes sense and when it does not\n\nI am not going to pretend this replaces video everywhere. It does not.\n\nIf your product demo involves real user data, logged-in dashboards, or workflows that change weekly, record a video. Scripting a timeline that mirrors a live product exactly is maintenance you do not want. Every time the UI changes, the animation breaks. A screen recording takes five minutes to redo.\n\nIf you are showing a physical product, a person talking, or anything outside the browser, video. Obviously. GSAP animates DOM elements, not reality.\n\nIf your team does not have someone comfortable reading a 400-line timeline file, video. This approach has a learning curve. The demos in this article took real engineering time, not drag-and-drop. Or an agent on your behalf.\n\nWhere it works: product walkthroughs of a stable UI that you want to feel alive. Onboarding sequences where you need the cursor to hit exact targets. Landing pages where the hero asset is the heaviest thing on the page.\n\nHere is the math. I measured the actual production build for the demos in this article:\n\n| Approach | Raw | Compressed | Notes |\n|----------|-----|------------|-------|\n| GSAP core (gsap.min.js) | 73 KB | 28 KB gzip | Shared across all animations on the page |\n| One demo component | 20 KB | 5.5 KB gzip | The simple task app above |\n| Both demos together | 115 KB | 37 KB gzip | Everything in this article |\n| 15s 1080p MP4 (H.264, optimized) | 2-4 MB | Does not compress further | Already codec-compressed |\n| 15s 1080p GIF | 8-15 MB | Does not compress further | GIF is the worst option by far |\n| 15s 1080p WebM (VP9) | 1-2...

gsap cursor product nthe time timeline

Related Articles