# Plan: A captured terminal demo for asmdiff's README / portfolio

## Prerequisites — install before execution

Please install **VHS** (the recording tool). Homebrew is already on this machine,
which pulls in VHS plus its `ttyd` and `ffmpeg` dependencies in one shot:

```bash
brew install vhs
```

Verify it's on PATH before we start: `vhs --version` and `ttyd --version`.

Everything else the plan needs is already present and requires **no install**:
- `asmdiff` (on PATH via `uv tool install`), `uv`/`uvx`
- `gcc`, `clang`, `objdump`, `ffmpeg`

*(Non-brew fallback, only if you'd rather not use brew: `go install
github.com/charmbracelet/vhs@latest` plus a `ttyd` binary — `ffmpeg` is already
installed. Or, to skip Go/ttyd entirely, `uv tool install termtosvg` and use the
animated-SVG alternative described below.)*

## Context

`asmdiff`'s README is thorough but entirely text — there is no visual asset in
the repo. For a portfolio/README, a short captured terminal workflow shows the
tool "doing its thing" in seconds and is the single highest-leverage thing to
add. The output is a good fit for capture: deterministic, **monochrome** plain
text (verified — zero ANSI escapes), whose appeal is the aligned side-by-side
listings and the `insns / loop spans / calls` summary table.

**Decisions locked in (from the user):**
- `asmdiff` is **installed on PATH via `uv tool install`**, with a global config at
  `~/.config/asmdiff.toml`. So the recording uses the bare **`asmdiff ...`** command
  (cleaner than `uvx`, and it removes the one-time PyPI-download pre-warm step
  entirely). `uvx asmdiff ...` remains a fine alternative if you specifically want
  to show the zero-install one-liner from the README.
- A **3-beat guided tour** (~40–60s), not a single command.
- Format: user deferred to recommendation → **VHS** (see below). User confirmed
  they can install `go`/`npm`/`cargo`; simplest path is Homebrew (already present
  at `/home/linuxbrew`).

**Important config-precedence gotcha:** any beat that passes no `--cc`/`--target`
(beats 1 and 3 as written) uses the `default` target in `~/.config/asmdiff.toml`.
If that default is an ESP/cross target, beat 1 will try to cross-compile instead of
showing the clean host gcc/clang matrix — and the GIF won't reproduce for anyone
whose config differs. Pin the demo to host codegen (see the tape's `--config` /
explicit-`--cc` handling below) so the result is deterministic regardless of the
machine's global config.

## Recommended approach: VHS (`charmbracelet/vhs`)

Record from a **version-controlled `.tape` script**, not a hand-typed live
session. VHS is the standard for CLI-tool README demos and is the right fit here:

- **Reproducible & regenerable** — the `.tape` lives in the repo; regenerate the
  GIF any time the tool's output changes. This is what makes it portfolio-grade
  rather than a one-off screen recording.
- **Precise control** — terminal geometry, theme, font, typing speed, and pauses
  are all scripted, so every take is identical and readable.
- **Inline on GitHub with no hosting** — outputs a GIF committed to the repo and
  embedded with a plain `![](...)`; no asciinema.org link or player JS needed.
- Deterministic monochrome text captures crisply as a GIF (color isn't lost —
  there is none).

Alternative if a GIF ever feels too heavy: **termtosvg** (`uv tool install
termtosvg`) produces a self-contained animated SVG, no Go/ttyd needed. Noted as a
fallback only; VHS is the recommendation.

## Tooling install

`ffmpeg` is already present. Easiest single install (Homebrew is available):

```bash
brew install vhs        # pulls in vhs + ttyd + ffmpeg
```

(Non-brew path, since Go/npm are installable: `go install
github.com/charmbracelet/vhs@latest` plus a `ttyd` binary.)

## Files to create

All under a new `demo/` directory (referenced from the README):

- **`demo/demo.tape`** — the VHS script (below). The only hand-authored file.
- **`demo/demo.gif`** — generated by `vhs demo/demo.tape`, committed to the repo.
- Optional: a `Makefile`/`justfile` target `make demo` running `vhs demo/demo.tape`
  so regenerating is one command.

### `demo/demo.tape` (starting point)

Key details baked in: keep the terminal ≥ ~100 cols so the fixed 92-col side-by-side
listing is never width-trimmed; run from the repo root so `asmdiff_example.c`
resolves; and **pin the compiler matrix** so the GIF is host-deterministic
regardless of `~/.config/asmdiff.toml`. Two ways to pin — pick one:

- **Simplest:** commit a tiny `demo/asmdiff.toml` with `default = ["host-gcc",
  "host-clang"]` (two host targets), record from `demo/`, and let the no-`--cc`
  beats use it. Shows off the config feature *and* stays reproducible.
- **Or:** pass `--cc 'gcc -O3' --cc 'clang -O3'` explicitly on beats 1 and 3.

The tape below uses the explicit-`--cc` form (no extra file needed):

```tape
Output demo/demo.gif
Require asmdiff

Set Shell   bash
Set FontSize 16
Set Width   1300           # ~110 cols at this font — clears the 92-col layout
Set Height  820
Set Padding 24
Set Theme   "Builtin Solarized Dark"   # pick any clean dark theme
Set TypingSpeed 55ms

# --- Beat 1: the headline — side-by-side asm + fold-vs-libcall table ---
Type "asmdiff asmdiff_example.c --cc 'gcc -O3' --cc 'clang -O3'" Sleep 400ms Enter
Sleep 4.5s

# --- Beat 2: same function across optimization levels ---
Type "asmdiff asmdiff_example.c --across new_rt --cc 'gcc -O0' --cc 'gcc -O3'" Sleep 400ms Enter
Sleep 4.5s

# --- Beat 3: quick-inspect one function (no comparison) ---
Type "asmdiff asmdiff_example.c old_rt --cc 'gcc -O3'" Sleep 400ms Enter
Sleep 4s
```

**Beat rationale (all verified to run on the bundled `asmdiff_example.c`):**
1. `asmdiff asmdiff_example.c ...` — the money shot: two `old_*|new_*` side-by-side
   listings plus the summary table whose `calls` column shows `exp2f`/`ldexpf`
   (fold-vs-libcall). This alone communicates what the tool is for.
2. `--across new_rt --cc 'gcc -O0' --cc 'gcc -O3'` — the same function under two
   flag sets, showing the `cc#N` legend + baseline/candidate framing (13 insns → 2).
3. `... old_rt --cc 'gcc -O3'` — inspect mode: "just show me one function," a single
   clean listing + stats row. Demonstrates the tool is not only for A/B.
   - *Swap-in option:* `asmdiff --example-config | head -30` instead, to show the
     batteries-included ESP/STM32/RP2350 config as beat 3 (and it needs no `--cc`).

## README embedding

Add near the top, right under the tagline (before "Try it yourself"):

```markdown
![asmdiff in action](demo/demo.gif)
```

Reuse the existing worked-example prose in the README as the caption context — the
GIF replaces having to imagine the output.

## Verification (end-to-end)

1. From the repo root: `vhs demo/demo.tape` → produces `demo/demo.gif`.
2. Open the GIF and confirm: all three beats play, the side-by-side columns are
   **not** truncated (if they are, raise `Set Width` / lower `Set FontSize` and
   re-run), and beat 1 shows the intended host gcc/clang matrix (not a cross target
   pulled from `~/.config/asmdiff.toml`).
3. Check file size is README-friendly (aim < ~2–3 MB; trim `Sleep`s or width if
   larger).
4. Preview the README locally (or push to a branch) to confirm GitHub renders the
   GIF inline.
5. Commit `demo/demo.tape` + `demo/demo.gif` and the README edit together.

## Notes / gotchas

- Because the tape pins `--cc` explicitly, the recording is independent of both the
  installed version's default flags and whatever `default` sits in
  `~/.config/asmdiff.toml`. If you drop the explicit `--cc` (e.g. to demo the
  zero-config UX), first check `asmdiff --example-config`-style config: a stray ESP
  `default` will hijack the run.
- `clang` is present here, so beat 1 emits both a `gcc -O3` and a `clang -O3`
  section — good, it reinforces the "matrix" story; size `Set Height` to fit both,
  or drop the `--cc 'clang -O3'` if you want a shorter frame.
- Keep the `.tape` the source of truth: never hand-edit the GIF; regenerate.




## User feedback 

Evaluate the value of including these in the demo.

- Full Esp32 xtensa matrix in a real workspace via asmconfig.toml, automatic parsing of compile_commands, show real differences without building 3 seperate isolated workspaces with the chance of messing up a 100 setup manual setup.

```bash 
  asmdiff main/main.c -db
target [esp32]: cc pattern matched 2 toolchains, using /home/fatta/.espressif/tools/xtensa-esp-elf/esp-15.2.0_20251204/xtensa-esp-elf/bin/xtensa-esp32-elf-gcc
target [esp32s2]: cc pattern matched 2 toolchains, using /home/fatta/.espressif/tools/xtensa-esp-elf/esp-15.2.0_20251204/xtensa-esp-elf/bin/xtensa-esp32s2-elf-gcc
target [esp32s3]: cc pattern matched 2 toolchains, using /home/fatta/.espressif/tools/xtensa-esp-elf/esp-15.2.0_20251204/xtensa-esp-elf/bin/xtensa-esp32s3-elf-gcc

== /home/fatta/.espressif/tools/xtensa-esp-elf/esp-15.2.0_20251204/xtensa-esp-elf/bin/xtensa-esp32-elf-gcc -O2 -mlongcalls ==

function                       insns  loop spans               calls
is_power_of_two                11     .L3:5                    -
new_delay_line                 42     .L13:5 .L16:23 .L21:16   fprintf, abort, memset, malloc_caps
free_delay_line                4      -                        free
delay_line_in_out              83     .L25:53                  -
delay_line_in_out_fixed_delay  169    .L31:24 .L35:35 .L36:35  -
apply_variable_delay           11     -                        delay_line_in_out
apply_fixed_delay              11     -                        delay_line_in_out_fixed_delay
new_reverb                     13     .L48_LEND:2              malloc_caps
delete_reverb                  5      -                        free
config_stereo_reverb           39     -                        __divsf3
deinit_stereo_reverb           34     -                        free
init_stereo_reverb             97     -                        new_delay_line, fwrite, deinit_stereo_reverb
stereo_reverb                  509    .L110:290                -
TOTAL (13 functions)           1028   -                        fprintf, abort, memset, malloc_caps, free, delay_line_in_out, delay_line_in_out_fixed_delay, __divsf3, Total Calls:11

== /home/fatta/.espressif/tools/xtensa-esp-elf/esp-15.2.0_20251204/xtensa-esp-elf/bin/xtensa-esp32s2-elf-gcc -O2 -mlongcalls ==

function                       insns  loop spans               calls
is_power_of_two                11     .L3:5                    -
new_delay_line                 42     .L13:5 .L16:23 .L21:16   fprintf, abort, memset, malloc_caps
free_delay_line                4      -                        free
delay_line_in_out              84     .L25:53                  -
delay_line_in_out_fixed_delay  171    .L30:24 .L34:35 .L35:35  -
apply_variable_delay           11     -                        delay_line_in_out
apply_fixed_delay              11     -                        delay_line_in_out_fixed_delay
new_reverb                     10     -                        malloc_caps, memset
delete_reverb                  5      -                        free
config_stereo_reverb           29     -                        __mulsf3, __fixsfsi, __divsf3, __subsf3
deinit_stereo_reverb           34     -                        free
init_stereo_reverb             97     -                        new_delay_line, fwrite, deinit_stereo_reverb
stereo_reverb                  508    .L93:289                 -
TOTAL (13 functions)           1017   -                        fprintf, abort, memset, malloc_caps, free, delay_line_in_out, delay_line_in_out_fixed_delay, __mulsf3, Total Calls:14

== /home/fatta/.espressif/tools/xtensa-esp-elf/esp-15.2.0_20251204/xtensa-esp-elf/bin/xtensa-esp32s3-elf-gcc -O2 -mlongcalls ==

function                       insns  loop spans               calls
is_power_of_two                11     .L3:5                    -
new_delay_line                 42     .L13:5 .L16:23 .L21:16   fprintf, abort, memset, malloc_caps
free_delay_line                4      -                        free
delay_line_in_out              83     .L25:53                  -
delay_line_in_out_fixed_delay  169    .L31:24 .L35:35 .L36:35  -
apply_variable_delay           11     -                        delay_line_in_out
apply_fixed_delay              11     -                        delay_line_in_out_fixed_delay
new_reverb                     13     .L48_LEND:2              malloc_caps
delete_reverb                  5      -                        free
config_stereo_reverb           39     -                        __divsf3
deinit_stereo_reverb           34     -                        free
init_stereo_reverb             97     -                        new_delay_line, fwrite, deinit_stereo_reverb
stereo_reverb                  509    .L110:290                -
TOTAL (13 functions)           1028   -                        fprintf, abort, memset, malloc_caps, free, delay_line_in_out, delay_line_in_out_fixed_delay, __divsf3, Total Calls:11
``` 

- Finding exactly the readme microsecond example in real Amy source

  [Rapport](amy-hotspot-analysis.md)
