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".
Instal·la
npx skillscat add mycelium-io/mycelium/screenshot Instal·la des del registre de SkillsCat.
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 doctorIt 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 --offlineFour 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 rAnything 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, soclick:table finds a button labeled "table" before it considers a <table>.
For a selector use #id, .class, role=button[name="Save"], text=Save, orcss= 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-zoomSame --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 isnode 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 doctorFlags 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 inshotkit.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 screenshotsinmycelium-frontend/, publishing perscreenshots/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()inshotkit/src/api.mjsis importable.shotkit/is vendored from github.com/juliarvalenti/shotkit: change it there,
thenscripts/sync-shotkit.shbrings it here (an edit made only here is
overwritten on the next sync). - Leave the daemon running. It idles out after 15 minutes.
shot stoponly
if you need a clean slate.