Skip to content

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Slop-Disclaimer

I was just to lazy to do it my self, so I let my Codex agent to build it for my Hermes agent, so I can capture walk-throughs remotely.

It works fine tbh.

Use it as you wish. But change your design template before installing it. There is no contribution expected. And of course this readme was not meant to be read by humans, let your agent read and explain it for you.

HTML Renderer

Reusable AI-agent skill for turning local HTML pages or browser apps into reliable rendered media, especially short MP4 walkthroughs, looped clips by default, and linear videos when requested.

The skill is built around a bundled Node renderer instead of ad hoc Playwright scripts. The intended workflow is:

  1. Identify the app entry point, state seeding needs, selectors for each interaction, and assertions that prove each step completed.
  2. Write a JSON capture config from references/capture-config.md, usually in the target project under tools/.
  3. Run scripts/render-html-video.cjs with that config.
  4. Verify the exported MP4 metadata and preview frames before considering the render complete.

How The Renderer Works

render-html-video.cjs accepts one argument:

node scripts/render-html-video.cjs path/to/config.json

At runtime it:

  1. Resolves the config directory, static root, entry, and output.
  2. Installs or resolves playwright and ffmpeg-static in a temp dependency directory if local modules are unavailable.
  3. Generates a temporary stage HTML file containing:
    • a branded background and optional title
    • a 16:9 iframe for the app
    • semantic default, pointer, and text cursors with click feedback
    • helper functions for cursor movement, clicks, waits, and iframe assertions
  4. Starts a local static server on 127.0.0.1 and injects an early inline app background style into served HTML pages.
  5. Opens the stage in headless Chromium at the configured capture size.
  6. Seeds localStorage before loading the app iframe.
  7. Waits for iframe load plus any configured initial selector/text assertion before revealing the cursor.
  8. Trims the final MP4 to begin after the app-ready paint by default, then holds for the configured pre-roll before running declarative actions such as click, setCursor, waitForSelector, waitForText, waitForUrl, and navigateFrame.
  9. In looped mode, returns the cursor to the configured loop point before ending the recording.
  10. Records a source WebM using Playwright video recording.
  11. Transcodes the recording to MP4 with H.264, yuv420p, Lanczos scaling, configured FPS, and +faststart.
  12. Deletes the temporary WebM and generated stage file unless keepIntermediate is enabled.

Config Basics

A minimal config looks like this:

{
  "root": ".",
  "entry": "/index.html",
  "output": "renders/app-walkthrough.mp4",
  "loop": true,
  "title": "Product",
  "appBackground": "#111211",
  "initialWaitForSelector": ".tab[data-tab='home']",
  "initialCursorSelector": ".tab[data-tab='home']",
  "preRollMs": 500,
  "actions": [
    { "type": "click", "selector": ".tab[data-tab='home']", "wait": 700 },
    { "type": "click", "selector": ".tab[data-tab='settings']", "waitForSelector": ".settings-panel" }
  ]
}

Important fields:

  • root: Static web root. Relative paths resolve from the config file directory.
  • entry: URL path loaded inside the staged iframe.
  • output: Final MP4 path. Relative paths resolve from root.
  • loop: Defaults to true. Set false for a normal linear walkthrough ending.
  • storage: Optional localStorage seed entries using value, json, jsonFile, or textFile.
  • appBackground: Background shown behind and inside the iframe before the app paints, injected into served HTML pages as an early inline style, defaulting to dark #111211.
  • initialWaitForSelector / initialWaitForText: Optional required readiness assertions after iframe load and before cursor reveal/actions.
  • preRollMs: Optional hold after readiness and cursor placement before actions begin, defaulting to 500. initialWait remains supported as a legacy alias.
  • trimBeforeReady: Optional boolean, defaulting to true. Removes frames before the app-ready paint from the final MP4 while keeping preRollMs.
  • trimSafetyMs: Optional milliseconds to back up the trim point, defaulting to 0.
  • initialCursorSelector: Initial cursor position. For loops, this is also the default final cursor return point.
  • loopCursorSelector: Optional final cursor return point for looped output. Defaults to initialCursorSelector, then stage center.
  • loopHold: Optional milliseconds to hold after the loop cursor return, defaulting to 500.
  • capture: Recording size, defaulting to 3840x2160.
  • outputSize: Delivery size, defaulting to 1920x1080.
  • fps: Output frame rate, defaulting to 30.
  • stage: Optional visual styling for title, background, frame, zoom, and glow.
  • actions: Ordered declarative interaction list.

See references/capture-config.md for the complete schema and examples.

Reliability Notes

  • Record larger than the final delivery size, then downscale for sharper text.
  • Seed app state before iframe load rather than relying on manual setup.
  • Keep the app frame dark before load with appBackground or stage.appBackground; the renderer injects this into served HTML pages and masks the frame until ready.
  • Preserve the intended title font. Leave the default JetBrains Mono stage.titleFontUrl and matching stage.titleFontFamily in place unless the user asks for a different font; use "titleFontUrl": false only for explicit offline/no-network rendering.
  • The renderer chooses the pointer cursor for scripted actions, the text cursor for editable targets, and the default cursor elsewhere.
  • Require an initial readiness assertion with initialWaitForSelector or initialWaitForText before the first visible cursor motion.
  • Leave trimBeforeReady enabled unless you intentionally need to show the app loading sequence.
  • Use assertions after interactions: waitForSelector, waitForText, or waitForUrlContains.
  • Use fallbackNavigate only after a visible click when app routing is flaky.
  • Configs are looped by default. Use "loop": false when the requested output should finish on a distinct final state.
  • For looped clips, make the first visible app state match the final app state. The renderer returns the cursor to loopCursorSelector, initialCursorSelector, or stage center before ending.
  • Prefer bundled ffmpeg-static or explicit FFMPEG_PATH; do not rely on system ffmpeg.
  • Do not keep raw recordings or preview images unless they are needed for debugging or requested.

Verification

Before publishing a render, check:

  • The MP4 exists and is meaningfully sized.
  • The codec is H.264 in an MP4 container, not a renamed WebM.
  • Resolution, aspect ratio, and FPS match the request.
  • Preview frames show the intended staging and important UI destinations.
  • For loops, first and last frames align visually, including cursor position. For "loop": false, the last frame should show the intended linear ending.

Useful commands:

ffmpeg -hide_banner -i renders/app-walkthrough.mp4
ffmpeg -hide_banner -ss 00:00:00.5 -i renders/app-walkthrough.mp4 -frames:v 1 -update 1 renders/first.png
ffmpeg -hide_banner -ss 00:00:13.0 -i renders/app-walkthrough.mp4 -frames:v 1 -update 1 renders/last.png
node scripts/verify-no-white-start.cjs

Before publishing the skill itself, run the cross-harness compatibility proof:

node scripts/verify-harness-compat.cjs

The proof validates the portable skill structure, checks OpenAI/Codex metadata, stages the skill in temporary Codex and Hermes homes, and validates a generated Claude plugin wrapper with claude plugin validate. It does not make model/API calls.

Requirements

  • Node.js
  • npm network access on first use, unless playwright and ffmpeg-static are already locally available
  • A local filesystem
  • Chromium installed by Playwright, which the script attempts to install automatically

Optional environment variables:

  • HTML_RENDERER_DEPS_DIR: Override the temp dependency install directory.
  • FFMPEG_PATH: Use a specific ffmpeg binary.

License

MIT. This skill is free to use, copy, edit, and redistribute.

About

Reusable AI-agent skill for rendering local HTML apps into MP4 walkthrough media

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages