Skip to content

Add hero diagram, project icon, and VHS demo pipeline (#46)#78

Merged
obj-p merged 8 commits intomainfrom
worktree-readme-polish
Apr 11, 2026
Merged

Add hero diagram, project icon, and VHS demo pipeline (#46)#78
obj-p merged 8 commits intomainfrom
worktree-readme-polish

Conversation

@obj-p
Copy link
Copy Markdown
Owner

@obj-p obj-p commented Apr 11, 2026

Summary

  • Restructures the README header with a centered icon, tagline, and a Mermaid flow diagram showing the AI-agent → MCP → simulator → snapshot loop
  • Adds an SVG project icon at assets/icon.svg (orange/pink gradient, preview-window motif with a device frame and a green live-indicator dot)
  • Adds a reproducible demo-GIF pipeline: scripts/demo.tape (vhs script) + scripts/record-demo.sh (deps check + release build + vhs invocation)

Addresses parts of #46 — hero diagram and icon land now; the demo GIF lands after running scripts/record-demo.sh (the README reference is currently commented out so GitHub doesn't render a broken image).

Notes

  • Renderer-agnostic: Mermaid renders natively on GitHub, the SVG is text/diff-able, and the GIF is regeneratable from the tape.
  • The tape uses the bundled SPM ToDo example and pipes the resulting snapshots through chafa so the GIF visually shows both the CLI and the rendered preview without needing a separate screen recording.
  • New runtime deps for the demo pipeline only (not the project): vhs, chafa. Documented in the README's "Regenerating the demo GIF" section.

Test plan

  • xmllint validates assets/icon.svg
  • SVG renders cleanly via rsvg-convert (verified visually)
  • Run scripts/record-demo.sh on a machine with vhs/chafa installed and confirm assets/demo.gif is produced
  • Uncomment the GIF <img> block in README.md and verify it renders in GitHub preview

obj-p and others added 8 commits April 10, 2026 22:13
Restructures the README header with a centered icon, tagline, and a
Mermaid flow diagram showing the AI-agent → MCP → simulator → snapshot
loop. Adds an SVG icon (assets/icon.svg) and a vhs-driven demo pipeline
(scripts/demo.tape + scripts/record-demo.sh) so the demo GIF can be
regenerated reproducibly. The GIF reference in the README is commented
out until the first recording lands.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Records assets/demo.gif via vhs against the bundled SPM ToDo example and
embeds it in the README header alongside the captured light/dark variant
PNGs. Simplifies the tape (drops chafa — it prints multi-image output
vertically, which overflows the terminal viewport) so the demo ends on
the variants progress output and the two captured file paths.

record-demo.sh now prefers an existing release/debug binary, drops the
chafa dependency, and copies the variant PNGs into assets/ as part of
the recording pipeline.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…46)

assets/demo.gif is now a side-by-side composite: `vhs` captures the
terminal running `previewsmcp list` and `previewsmcp run --platform
ios`, `xcrun simctl io recordVideo` captures the booted simulator, and
ffmpeg hstacks them with `tpad` to hold both final frames. scripts/
record-demo-ios.sh orchestrates the whole pipeline — warmup, parallel
recording, compositing, palette-gen gif.

Also fixes a latent bug in BuildHelpers.launchIOSPreview where the
FileWatcher for `run --platform ios` was a local `let`, released as
soon as the function returned. The timer closure used [weak self],
so deinit silently cancelled the polling timer and hot reload never
fired. Retained via a module-level IOSRunHolder.

The demo now shows the payoff clearly: editing ToDoView.swift renames
the navigation title from "My Items" to "Focus Mode" live in the
simulator, with the terminal logging "Literal-only change applied
(state preserved)" at the moment of the swap.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adopts the AppIcon.png composition (IDE window on the left, iPhone on
the right with content card, circular sync arrows over the overlap)
but keeps the flat orange→pink gradient and white foreground from the
previous icon. Same 256×256 viewBox, still pure SVG.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rasterized from assets/icon.svg at 1024×1024 via rsvg-convert so the
iOS host app's icon matches the new README branding.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Tape now performs two dramatic hot-reload edits: grows the SummaryCard
  from height 120 to 220 (literal-only, state preserved) and recolors
  it from .blue to .pink (structural recompile — on-brand). The pink
  card at full height is a much clearer wow moment than the prior
  navigationTitle-only swap.
- Removes the two variant preview PNGs under the hero GIF and drops
  the now-unused scripts/demo.tape + scripts/record-demo.sh pipeline
  that produced them.
- Moves the "how to regenerate the demo" documentation out of the
  README and into scripts/record-demo-ios.sh's header comment so the
  instructions live next to the code they describe.
- record-demo-ios.sh now trims sim.mp4 to the timestamp of its last
  real frame before compositing — simctl recordVideo pads several
  seconds of silence after SIGINT, which was stretching the gif to
  ~63s. Also tightened tape Sleeps where the previous runs showed
  slack.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three issues on top of the previous iOS demo recording:

1. IOSHostBuilder's cache key hashed only the Swift source, not the
   bundled resources — replacing AppIcon.png left a stale .app bundle
   in /tmp/previewsmcp-host serving the old icon indefinitely. The
   hash now covers the source, the info plist, and the icon PNG data.
   record-demo-ios.sh also wipes the host-app workdir before recording
   so any cache-busting edge cases can't bite.

2. The recording previously opened with the last-session's host app
   still showing. `simctl uninstall` doesn't return to home (iOS keeps
   a snapshot of the last foreground app), and osascript Cmd+Shift+H
   doesn't reach the Simulator when it's been launched headless. The
   script now kickstarts SpringBoard via launchctl, which forces a
   fresh home screen, and waits 10s for it to settle before starting
   the simulator recording.

3. simctl recordVideo is variable-framerate with sparse samples, which
   made the composite simulator half feel laggy against the vhs
   terminal half. The composite filtergraph now runs `fps=15` (before
   `trim` — order matters on VFR sources) on both inputs so the gif
   plays at a consistent 15fps. Also trims sim.mp4 to the terminal's
   duration + 1.5s to stop simctl's post-SIGINT ghost frames from
   stretching the composite.

The ToDoView demo's final color-swap sleep is also bumped 8s → 14s so
the structural recompile finishes before the tape cuts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Addresses review findings on PR #78:

- Move iOS `run` file-watcher retention from the module-level
  `IOSRunHolder` in BuildHelpers.swift to a proper hand-off through
  `PreviewHost.retainFileWatcher`. PreviewHost is already the MainActor
  app-lifetime singleton that stores the macOS path's watchers; storing
  iOS watchers there too removes the `nonisolated(unsafe) static var`
  footgun and matches the existing pattern.
- Add a regression test in the new PreviewsMacOSTests target that
  creates a FileWatcher inside an inner scope, hands it to
  PreviewHost.retainFileWatcher, releases the local binding, and then
  asserts the callback still fires on a subsequent file modification.
  Without the retention hand-off the timer closure's weak self would
  cause deinit immediately and the test would go red — a direct guard
  against regressing the original hot-reload bug.
- Drop `rm -rf /tmp/previewsmcp-host` from scripts/record-demo-ios.sh.
  It was a defensive workaround for the stale-cache bug fixed in the
  previous commit (IOSHostBuilder.sourceHash now covers resources), and
  it was costing ~30s per recording regen for no remaining benefit.
- Pass `$term_dur` into awk via `-v` instead of string interpolation.
  Trusted source here (ffprobe on a file we just wrote) so no active
  vulnerability, but the previous pattern would have produced a parse
  error on any non-numeric output — wrong-by-default.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@obj-p obj-p merged commit 01eb010 into main Apr 11, 2026
4 checks passed
@obj-p obj-p deleted the worktree-readme-polish branch April 11, 2026 21:48
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