Web Visualizer
June 4, 2026 · View on GitHub
Generate a self-contained static site that lets anyone browse a GRAIL motion library in a web browser — hover to play the MP4 preview, per-motion metadata panel, client-side name filter, dark/light mode.
No server-side code, no WebGL, no shader setup. It's just HTML + JS + a
manifest JSON alongside kinematic-replay MP4s in <motion_lib>/vis/ and
meta pickles from retarget / data-export.
Generate
Render kinematic-replay MP4s into <motion_lib>/vis/ first (if not already
present):
conda activate sonic # or GRAIL_SONIC_ENV override
bash grail/visualization/scripts/visualize.sh data/pickup_table
Then build the static site:
python -m grail.web_visualizer.generate_manifest \
--motion_lib data/pickup_table \
--output out/viz/pickup_table
Outputs:
out/viz/pickup_table/
├── index.html
├── main.js
├── style.css
├── manifest.json # 41 motions, 41 with video (example)
└── vis/ # relative symlinks into motion_lib/vis/
├── pickup_table__apple_0__000.mp4
└── ...
The vis/ entries are relative symlinks by default — fast + space-efficient.
Pass --copy_videos if you need a self-contained directory (e.g. publishing
to S3).
Serve
Any static-file host works. For a quick local check:
cd out/viz/pickup_table
python -m http.server 8000
# open http://localhost:8000/
To publish on GitHub Pages, host from a dedicated branch or drop the output into a path the Pages workflow picks up.
What the manifest contains
A stable-allowlist projection from the motion library:
| Field | Source | Notes |
|---|---|---|
name | filename stem of robot/*.pkl | |
frames | robot pkl (joint_pos / body_pos) | number of frames |
video | vis/*.mp4 | omitted if video missing |
meta.* | meta/*.pkl (allowlisted keys) | object_name, table_{pos,quat,size} |
Only the allowlisted meta keys are copied into the manifest so the schema
stays stable even as meta/*.pkl grows new fields.
What the viewer does
- Renders a grid of cards, responsive down to mobile width.
- Hover-to-play / mouseleave-to-pause. No autoplay, no audio.
- Type-to-filter:
searchbox performs a case-insensitive substring match against motion names (client-side, instant). - Dark mode honours
prefers-color-scheme; no theme switch widget.