Skip to content
Closed
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
5 changes: 5 additions & 0 deletions .fallowrc.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@
"registry/**",
"examples/**",
".github/workflows/fixtures/**",
// Picker assets — vendored slide templates (template.html, summary.html,
// deck-stage.js shims, styles.css) and the picker shell (design-picker.html).
// Loaded at runtime by iframes, not imported. Built/served by skills scripts.
"skills/hyperframes/templates/presentations/**",
"skills/hyperframes/templates/design-picker.html",
],
"ignoreExports": [
// CLI command files: every command exports a const `examples` per the
Expand Down
17 changes: 8 additions & 9 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ coverage/

# Producer regression test failures (generated debugging artifacts)
packages/producer/tests/*/failures/
packages/producer/tests/distributed/*/failures/
packages/producer/tests/parity/fixtures/hyperframe.runtime.iife.js

# Player perf test results (generated each run, attached as CI artifact)
Expand All @@ -42,7 +41,6 @@ packages/player/tests/perf/results/
output/
renders/
!packages/producer/tests/*/output/
!packages/producer/tests/distributed/*/output/

# Composition source media (large binaries)
compositions/**/*.mp4
Expand All @@ -67,12 +65,7 @@ packages/producer/src/services/fontData.generated.ts
# Local proof / test artifacts
qa-artifacts/
my-video/
examples/*
# Tracked OSS examples — negations override the blanket `examples/*` ignore.
!examples/aws-lambda
!examples/aws-lambda/**
!examples/k8s-jobs
!examples/k8s-jobs/**
examples/
packages/studio/data/
.desloppify/
.worktrees/
Expand Down Expand Up @@ -110,4 +103,10 @@ claude-design-hyperframes-video/
.claude/worktrees/
.claude/
docs/superpowers/
.worktrees

# hyperframes pick — generated picker + per-project picker data
.hyperframes/

# hyperframes pick — generated user-design template (created when DESIGN.html exists)
/templates/

116 changes: 23 additions & 93 deletions docs/packages/cli.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,29 @@ This is suppressed in CI environments, non-TTY shells, and when `HYPERFRAMES_NO_

</Tab>
<Tab title="Preview">
### `pick`

<Note>
Experimental. Hidden behind a feature flag. Set `HYPERFRAMES_DESIGN_PICKER=1` (or `true` / `on` / `yes`) to enable. Always enabled when running from the monorepo for contributors.
</Note>

Open the design picker in your browser to choose a template and create a `design.md`:

```bash
HYPERFRAMES_DESIGN_PICKER=1 npx hyperframes pick
HYPERFRAMES_DESIGN_PICKER=1 npx hyperframes pick --port 8723
HYPERFRAMES_DESIGN_PICKER=1 npx hyperframes pick --build-only
```

| Flag | Description |
|------|-------------|
| `--port` | Port to serve the picker on (default: 8723) |
| `--build-only` | Build the picker HTML without serving it |

Builds `.hyperframes/pick-design.html` from the installed skill template, starts a local HTTP server, and opens the picker. Requires the HyperFrames skills (`npx hyperframes skills`) and `python3` installed.

The picker walks you through palette, typography, corners, density, depth, motion, and an optional shader background. Export the resulting `design.md` and paste it into your project root.

### `preview`

Start a live preview server with hot reload:
Expand Down Expand Up @@ -860,99 +883,6 @@ This is suppressed in CI environments, non-TTY shells, and when `HYPERFRAMES_NO_
</Tab>
</Tabs>

## hyperframes lambda

Deploy HyperFrames distributed rendering to AWS Lambda and drive renders from your laptop or CI.

The `hyperframes lambda` command group wraps the `@hyperframes/aws-lambda` SDK plus AWS SAM so an end-to-end render is three commands:

```bash
hyperframes lambda deploy
hyperframes lambda render ./my-project --width 1920 --height 1080 --wait
hyperframes lambda destroy # when you're done
```

### Prerequisites

- AWS credentials configured (env vars, `~/.aws/credentials`, SSO, or IMDS).
- [AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html) on `PATH`.
- `bun` on `PATH` (used to build the Lambda handler ZIP).

### Subcommands

#### `lambda deploy`

Builds `packages/aws-lambda/dist/handler.zip` and SAM-deploys the stack at `examples/aws-lambda/template.yaml`. On success, writes `<cwd>/.hyperframes/lambda-stack-<stackName>.json` so the other subcommands don't need to re-derive the bucket / state-machine ARN.

```bash
hyperframes lambda deploy \
--stack-name=hyperframes-prod \
--region=us-east-1 \
--concurrency=8 \
--memory=10240
```

Idempotent — re-running on the same `--stack-name` resolves to a no-op when nothing changed.

#### `lambda sites create <projectDir>`

Tars + uploads `<projectDir>` to S3 with a content-addressed key. Returns a `siteId` you can reuse across multiple renders so a re-render of the same tree skips the upload.

```bash
hyperframes lambda sites create ./my-project
# → siteId: abc1234deadbeef0 (stable across re-runs of the same tree)

hyperframes lambda render ./my-project --site-id=abc1234deadbeef0 --width 1920 --height 1080
```

#### `lambda render <projectDir>`

Starts a Step Functions execution. Returns immediately with a `renderId` (use `lambda progress` to poll) unless `--wait` is set, in which case the CLI blocks until the render finishes and streams per-chunk progress lines.

```bash
hyperframes lambda render ./my-project \
--width=1920 --height=1080 --fps=30 --format=mp4 \
--chunk-size=240 --max-parallel-chunks=16 \
--wait
```

`--json` swaps the human-readable output for a machine-parseable JSON snapshot.

#### `lambda progress <renderId | executionArn>`

Prints one progress snapshot — overall percent, frames rendered, Lambda invocations, accrued cost, and any errors. Accepts either a bare `renderId` (resolved against the stack's state-machine ARN) or a full SFN execution ARN.

```bash
hyperframes lambda progress hf-render-abcd1234
```

#### `lambda destroy`

Calls `sam delete --no-prompts` and drops the local state file. The render S3 bucket is configured with CloudFormation `Retain` so it survives destruction — empty and delete it via the AWS console / CLI if you want the storage back.

#### `lambda policies role | user | validate`

Print or validate the minimum IAM policy the CLI needs to deploy / invoke / destroy the stack.

```bash
# Print an inline-policy doc you can attach to an IAM user that runs the CLI.
hyperframes lambda policies user

# Print { TrustRelationship, InlinePolicy } for an IAM role (default: cloudformation principal).
hyperframes lambda policies role --principal=cloudformation

# Validate a checked-in policy still covers the CLI's needs.
hyperframes lambda policies validate ./infra/iam/hyperframes-deploy.json
```

`validate` reads the JSON doc and checks the union of its `Effect: Allow` actions against the CLI's required action set, expanding `s3:*` / `s3:Get*` / `*` wildcards. Missing actions print to stderr and the command exits non-zero — wire it into CI to catch drift before the next deploy fails.

The actions list is deliberately broad (`Resource: "*"`) because CloudFormation creates new function / state-machine / bucket ARNs on every adopter's first deploy. Adopters with stricter security postures should narrow `Resource` to the deployed ARNs after the first successful run.

### State files

`hyperframes lambda` keeps per-stack metadata under `<cwd>/.hyperframes/lambda-stack-<name>.json` so the verbs don't need to call `describe-stacks` every time. Commit the file to a repo or `.gitignore` it depending on your workflow — it contains the bucket name, state-machine ARN, and region, none of which are secrets but all of which are AWS-account-identifying.

## hyperframes.json

`hyperframes init` writes a `hyperframes.json` file at the root of every new project. `hyperframes add` reads it to know which registry to pull items from and where to drop them. Edit the file (or delete it to fall back to defaults) to reshape your project layout or point at a custom registry.
Expand Down
32 changes: 1 addition & 31 deletions packages/cli/src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,5 @@
#!/usr/bin/env node

// ── Worker entry path bootstrap (must run before any producer/engine load) ──
// The hf#677 worker_threads pools (`pngDecodeBlitWorkerPool`,
// `shaderTransitionWorkerPool`) live in the producer package and try to
// resolve their worker entry by probing for sibling `.js` files next to
// `import.meta.url`. When this CLI is bundled by tsup, the producer code is
// inlined into `cli.js`, but `import.meta.url` resolves to the producer's
// own dist path (NOT cli.js) on some module-graph layouts — so the sibling
// probe lands in a directory that does not contain the bundled workers.
// We emit the worker entries next to cli.js (see tsup.config.ts) and tell
// the pools where to find them via the published env-var overrides. The
// pools have an explicit `workerEntryPath` factory option as the canonical
// API, but setting the env vars here covers every call site without having
// to thread the path through the renderOrchestrator → captureHdrStage →
// captureHdrHybridLoop chain.
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { existsSync } from "node:fs";

(() => {
const here = dirname(fileURLToPath(import.meta.url));
const shader = join(here, "shaderTransitionWorker.js");
const png = join(here, "pngDecodeBlitWorker.js");
if (!process.env.HF_SHADER_WORKER_ENTRY && existsSync(shader)) {
process.env.HF_SHADER_WORKER_ENTRY = shader;
}
if (!process.env.HF_PNG_DECODE_BLIT_WORKER_ENTRY && existsSync(png)) {
process.env.HF_PNG_DECODE_BLIT_WORKER_ENTRY = png;
}
})();

// ── Fast-path exits ─────────────────────────────────────────────────────────
// Check --version before importing anything heavy. This makes
// `hyperframes --version` near-instant (~10ms vs ~80ms).
Expand Down Expand Up @@ -65,6 +35,7 @@ const subCommands = {
add: () => import("./commands/add.js").then((m) => m.default),
catalog: () => import("./commands/catalog.js").then((m) => m.default),
play: () => import("./commands/play.js").then((m) => m.default),
pick: () => import("./commands/pick.js").then((m) => m.default),
preview: () => import("./commands/preview.js").then((m) => m.default),
publish: () => import("./commands/publish.js").then((m) => m.default),
render: () => import("./commands/render.js").then((m) => m.default),
Expand All @@ -86,7 +57,6 @@ const subCommands = {
validate: () => import("./commands/validate.js").then((m) => m.default),
snapshot: () => import("./commands/snapshot.js").then((m) => m.default),
capture: () => import("./commands/capture.js").then((m) => m.default),
lambda: () => import("./commands/lambda.js").then((m) => m.default),
};

const main = defineCommand({
Expand Down
Loading
Loading