mycelium-io

screenshot

Take a screenshot of the running Mycelium app, or of CLI output rendered as a terminal card, or record a short video of a flow with a visible cursor and click/zoom animations. Use when you need to SEE the UI — verifying a frontend change, checking a layout at phone/tablet/desktop widths, driving a multi-step flow and looking at each step, producing an image of a `mycelium` command's output for a doc or PR, or showing a flow in motion. Triggers on "screenshot", "show me the app", "what does it look like", "check the layout", "responsive", "capture the terminal", "record a video", "screen recording", "demo clip", "show it in motion".

mycelium-io 122 13 Updated 3w ago
GitHub

Install

npx skillscat add mycelium-io/mycelium/screenshot

Install via the SkillsCat registry.

SKILL.md

Screenshot the app or the CLI

shotkit/ is this repo's camera. It holds a browser open in a background
daemon, so the first shot costs ~2s and every later one ~150ms.

Run it from the repo root:

node shotkit/bin/shot.mjs <command> [flags]

The absolute PNG path is the only thing on stdout — read that file back to see
the result. Timings and warnings go to stderr.

First run on a machine

node shotkit/bin/shot.mjs doctor

It reports the browser, script(1), whether the frontend's deps are installed,
whether an app is already listening, and whether webfonts load here. Fix
anything it marks ✗ before capturing. Terminal and code cards need no app at
all.

If the webfont check warns, add --offline to every app capture and don't
publish shots taken on this machine — they will render in fallback fonts. A
capture that takes more than a few seconds prints the same hint.

Screenshot the app

# boot the mock frontend (no backend, SLIM or LLM needed) and shoot a route
node shotkit/bin/shot.mjs app /room/checkout --mock

# against an app you already have running
node shotkit/bin/shot.mjs app / --base-url http://localhost:3000

--mock boots pnpm dev:mock inside the daemon, so it stays warm across
shots — pass it on the first capture and omit it afterwards. An already-running
dev server is found automatically, whatever port it is on.

Add --offline when a capture takes more than a few seconds. The frontend
links Google Fonts; where those are unreachable, each navigation waits ~13s on
them. --offline resolves nothing but localhost and the app renders with
fallback fonts.

Check a layout across breakpoints

node shotkit/bin/shot.mjs app / --responsive --sheet --offline

Four frames — phone, tablet, laptop, wide — plus one contact sheet composing
them at their true relative widths. Read the sheet: it answers "is this
responsive" in a single look. --viewports phone,wide picks a subset;
--viewport 1280x800@2 takes an exact size.

Drive a flow, then look

For a state behind a click, either pass ordered steps to one capture:

node shotkit/bin/shot.mjs app /room/checkout --offline \
  --do click:Negotiate --do wait:.offer-grid

…or hold the page open and work against it, which is what you want when you
need to see each step before deciding the next:

node shotkit/bin/shot.mjs open /room/checkout --session r --offline
node shotkit/bin/shot.mjs do click:Negotiate --session r
node shotkit/bin/shot.mjs shoot --session r --name negotiate   # ~250ms
node shotkit/bin/shot.mjs close --session r

Anything without CSS punctuation is matched by accessible name, then visible
text — click:Negotiate, and phrases too: click:Install CLI is a button, not a
descendant selector. Words that are also tag names are no exception, so
click:table finds a button labeled "table" before it considers a <table>.
For a selector use #id, .class, role=button[name="Save"], text=Save, or
css= when it is only tag names and spaces. shot help shoot lists every verb.

Record a short video

When the thing to show is a flow rather than a state — a demo clip for a PR or
a doc, or checking that an interaction feels right:

node shotkit/bin/shot.mjs video /room/checkout --mock --offline \
  --do click:Negotiate --do wait:.offer-grid --auto-zoom

Same --do verbs as a screenshot. The recording adds what a still does not
need: the pointer travels to each target (moving the real mouse, so hover states
fire), a ring marks each click, and --auto-zoom pushes the camera in on what is
being pressed and back out after. zoom:<sel>, zoom:<sel>@2.2 and zoomout
place the camera by hand.

The output path on stdout is an .mp4 where the machine has a full ffmpeg, and
a .webm otherwise
— Playwright's bundled build is webm-only. shot doctor
says which. You cannot watch it: hand the path to the user, or pull a frame out
of it to look at. Keep takes short (a few actions); --max-seconds caps one.

--sound gives the take its clicks and keystrokes as sound (over --bed <file> if given), and shot sound <video> re-mixes one; the take writes
<video>.sounds.json either way. The product demo's sound is
node mycelium-promo/record.mjs, which adds the drone too.

Screenshot CLI output

Runs the command under a pty, so Rich keeps its colors and box drawing:

node shotkit/bin/shot.mjs term --cols 84 -- mycelium memory --help

# run one command, label it as another (the CLI often needs `uv run` locally)
node shotkit/bin/shot.mjs term --cwd mycelium-cli --command "mycelium doctor" \
  -- uv run mycelium doctor

Flags must come before the command; everything after the first plain word
belongs to the child. shot text <file> renders an ANSI log you already have,
and shot code <file> --range 40:80 makes a syntax-highlighted code card.

Framing for a PR or doc

node shotkit/bin/shot.mjs app /room/checkout --chrome --offline          # browser window frame
node shotkit/bin/shot.mjs app / --chrome --theme light --backdrop dusk
node shotkit/bin/shot.mjs app / --chrome --backdrop canvas --padding 90
node shotkit/bin/shot.mjs app / --demo --backdrop glass --offline       # tilted, over the docs' glass

--theme switches the app itself, not just the browser's media query.

--backdrop canvas is the desktop behind the window: the docs site's mycelial
network, the same one docs/banner.png is cut from (backdrop.canvas in
shotkit.config.json). --backdrop glass is the docs' glass droplets
(docs/glass.js), which move under a staged take. Give either padding to show,
and prefer a quiet backdrop (mycelium, ink, paper) when the screen itself
is busy.

Rules

  • Never commit anything from .shotkit/. It is gitignored scratch. The
    committed docs screenshots have their own pipeline — pnpm screenshots in
    mycelium-frontend/, publishing per screenshots/targets.ts. Run that, and
    commit its output, only when asked to update the docs assets.
  • Don't hand-roll Playwright for a screenshot. If shotkit is missing a
    capability, add it there; capture() in shotkit/src/api.mjs is importable.
    shotkit/ is vendored from github.com/juliarvalenti/shotkit: change it there,
    then scripts/sync-shotkit.sh brings it here (an edit made only here is
    overwritten on the next sync).
  • Leave the daemon running. It idles out after 15 minutes. shot stop only
    if you need a clean slate.