Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions docs/packages/cli.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ npx hyperframes <command>
- Preview compositions with live hot reload (`preview`)
- Render compositions to MP4 locally or in Docker (`render`)
- Lint compositions for structural issues (`lint`)
- Inspect rendered visual layout for text overflow and clipped containers (`inspect`)
- Capture key frames as PNG screenshots (`snapshot`)
- Check your environment for missing dependencies (`doctor`)

Expand Down Expand Up @@ -445,6 +446,47 @@ This is suppressed in CI environments, non-TTY shells, and when `HYPERFRAMES_NO_

The linter detects missing attributes, missing adapter libraries (GSAP, Lottie, Three.js), structural problems, and more. See [Common Mistakes](/guides/common-mistakes) for details on each rule.

### `inspect`

Inspect rendered visual layout across the composition timeline:

```bash
npx hyperframes inspect [dir]
npx hyperframes inspect [dir] --json
npx hyperframes inspect [dir] --samples 15
npx hyperframes inspect [dir] --at 1.5,4,7.25
```

```
◆ Inspecting layout for my-project (9 timeline samples)

✗ text_box_overflow t=3.25s #headline inside .bubble overflowed right 18px — "Quarterly plan"
Fix: Text is 418px x 42px inside 400px x 120px and overflows by up to 18px; widen the container to at least ~418px, or allow wrapping with max-width/fitTextFontSize.

◇ 1 error(s), 0 warning(s), 0 info(s)
```

`inspect` bundles the project, serves it locally, opens headless Chrome, seeks through the composition, and reports text or elements that escape their intended boxes. It is designed for agent workflows: each finding includes a schema version, timestamp or collapsed timestamp range, selector, nearest container selector, measured bounding boxes, overflow sides, and a fix hint.

| Flag | Description |
|------|-------------|
| `--json` | Output agent-readable findings with `schemaVersion`, `samples`, `issues`, bounding boxes, and summary counts |
| `--samples` | Number of midpoint samples across the composition duration (default: 9) |
| `--at` | Comma-separated timestamps in seconds for explicit hero-frame checks |
| `--tolerance` | Allowed pixel overflow before reporting an issue (default: 2) |
| `--timeout` | Ms to wait for runtime initialization (default: 5000) |
| `--collapse-static` | Collapse repeated static issues across samples (default: true) |
| `--max-issues` | Maximum findings to print or return after static collapse (default: 80) |
| `--strict` | Exit non-zero on warnings as well as errors |

Use `data-layout-allow-overflow` on an element or ancestor when overflow is intentional, such as a planned off-canvas entrance. Use `data-layout-ignore` for decorative elements that should not be audited.

`layout` remains available as a compatibility alias for the same visual inspection pass:

```bash
npx hyperframes layout [dir] --json
```

### `snapshot`

Capture key frames from a composition as PNG screenshots — verify visual output without a full render:
Expand Down
6 changes: 6 additions & 0 deletions packages/cli/scripts/build-copy.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ async function main() {
for (const sub of ["studio", "docs", "templates", "skills", "docker"]) {
mkdirSync(join(DIST, sub), { recursive: true });
}
mkdirSync(join(DIST, "commands"), { recursive: true });

const studioDist = resolve(CLI_ROOT, "..", "studio", "dist");
await waitForStudioDist(studioDist);
Expand All @@ -76,6 +77,11 @@ async function main() {
cpSync(dockerfile, join(DIST, "docker", "Dockerfile.render"));
}

const layoutAuditScript = join(CLI_ROOT, "src", "commands", "layout-audit.browser.js");
if (existsSync(layoutAuditScript)) {
cpSync(layoutAuditScript, join(DIST, "commands", "layout-audit.browser.js"));
}

copyMdFiles(join(CLI_ROOT, "src", "docs"), join(DIST, "docs"));

console.log("[build-copy] done");
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ const subCommands = {
publish: () => import("./commands/publish.js").then((m) => m.default),
render: () => import("./commands/render.js").then((m) => m.default),
lint: () => import("./commands/lint.js").then((m) => m.default),
inspect: () => import("./commands/inspect.js").then((m) => m.default),
layout: () => import("./commands/layout.js").then((m) => m.default),
info: () => import("./commands/info.js").then((m) => m.default),
compositions: () => import("./commands/compositions.js").then((m) => m.default),
benchmark: () => import("./commands/benchmark.js").then((m) => m.default),
Expand Down
12 changes: 12 additions & 0 deletions packages/cli/src/commands/inspect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { Example } from "./_examples.js";
import { createInspectCommand } from "./layout.js";

export const examples: Example[] = [
["Inspect visual layout across the current composition", "hyperframes inspect"],
["Inspect a specific project", "hyperframes inspect ./my-video"],
["Output agent-readable JSON", "hyperframes inspect --json"],
["Use explicit hero-frame timestamps", "hyperframes inspect --at 1.5,4.0,7.25"],
["Run the compatibility alias", "hyperframes layout --json"],
];

export default createInspectCommand("inspect");
Loading
Loading