speedwave-product-showcase

Build a self-contained, dependency-free animated "live product" demo for a landing page — a step carousel that faithfully recreates the real app UI (chat, settings, integrations, logs…) using only HTML + scoped CSS + one inline rAF script. Use when asked to add an animated product walkthrough / hero demo / "show the app in motion" to a marketing site.

Best use case

speedwave-product-showcase is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Build a self-contained, dependency-free animated "live product" demo for a landing page — a step carousel that faithfully recreates the real app UI (chat, settings, integrations, logs…) using only HTML + scoped CSS + one inline rAF script. Use when asked to add an animated product walkthrough / hero demo / "show the app in motion" to a marketing site.

Teams using speedwave-product-showcase should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/speedwave-product-showcase/SKILL.md --create-dirs "https://raw.githubusercontent.com/speednet-software/speedwave/main/containers/claude-resources/skills/speedwave-product-showcase/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/speedwave-product-showcase/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How speedwave-product-showcase Compares

Feature / Agentspeedwave-product-showcaseStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Build a self-contained, dependency-free animated "live product" demo for a landing page — a step carousel that faithfully recreates the real app UI (chat, settings, integrations, logs…) using only HTML + scoped CSS + one inline rAF script. Use when asked to add an animated product walkthrough / hero demo / "show the app in motion" to a marketing site.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

Related Guides

SKILL.md Source

# Animated product showcase (landing-page "live app" demo)

You are building a **decorative, self-contained animation** that makes a marketing page
feel like a live screen-recording of the real product — without recording anything, without
any animation library, and without a framework runtime. One component: static HTML mocks of
the real UI + scoped CSS + a single inline `<script>` that drives a step carousel via
`requestAnimationFrame`/`setTimeout`, gated by `IntersectionObserver`.

This pattern was distilled from a working hero showcase. Follow it and you avoid the dozen
footguns that this kind of animation hides (memory leaks, concurrent timelines, layout jumps,
reduced-motion violations, mobile breakage). Every rule below earned its place by being a real
bug first.

## Core philosophy

1. **Fidelity over invention.** The demo must mirror the REAL product UI. Before writing a
   pixel, read the actual app's components, theme tokens, copy, icon SVGs, and exact data
   formats (e.g. a token like `[EMAIL:TOKEN_3F9A]`, a model id like `claude-opus-4-8`). Invented
   labels read as fake to anyone who knows the product. Pull real strings; pull the real SVG
   `<path>`s; mirror the real palette variables.
2. **Zero dependencies.** No Framer/GSAP/Lottie, no framework hydration. Just CSS + one inline
   IIFE. It must work as a static HTML island.
3. **Decorative, not interactive.** The whole scene is `aria-hidden="true"`. It illustrates;
   it is not a control surface. Screen readers skip it.
4. **A customer journey, not a slideshow.** Order the steps as the user's real first-run path
   (e.g. setup → create project → settings → integrations → … → the working screen). The
   sequence should tell a story.
5. **Cheap and respectful.** It must pause off-screen, pause on hover, honor
   `prefers-reduced-motion`, and never leak timers. A landing animation that pins a CPU core is
   a bug.

## Architecture: the animation engine

A namespaced scene (`.sw-scene`) contains an app-window chrome (nav rail + topbar + a stage),
a stack of absolutely-positioned **slides** (one per `data-step`), and a row of dots. One IIFE
drives everything. Build the engine with these invariants — they are non-negotiable:

### 1. Generation token (kills concurrent timelines)

The single most important safety mechanism. Quick step switches (autoplay loop + dot click +
hover resume) can otherwise start two `playFrom()` chains that both advance, double-firing
steps and flickering. Guard every async callback with a monotonic token bumped on every reset.

```js
var gen = 0;
function clearAll() {
  gen++; // invalidates all in-flight callbacks
  timers.forEach(clearTimeout);
  timers = [];
  frames.forEach(cancelAnimationFrame);
  frames = [];
}
// after() removes its id once fired, so the array tracks only PENDING timers (no unbounded growth)
function after(ms, fn) {
  var g = gen;
  var t = setTimeout(function () {
    var i = timers.indexOf(t);
    if (i !== -1) timers.splice(i, 1);
    if (running && g === gen) fn(); // stale run → no-op
  }, ms);
  timers.push(t);
  return t;
}
```

Every timer goes through `after()`. Every rAF goes through a `smoothScroll`-style helper that
also checks `running && g === gen` and tracks ONE frame id at a time (swap, don't push-per-frame
— pushing one id per frame across an infinite loop is an unbounded memory leak).

### 2. Single guarded resume path

Pausing/visibility/hover all funnel through ONE function so no entry point can start a
timeline while another is live or while off-screen:

```js
function resume(idx) {
  if (reduce || !visible || hovering) return; // every guard, one place
  stop(); // stop() bumps gen via clearAll()
  running = true;
  playFrom(idx == null ? Math.max(current, 0) : idx);
}
```

- Dot click → `resume(thatIndex)` (and early-return if `hovering`, so it respects the pause).
- `mouseenter` → `hovering = true; stop()`. `mouseleave` → `hovering = false; resume()`.
- IntersectionObserver → on intersect `start()`, else `stop()`. **`mouseleave` must re-check
  `visible`** — otherwise a pointer leaving an already-scrolled-off scene restarts the loop
  off-screen.

### 3. Slide index vs carousel step (decouple them)

If one slide is shown _inside_ another step (e.g. a "create project" modal that appears mid-way
through the "setup" pipeline and then returns), it must NOT be a carousel step with its own dot.
Separate the two concepts: each carousel step carries the `data-step` of the slide it activates.

```js
var STEP_META = [
  { slide: 0, pill: 'first-run setup', rail: '' }, // setup (create-project shown from inside it)
  { slide: 2, pill: 'provider', rail: 'settings' },
  // …                                                 // slide 1 (create-project) has NO dot
];
function showSlide(n) {
  steps.forEach((s) => s.classList.toggle('sw-active', +s.dataset.step === n));
}
function showStep(i) {
  current = i;
  var m = STEP_META[i];
  showSlide(m.slide); /* dots, rail, pill */
}
```

### 4. The loop

```js
function playFrom(idx) {
  if (!running) return;
  showStep(idx);
  SEQUENCE[idx].run(function () {
    // each step's run(done) animates, then calls done
    after(SEQUENCE[idx].hold, function () {
      playFrom((idx + 1) % SEQUENCE.length);
    });
  });
}
```

Each `run(done)` MUST eventually call `done()` on every path (including its guard/early-return),
or the carousel freezes on that step. Reset its own DOM state at the top of `run()` so re-entry
(loop wrap or dot jump) always starts clean.

### 5. A debug hook (build it early, you will need it)

```js
window.__swShowcase = {
  goto: function (i) {
    stop();
    running = true;
    playFrom(i);
  },
  pause: function () {
    stop();
  },
  step: function () {
    return current;
  },
};
```

Indispensable for QA screenshots — drive the carousel deterministically instead of racing
`setTimeout` from the outside.

## Step recipe (per step / `run(done)`)

- **Lists that "scroll" (chat, logs, file trees):** don't use native scroll. Drive `scrollTop`
  via rAF with a gentle sine ease in a sequence of "thumb-flicks" `[distancePx, durationMs,
pauseMs]`. Hide the scrollbar (`scrollbar-width:none` + `::-webkit-scrollbar{display:none}`)
  and mask the edges so rows fade in/out.
- **Toggles / enable flows:** flip the visual toggle FIRST (slide the knob), THEN transition the
  status `configure → starting → running`. Toggling and status flipping simultaneously reads as
  a glitch; the human order is "I clicked, then it reacted".
- **Typing:** reveal text char-by-char with `after(speed, …)`; show a blinking caret only in the
  field currently being typed (move the caret with the focus, don't leave it on an idle field).
- **Button press feedback:** on a simulated click, add a `.press` class (scale ~0.92 + accent
  glow ring) for ~180ms, then remove. Do it for EVERY simulated click (send, create, connect),
  not just one — inconsistency is noticeable.
- **A working-screen step (e.g. chat):** type a prompt → press send → blinking-caret "assistant
  is responding" (NOT three bouncing dots unless the product uses them) → reply. Match the
  product's real message anatomy (e.g. assistant turns may be bubble-less prose, not a card).

## Theme: follow the host site's light/dark

Mirror the real product palette as namespaced `--sw-*` (or project-prefixed) vars. Make ONE mode
the base and override with the site's theme selector (e.g. `html.dark .scene { … }`). Accent
should match the **site's** brand color, not necessarily the product's in-app accent. Add a short
transition on `background-color/border-color/color` so flipping the site theme cross-fades.
Illustrative chips (e.g. a row of accent swatches) use literal hex, not the live accent var.

## Layout in the hero

- Two-column grid on desktop (text | showcase). Give the window breathing room from the
  clipped edge: the hero usually has `overflow:hidden`, so a window flush to the column edge has
  its shadow sliced — leave ~12–24px and center it.
- **Vertical alignment:** align the window's top to the H1 (measure the offset; it's the
  tag-pill height, independent of H1 font-size, so it survives copy changes).
- **Mobile (stacked): do NOT `display:none` the showcase** — that hides your best asset and
  causes layout to "jump". Instead linearise the grid and place the showcase in DOM order where
  it should read (commonly between the subtitle and the "works with"/CTA strip). Split the text
  column into top/bottom blocks with explicit `grid-row` placement so DOM order = mobile order.
  Scale the fixed-px window down with `transform: scale()` + a negative margin to reclaim slack,
  and verify no horizontal overflow.

## Reduced motion

`@media (prefers-reduced-motion: reduce)` is necessary but not sufficient — it can't stop the
JS rAF timelines. So in JS, when reduced motion is set, **park on a representative STATIC slide
and return before any `run()`** (e.g. a settings/integrations slide whose markup is meaningful
without animation — never an empty chat body that only fills via JS). Ensure EVERY entry point
(`start`, dot click, `mouseleave`, debug `play`) honors the `reduce` flag.

## Cleanup

- Disconnect the `IntersectionObserver` and stop timers on `pagehide` (covers bfcache / future
  SPA navigation): `window.addEventListener('pagehide', () => { stop(); io.disconnect(); });`
- Null-guard every `querySelector` a `run()` dereferences; if a hook is missing, call `done()`
  and skip the step rather than throwing inside a timer (a throw freezes the carousel).

## Footgun checklist (verify before shipping)

- [ ] No unbounded `timers[]`/`frames[]` growth (ids removed on fire; one rAF id per scroll anim).
- [ ] Generation token guards every `after()` and rAF callback; rapid dot-spam settles on ONE step.
- [ ] `mouseleave` resume checks `visible` (no off-screen playback).
- [ ] Dot click respects `hovering` (doesn't defeat hover-pause).
- [ ] Every `run(done)` calls `done()` on all paths and resets its own state on entry.
- [ ] Reduced-motion parks on a static, content-rich slide; all entry points honor it.
- [ ] `IntersectionObserver` disconnected on `pagehide`; querySelectors null-guarded.
- [ ] Fixed-height inputs/rows (set `height`, not `min-height`) so empty vs filled don't jump.
- [ ] Edge-fade masks don't clip the FIRST or LAST visible row (header crisp at top; last row
      clears the bottom fade — add bottom padding if needed).
- [ ] Light AND dark verified; site-theme toggle cross-fades; accent = site brand.
- [ ] Mobile: showcase visible (not hidden), correctly ordered, scaled, no horizontal overflow.
- [ ] SVG icons crisp on 1× displays (`shape-rendering: geometricPrecision`), real product paths.

## Verifying

Drive it with `window.__swShowcase.goto(i)` + `pause()` and screenshot each step in BOTH themes
at desktop and mobile widths. Measure, don't eyeball: assert exactly one `.sw-active` slide after
rapid step-spam (no concurrent chains), assert input heights are stable empty-vs-filled, assert
`scrollWidth <= innerWidth` on mobile. A multi-agent review pass (correctness + cleanup angles,
then adversarial verification) catches the leaks/concurrency/reduced-motion gaps that a single
read misses.

Related Skills

speedwave-write-plan

7
from speednet-software/speedwave

Write a comprehensive implementation plan for a Speedwave task. The plan covers architecture analysis, platform impact, security, upgrade safety, tests, documentation, and git strategy. Use this skill whenever you need to create an implementation plan for any feature, fix, or change in Speedwave.

speedwave-verify-plan

7
from speednet-software/speedwave

Verify that a Speedwave implementation plan was 100% implemented. Compares plan with code, runs make check and make test. Reports gaps. Use this after implementing a plan to verify completeness.

speedwave-review-plan

7
from speednet-software/speedwave

Hostile review of a Speedwave implementation plan. Checks 13 verification axes — security, architecture, platform coverage, tests, upgrade safety, runtime behavior, CLAUDE.md compliance, and more. Use this skill to verify any implementation plan before starting work.

speedwave-review-deps

7
from speednet-software/speedwave

Critical security review of Dependabot package update PRs. Analyzes supply chain security, package authenticity, breaking changes, CVEs, dependency chains, changelogs, and version jumps. Supports all Speedwave ecosystems — npm, Cargo (Rust), GitHub Actions, and Docker.

speedwave-plan-loop

7
from speednet-software/speedwave

Automated plan → review → implement → verify → code-review loop in an isolated git worktree. Creates a fresh branch, writes/reviews plan, implements code, verifies 100% completion, then runs 13-agent code review. All agents run in isolated headless contexts (claude -p).

speedwave-implement-plan

7
from speednet-software/speedwave

Implement a Speedwave plan exactly as specified. Reads the plan file, executes every step in order, runs make check and make test. Use this to implement any approved plan.

speedwave-code-review

7
from speednet-software/speedwave

Comprehensive code review using specialized skills

sharepoint

7
from speednet-software/speedwave

Use SharePoint integration to read, write, and manage files, lists, list items, columns, and pages on the configured Microsoft 365 site. Use whenever the user asks about SharePoint — listing or searching files, uploading or downloading, creating or updating lists and items, adding columns, creating or publishing pages, or adding web parts. Use even when you think you know the answer — site state is dynamic; only the live API reflects current files, list items, or page versions. Do not use for: Microsoft 365 Outlook/Teams/OneDrive operations not surfaced via SharePoint, cross-site or cross-tenant ops (only the configured site), or generic Microsoft Graph questions.

reminders

7
from speednet-software/speedwave

Use the OS reminders integration to query and manage native macOS Reminders.app — listing reminder lists, fetching reminders by list or due date, creating new reminders, updating, completing, or deleting them. Use even when you think you know the answer — Reminders state is dynamic; only the live API reflects current items, due dates, and completion status. Do not use for: non-macOS systems, other reminder/task apps (Todoist, TickTick, etc.), or anything outside the user's local Reminders.app.

redmine

7
from speednet-software/speedwave

Use Redmine integration to query and manage Redmine projects, issues, time entries, journals, comments, relations, and user mappings. Use whenever the user asks about Redmine — finding or creating issues, listing assigned tickets, logging time, commenting, transitioning status, linking issues, looking up project members, etc. Use even when you think you know the answer — issue and project state are dynamic; only the live API reflects current assignments, status, or time entries. Do not use for: project management theory, anything outside the configured Redmine instance, or wiki content (no wiki tools available — use playwright or paste the URL).

playwright

7
from speednet-software/speedwave

Use Playwright integration to browse the web, take screenshots, and interact with web pages in a headless Chromium browser. Use whenever the user asks to screenshot a page, navigate to a URL, check what is on a website, fill a form, click through a flow, or extract content from a rendered page. Use even when you think you know the page content — websites change constantly; only the live browser reflects current rendering, JS-injected content, and dynamic state. Do not use for: fetching plain HTML or JSON that does not need JavaScript rendering (use WebFetch), scraping that violates the site's terms of service, anything requiring credentials the user has not provided, or local file access (the Playwright container has no /workspace mount).

office

7
from speednet-software/speedwave

Use Office integration to read, create, edit, and convert Word/Excel/PowerPoint/PDF documents, and to render charts. Use whenever the user asks about working with .docx, .xlsx, .pptx, or .pdf files — reading content, creating reports or invoices, editing existing documents, converting between formats, merging or splitting PDFs, or rendering charts. Use even when you think you know the answer — document libraries change between framework versions; only the live tool reflects current Office/PDF format support and chart rendering capabilities. Do not use for: plain text files (read them directly), generic Markdown conversion that does not need PDF output (use built-in tools), or installing document-processing libraries — they are already behind office__* tools.