SkillLens: usage and maintenance
SkillLens turns any SKILL.md into an animated swimlane flowchart: cards are steps, diamonds are decisions, solid lines move forward, dashed lines loop back, glowing dots travel along the lines and the lit card is the current step. The UI and the fixed chart text come in English (default) and Chinese; "中 / EN" at the top right switches.
title: SkillLens
subtitle: SKILL.md in · auto-extracted · animated flowchart out
hero: SkillLens | import · extract · tweak · export
trigger start: Want to understand a skill [When] {bell}
read the workflow
check or present it
lane L1: Import [import] (green)
step open: Open SkillLens [start.bat] {play}
lists every local skill
redraws on every save
step add: Drop or paste [drop] {upload}
folders, .md files
or pasted text
lane L2: Extract [extract] (blue)
decide has: skillflow block? [skillflow?]
step auto: Heuristic extraction [auto] {sparkles}
sections → lanes
steps / decisions / loops
step check: Check against the source [review] {scan-eye}
click a card for its text
see where it connects
step tune: Tweak in Structure [edit] {pencil}
apply to redraw
copy as a code block
lane L3: Output [export] (purple)
step draw: Draw from the block [render] {layers}
lanes · cards · diamonds
dots flow along lines
step out: Export [export] {download} +end
HTML / SVG / PNG
record an mp4
flow:
start -> open -> add -> has
has -> auto : No
has -> draw : Yes
auto -> check -> tune -> draw -> out
check ~> auto : fix the source text
Open it
- Double-click
start.bat: starts a local server and opens the browser. The list holds the repo'sskills/andexamples/plus the local Claude user and plugin skills, and redraws within 2 seconds after a SKILL.md changes. Same asnpm start;npm run start:projectlists only the repo's own skills. - Open
index.htmldirectly: no server, but the list comes fromdata/skills.js, so runnpm run scanfirst. Video recording and auto-translation need the server. - Extra folders:
--root Name=<path>, or askillviz.config.jsonin the repo root:{"roots":[{"label":"Team skills","dir":"<path>"}]}.
Writing skills that chart well
The extraction rules live in src/extract.js. A SKILL.md written like this charts correctly without a skillflow block:
- Put the procedure under a heading such as
## Workflow/## Steps/## Process, as an ordered list or numbered###subsections; write each step as**Short title**: explanation. - Start a decision with "If …" / "Whether …";
If X, do Ybecomes a diamond with a Yes exit. - Write a router as a two-column table whose header says "State / Condition / If" on the left and "Action / Do / Route" on the right: it becomes a chain of first-match decisions.
- Write loops as "go back to step N until …".
- Mark optional steps with a leading
[If necessary]/[optional]; the card gets a dashed border. - Rules under
## Rules/## Notesbecome amber notes; material under## Referencebecomes an unconnected reference lane.
The skillflow block (exact control)
When a SKILL.md contains a ```skillflow block, SkillLens draws only that. The fastest way to write one: fix the auto-extracted chart in the Structure panel, click "Copy as code block" and paste it into the SKILL.md. Syntax:
| Line | Meaning |
|---|---|
title: subtitle: hero: title | subtitle footer: window: cols: 4 | page text and cards per row |
trigger id: Title [tag] {icon} | the trigger card at the top; indented lines below are its description |
lane id: Title [tag] (color kind) | a lane; colors green / blue / purple / teal / rose / amber / slate; kinds flow (default, chained) / ref (reference, unconnected) / bare (no frame) |
step id: Title [tag] {icon} +optional +end | a step card; +end is the end step (solid icon), +optional a dashed card |
decide id: Question? [subtitle] | a decision diamond |
note: text | a note inside the lane |
a -> b -> c : label under flow: | forward lines; ~> is a dashed loop; a -> "text" : Yes is an exit pointing at a short text |
Without flow:, the cards of non-ref lanes are chained in order. Icons are Lucide names, listed in src/icons.js; to add one, copy its SVG body from lucide-static.
Changing SkillLens
- Layers:
markdown.jsparses →extract.js/dsl.jsbuild the structure →layout.jsplaces cards and routes lines →render.jsdraws the SVG and plays it →app.jsis the UI. All UI and chart strings live ini18n.js; add every key in bothenandzh. - The page must open by double-click, so it uses plain
<script>tags, no ES modules. Each script is written asSV.mod.name = function (SV) {…}so the standalone export can inline the code withtoString(). - Every frame must be a pure function of time t (no CSS animation,
Math.randomor wall clock), or frame-by-frame video recording breaks. - Themes: Blueprint (default), Midnight and Glass. Chart colors are in
THEMESinrender.js, UI colors in the CSS variables at the top ofstyle.css; change both together. Blueprint-only details (grid, rulers, corner ticks, card numbers, amber active step) are behindP.blueprint. - Fonts: Noto Sans SC (Chinese), Inter (Latin), JetBrains Mono (tags and paths) from Google Fonts, falling back to system fonts offline. Layout measures text with a canvas, so it must wait for fonts:
app.jsclears the measure cache and redraws onloadingdone, and record mode plus the standalone export calldocument.fonts.loadfor the chart's text first. Keep the font link inindex.html,FONT/MONOinlayout.jsand the link in the standalone template in sync. - Auto-translation:
scripts/lib/translate.mjs(server,/api/translate) anduseTranslationinsrc/app.js(which strings on the chart get translated). Only chart text and opened source text are translated; tags, file names, paths and Yes / No are kept. Backend order: the Anthropic SDK when an API key is set and@anthropic-ai/sdkis installed, else the local Claude Code CLI (on Windows callnode_modules/@anthropic-ai/claude-code/bin/claude.exedirectly to avoid.cmdquoting). The cache key islang + \u0001 + texton both sides. - Check changes in a headless browser:
npm run scan, thennode scripts/record.mjs <skill> --seconds 3, or screenshot throughscripts/lib/cdp.mjs. For a regression run, push every skill throughSV.extract→SV.layout→SV.render.toSVGand make sure nothing throws and no text overflows its card. - Recording needs a local Chrome / Edge and ffmpeg; set
SV_CHROME/SV_FFMPEGif they are not found. - README hero media:
docs/promo.webp(the animation shown inline) links to the rawdocs/promo.mp4(the full video with sound). GitHub never plays a repo MP4: not inline in the README and not in the file view, whatever its size, so the raw link downloads it; an inline player needs the video uploaded through the github.com editor (auser-attachmentsURL). Use animated WebP, not GIF: on the dark Blueprint gradients a 30 s GIF is over 20 MB, while WebP stays under 8 MB with cleaner color. From a 1080p master:ffmpeg -i master.mp4 -vf "fps=15,scale=960:-1:flags=lanczos" -c:v libwebp -quality 70 -compression_level 6 -loop 0 -an docs/promo.webpandffmpeg -i master.mp4 -c:v libx264 -preset slow -crf 23 -pix_fmt yuv420p -c:a aac -b:a 160k -movflags +faststart docs/promo.mp4.