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
28 changes: 28 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ packages/
cli/ → hyperframes CLI (create, preview, lint, render)
core/ → Types, parsers, generators, linter, runtime, frame adapters
engine/ → Seekable page-to-video capture engine (Puppeteer + FFmpeg)
player/ → Embeddable <hyperframes-player> web component
producer/ → Full rendering pipeline (capture + encode + audio mix)
studio/ → Browser-based composition editor UI
```
Expand Down Expand Up @@ -94,6 +95,7 @@ When adding a new CLI command:
## Key Concepts

- **Compositions** are HTML files with `data-*` attributes defining timeline, tracks, and media
- **Clips** can be animated directly with GSAP. The only restriction: don't animate `visibility` or `display` on clip elements — the runtime manages those.
- **Frame Adapters** bridge animation runtimes (GSAP, Lottie, CSS) to the capture engine
- **Producer** orchestrates capture → encode → audio mix into final MP4
- **BeginFrame rendering** uses `HeadlessExperimental.beginFrame` for deterministic frame capture
Expand Down Expand Up @@ -185,3 +187,29 @@ Use `npx hyperframes tts --list` for the full set, or pass any valid Kokoro voic

- Python 3.8+ (auto-installs `kokoro-onnx` package on first run)
- Model downloads automatically on first use (~311 MB model + ~27 MB voices, cached in `~/.cache/hyperframes/tts/`)

## Embeddable Player

The `@hyperframes/player` package provides a `<hyperframes-player>` web component for embedding
compositions in any web page. Zero dependencies, works with any framework.

### Quick reference

```html
<!-- Load the player (CDN or npm) -->
<script src="https://cdn.jsdelivr.net/npm/@hyperframes/player"></script>

<!-- Embed a composition -->
<hyperframes-player src="./my-composition/index.html" controls></hyperframes-player>
```

### JavaScript API

```js
const player = document.querySelector("hyperframes-player");
player.play();
player.pause();
player.seek(2.5);
console.log(player.currentTime, player.duration, player.paused);
player.addEventListener("ready", (e) => console.log("Duration:", e.detail.duration));
```
1 change: 1 addition & 0 deletions Dockerfile.test
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ ENV PATH="/root/.bun/bin:$PATH"
COPY package.json bun.lock ./
COPY packages/core/package.json packages/core/package.json
COPY packages/engine/package.json packages/engine/package.json
COPY packages/player/package.json packages/player/package.json
COPY packages/producer/package.json packages/producer/package.json
COPY packages/cli/package.json packages/cli/package.json
COPY packages/studio/package.json packages/studio/package.json
Expand Down
21 changes: 16 additions & 5 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions docs/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"pages": [
"packages/core",
"packages/engine",
"packages/player",
"packages/producer",
"packages/studio",
"packages/cli"
Expand Down
175 changes: 175 additions & 0 deletions docs/packages/player.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
---
title: "@hyperframes/player"
description: "Embeddable web component for playing HyperFrames compositions in any web page."
---

The player package provides a `<hyperframes-player>` custom element that embeds a HyperFrames composition anywhere — in any framework or plain HTML. Zero dependencies, 3KB gzipped.

```bash
npm install @hyperframes/player
```

## When to Use

**Use `@hyperframes/player` when you need to:**
- Embed a rendered composition in a website, dashboard, or app
- Add a video-like player to a landing page or product demo
- Show compositions in documentation or blog posts

**Use a different package if you want to:**
- Edit compositions interactively — use the [studio](/packages/studio)
- Preview during development — use the [CLI](/packages/cli) (`npx hyperframes preview`)
- Render to MP4 — use the [CLI](/packages/cli) or [producer](/packages/producer)

## Quick Start

### Via CDN

```html
<script src="https://cdn.jsdelivr.net/npm/@hyperframes/player"></script>

<hyperframes-player
src="./my-composition/index.html"
controls
autoplay
muted
style="width: 100%; max-width: 800px; aspect-ratio: 16/9"
></hyperframes-player>
```

### Via npm

```js
import '@hyperframes/player';
```

```html
<hyperframes-player src="/compositions/intro.html" controls></hyperframes-player>
```

## HTML Attributes

| Attribute | Type | Default | Description |
|-----------|------|---------|-------------|
| `src` | string | required | URL or relative path to composition HTML |
| `width` | number | 1920 | Composition width in pixels |
| `height` | number | 1080 | Composition height in pixels |
| `controls` | boolean | false | Show playback controls overlay |
| `autoplay` | boolean | false | Start playing on load |
| `loop` | boolean | false | Loop playback |
| `muted` | boolean | true | Mute audio (required for autoplay in most browsers) |
| `poster` | string | — | Image URL to show before first play |
| `playback-rate` | number | 1 | Playback speed multiplier |

## JavaScript API

The player mirrors the native `<video>` element API:

```js
const player = document.querySelector('hyperframes-player');

// Playback
player.play();
player.pause();
player.seek(2.5); // seek to 2.5 seconds

// Properties
player.currentTime; // number — current position in seconds
player.currentTime = 5; // seek to 5 seconds
player.duration; // number — total duration
player.paused; // boolean
player.ready; // boolean — true after composition loads
player.playbackRate; // number — get/set speed
player.muted; // boolean — get/set mute
player.loop; // boolean — get/set loop
```

## Events

```js
const player = document.querySelector('hyperframes-player');

player.addEventListener('ready', (e) => {
console.log('Duration:', e.detail.duration);
});

player.addEventListener('timeupdate', (e) => {
console.log('Time:', e.detail.currentTime);
});

player.addEventListener('play', () => console.log('Playing'));
player.addEventListener('pause', () => console.log('Paused'));
player.addEventListener('ended', () => console.log('Ended'));
player.addEventListener('error', (e) => console.error(e.detail.message));
```

| Event | Detail | Description |
|-------|--------|-------------|
| `ready` | `{ duration }` | Composition loaded and timeline discovered |
| `timeupdate` | `{ currentTime }` | Fires during playback (~30fps) |
| `play` | — | Playback started |
| `pause` | — | Playback paused |
| `ended` | — | Playback reached end |
| `error` | `{ message }` | Load or runtime error |

## Framework Examples

### React

```jsx
import '@hyperframes/player';

function VideoPreview({ src }) {
return (
<hyperframes-player
src={src}
controls
style={{ width: '100%', maxWidth: 800 }}
/>
);
}
```

### Vue

```vue
<template>
<hyperframes-player :src="compositionUrl" controls />
</template>

<script setup>
import '@hyperframes/player';
const compositionUrl = './compositions/intro.html';
</script>
```

### Programmatic

```js
import '@hyperframes/player';

const player = document.createElement('hyperframes-player');
player.src = './my-composition/index.html';
player.controls = true;
player.addEventListener('ready', () => player.play());
document.getElementById('player-container').appendChild(player);
```

## Architecture

The player uses an iframe inside a Shadow DOM container. This provides:

- **Isolation** — composition CSS/JS can't leak into or conflict with your page
- **Security** — iframe sandbox restricts composition capabilities
- **Scaling** — auto-scales the composition to fit the player's container via CSS transforms

The player communicates with the composition via the HyperFrames runtime bridge protocol (`postMessage`). Existing compositions work without modification.

## Controls

When the `controls` attribute is present, a minimal overlay appears at the bottom:

- **Play/Pause** button (left)
- **Scrub bar** with drag support (mouse + touch)
- **Time display** showing current / total duration (right)
- Auto-hides after 3 seconds of inactivity, reappears on hover
1 change: 1 addition & 0 deletions packages/cli/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const isHelp = process.argv.includes("--help") || process.argv.includes("-h");

const subCommands = {
init: () => import("./commands/init.js").then((m) => m.default),
play: () => import("./commands/play.js").then((m) => m.default),
preview: () => import("./commands/preview.js").then((m) => m.default),
render: () => import("./commands/render.js").then((m) => m.default),
lint: () => import("./commands/lint.js").then((m) => m.default),
Expand Down
Loading
Loading