Skip to content

feat(web): scripted full-screen product demo mode#3927

Open
vibegui wants to merge 2 commits into
mainfrom
vibegui/interactive-studio-demo
Open

feat(web): scripted full-screen product demo mode#3927
vibegui wants to merge 2 commits into
mainfrom
vibegui/interactive-studio-demo

Conversation

@vibegui

@vibegui vibegui commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Summary

A public, fully-mocked, full-screen product demo (oya.ai-style) that animates the real Studio chat components from a scripted stream — no backend, MCP transport, or auth. The whole thing is a reusable framework: a demo reads top-to-bottom like a storyboard.

await d.user("Here's my store: https://acme.com — make it faster");
await d.tool(takeScreenshot({ url, image }));
await d.stream(DIAGNOSIS, { instant: true });

Two demos, each on its own URL (light mode)

  • /demo/storefront — business user drops in a URL → accurate perf+SEO diagnosis scorecard (real GFM table) → fix plan → parallel fixes → re-audit before/after → deploy.
  • /demo/agents — Studio as a web Conductor: the ghost cursor clicks Connect desktop → the real link modal opens → a mocked iTerm window runs `bunx decocms link` then minimizes → modal flips to Connected → work runs across two orgs in parallel (chat + live preview), switching context while the first org keeps building in the background.
  • /demo — a chooser linking to both. No cross-scenario auto-advance.

How it works (apps/mesh/src/web/demo/)

  • Director — non-React class owning all timing via `@decocms/std` `sleep`; mutates external `Store`s that components read through `useSyncExternalStore`, so no `useEffect` is needed to animate (the one lifecycle effect is documented, same pattern as `live-timer.tsx`).
  • Chat seam — `DemoChatStreamProvider` supplies a scripted `ChatStreamContextValue` (via a new exported `DemoChatStreamContext`), so the real `Chat.Messages` → `MessageAssistant` → tool-call renderers paint it identically to a live stream.
  • DemoProviders — mock `ProjectContext` + a network-free `QueryClient` (no auth gate).
  • Multi-track chats, org switching, iframe previews, ghost cursor, typed terminal — all driven by the same Director primitives.

The autoplay runner is guarded by a per-`stores` singleton with deferred teardown, so the dev runtime's spurious passive-effect re-runs (React Compiler / StrictMode) can't abort + restart a scenario mid-play.

Affected areas

  • New: `apps/mesh/src/web/demo/**`, `routes/demo.tsx`, `routes/demo-scenario.tsx`
  • Touched: `web/index.tsx` (register `/demo` + `/demo/$scenario` as public routes), `components/chat/chat-context.tsx` (export the chat-stream context for the demo seam — one line)
  • No backend/server changes.

Testing

  • `bun run check` ✅ · `bun run lint` ✅ · `bun run fmt:check` ✅
  • Verified end-to-end with Playwright: both demos run to completion in a stable loop with 0 console errors; zero network requests beyond static assets.
  • Screenshots: view live at `/demo/storefront` and `/demo/agents` (dev). UI is fully scripted/animated; static frames don't capture the motion.

🤖 Generated with Claude Code


Summary by cubic

Adds a public, full-screen Demo Mode that scripts the real Studio chat UI with no backend or auth. Includes paced beats, captions, smooth transitions, and a CTA end card; each demo plays once and then waits for replay.

  • New Features

    • Public routes: /demo chooser and /demo/$scenario (single scenario per URL; play-once then end card with “Get started free” and “Watch again”).
    • Reusable framework: non-React Director + external Stores (useSyncExternalStore) and an autoplay runner hardened against StrictMode re-runs; adds beat() pacing and stage caption() overlays.
    • Chat seam: DemoChatStreamProvider feeds a scripted ChatStreamContextValue to the real chat renderers.
    • Mock providers: ProjectContext + dedicated @tanstack/react-query client (staleTime: Infinity, no network, no auth).
    • Built-ins: multi-track chats, org switching with crossfade, ghost cursor-driven clicks, iframe preview fade-ins, and a typed terminal.
    • Demos:
      • /demo/storefront — paste URL → measured perf/SEO scorecard (real GFM) → approved plan → staggered parallel fixes → re-audit → deploy.
      • /demo/agents — connect desktop flow (bunx decocms link) → live preview → work runs across two orgs in parallel while switching context.
  • Refactors

    • Exported DemoChatStreamContext from components/chat/chat-context.tsx to let demos supply a scripted stream (no app behavior change).

Written for commit 9c2257e. Summary will update on new commits.

Review in cubic

vibegui and others added 2 commits June 15, 2026 14:39
Add a public, fully-mocked walkthrough that drives the REAL Studio chat
components from a recorded stream — no backend, MCP transport, or auth.

Framework (apps/mesh/src/web/demo/):
- Director: a non-React class that owns all timing via @decocms/std sleep
  and mutates external Stores; components subscribe via useSyncExternalStore,
  so no useEffect is needed to animate. Screenplays read as a storyboard
  (await d.user/stream/think/tool/parallel/endTurn) and support multiple
  parallel chat tracks plus org switching, previews, a ghost cursor, and a
  typed terminal.
- Chat seam: DemoChatStreamProvider supplies a scripted ChatStreamContextValue
  (via an exported DemoChatStreamContext) so the real renderers paint it
  identically to a live stream.
- DemoProviders: mock ProjectContext + a network-free QueryClient.

Two demos, each on its own URL (/demo chooser, /demo/<id>), light mode:
- /demo/storefront — business user drops in a URL and gets an accurate
  perf+SEO diagnosis scorecard, a fix plan, parallel fixes, and a re-audit.
- /demo/agents — Studio as a web Conductor: ghost cursor opens the connect-
  desktop modal, a mocked iTerm runs `bunx decocms link` then minimizes to
  "connected", then work runs across two orgs in parallel (chat + live
  preview) while switching context.

The autoplay runner is guarded by a per-stores singleton with deferred
teardown so the dev runtime's spurious effect re-runs can't restart a
scenario mid-play.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reworked the scripted demos for rhythm and a real ending.

- Pacing: deliberate beats with anticipation captions, reading holds after
  big content (diagnosis / result tables), staggered parallel fixes, and
  smoother typing speeds.
- Transitions: caption fade/slide, org-workspace crossfade on switch, preview
  iframe fade-in on change, and cursor-driven org switching (the ghost cursor
  glides to and clicks the org tab) instead of hard cuts.
- Ending: the demo no longer loops silently — after a full play-through it
  shows an end card ("Get started free" / "Watch again"). The runner plays
  once, then awaits a replay signal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant