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
3 changes: 3 additions & 0 deletions docs/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,9 @@
"group": "Packages",
"pages": [
"packages/core",
"packages/parsers",
"packages/lint",
"packages/studio-server",
"packages/sdk",
"packages/engine",
"packages/player",
Expand Down
20 changes: 17 additions & 3 deletions docs/packages/core.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ const result = validateCompositionHtml(html);

### GSAP Script Parsing

<Info>
The GSAP + HTML parsing layer now lives in its own standalone package, [`@hyperframes/parsers`](/packages/parsers). Core re-exports the API below for back-compat; import from `@hyperframes/parsers` directly in new code.
</Info>

```typescript
import {
parseGsapScript,
Expand Down Expand Up @@ -243,6 +247,10 @@ const styles = getStageStyles('portrait');

## Linter

<Info>
The composition linter now lives in its own package, [`@hyperframes/lint`](/packages/lint) — install it directly to lint a project or HTML string from Node without the CLI. `@hyperframes/core/lint` remains a back-compat re-export.
</Info>

The composition linter checks for structural issues that would cause rendering failures or unexpected behavior. You can run it from the CLI with `npx hyperframes lint`, or call it programmatically:

```typescript
Expand Down Expand Up @@ -431,6 +439,15 @@ import type {
## Related Packages

<CardGroup cols={2}>
<Card title="@hyperframes/parsers" icon="code" href="/packages/parsers">
The standalone GSAP + HTML parsing layer extracted from core.
</Card>
<Card title="@hyperframes/lint" icon="circle-check" href="/packages/lint">
The composition linter as a standalone library.
</Card>
<Card title="@hyperframes/studio-server" icon="server" href="/packages/studio-server">
The mountable studio preview/editor backend.
</Card>
<Card title="CLI" icon="terminal" href="/packages/cli">
The easiest way to create, preview, lint, and render compositions.
</Card>
Expand All @@ -440,7 +457,4 @@ import type {
<Card title="Producer" icon="film" href="/packages/producer">
Full rendering pipeline built on top of core and engine.
</Card>
<Card title="Studio" icon="palette" href="/packages/studio">
Visual composition editor that embeds the core runtime for preview.
</Card>
</CardGroup>
112 changes: 112 additions & 0 deletions docs/packages/lint.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
---
title: "@hyperframes/lint"
description: "The composition linter as a standalone library — lint a directory or a single HTML file without the CLI."
---

The lint package is the composition linter extracted from core into a dedicated, independently-installable package. It's the **single source of truth** for linting: both the CLI's `hyperframes lint` command and the render-time render-gate consume the same rule engine from here.

```bash
npm install @hyperframes/lint
```

## When to Use

<Tip>
This package is the payoff of running validation **as a library** instead of shelling out to the CLI. A Node app (an agent harness, a CI step, an editor plugin) can `import { lintProject } from '@hyperframes/lint'` and lint a composition directory directly — no `npx hyperframes lint` subprocess, no stdout parsing.
</Tip>

**Use `@hyperframes/lint` when you need to:**
- Lint a composition project (an index + sub-compositions) from Node
- Lint a single HTML string programmatically
- Gate a render on lint findings (`shouldBlockRender`)
- Surface lint findings in your own UI or CI annotations

<Info>
`@hyperframes/core/lint` still resolves (via a back-compat re-export stub), so existing imports keep working. New code should import from `@hyperframes/lint` directly.
</Info>

## Package Exports

The lint package has a single entry point:

```typescript
import {
lintHyperframeHtml,
lintMediaUrls,
lintProject,
shouldBlockRender,
} from '@hyperframes/lint';
import type {
HyperframeLintResult,
HyperframeLintFinding,
HyperframeLintSeverity, // "error" | "warning"
HyperframeLinterOptions,
ProjectLintResult,
} from '@hyperframes/lint';
```

## Linting a Single Composition

```typescript
import { lintHyperframeHtml, lintMediaUrls } from '@hyperframes/lint';

const result = lintHyperframeHtml(html, { filePath: 'index.html' });
// result.ok, result.errorCount, result.warningCount, result.findings

for (const finding of result.findings) {
console.log(finding.severity, finding.code, finding.message);
// finding.file, finding.selector, finding.elementId, finding.fixHint, finding.snippet
}

// Additional media URL validation
const mediaFindings = lintMediaUrls(result.findings);
```

## Linting a Project

`lintProject` walks a composition directory — the index plus any sub-compositions — and returns aggregated findings. It takes a **directory path string**, so it's callable from any Node context with nothing but a path:

```typescript
import { lintProject, shouldBlockRender } from '@hyperframes/lint';
import type { ProjectLintResult } from '@hyperframes/lint';

const result: ProjectLintResult = await lintProject('./my-composition');
// result.totalErrors, result.totalWarnings, result.results[]
// each result entry: { file, result: HyperframeLintResult }

if (shouldBlockRender(result)) {
throw new Error(`Lint found ${result.totalErrors} blocking error(s)`);
}
```

## What the Linter Catches

Detected issues include:

- Missing timeline registration (`window.__timelines`)
- Unmuted video elements (causes autoplay failures)
- Missing `class="clip"` on timed visible elements
- Deprecated attribute names
- Missing composition dimensions (`data-width`, `data-height`)
- Invalid `data-start` references to nonexistent clip IDs

<Info>
For a full list of what the linter catches and how to fix each issue, see [Common Mistakes](/guides/common-mistakes) and [Troubleshooting](/guides/troubleshooting).
</Info>

## Related Packages

<CardGroup cols={2}>
<Card title="@hyperframes/parsers" icon="code" href="/packages/parsers">
The HTML + GSAP parsing layer the linter builds on.
</Card>
<Card title="@hyperframes/core" icon="cube" href="/packages/core">
Types and runtime; re-exports the linter for back-compat.
</Card>
<Card title="CLI" icon="terminal" href="/packages/cli">
`npx hyperframes lint` wraps this package.
</Card>
<Card title="Studio" icon="palette" href="/packages/studio">
Surfaces lint findings in the editor.
</Card>
</CardGroup>
157 changes: 157 additions & 0 deletions docs/packages/parsers.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
---
title: "@hyperframes/parsers"
description: "The GSAP + HTML parser/writer suite — standalone, zero @hyperframes/* dependencies."
---

The parsers package is the standalone foundation extracted from core. It owns the GSAP animation parser/writer (recast **and** acorn implementations), the HTML composition parser, hf-id stamping, and spring-ease generation. It has **no `@hyperframes/*` dependencies**, so it's the base every other package builds on.

```bash
npm install @hyperframes/parsers
```

## When to Use

<Tip>
**Most users do not need to install `@hyperframes/parsers` directly.** [`@hyperframes/core`](/packages/core) re-exports the parser API it needs, and the [CLI](/packages/cli) / [studio](/packages/studio) depend on it transitively. Reach for it directly only when you want the parsing layer **without** pulling in the rest of core.
</Tip>

**Use `@hyperframes/parsers` when you need to:**
- Parse HTML compositions into structured TypeScript objects
- Parse, edit, and re-serialize GSAP timeline scripts (AST round-trip)
- Stamp deterministic `hf-id` attributes onto a document
- Build tooling that touches the parsing layer but doesn't need core's runtime, compiler, or generators

## Package Exports

| Import | Description |
|--------|-------------|
| `@hyperframes/parsers` | HTML parser, GSAP serialize/validate helpers, hf-ids, shared types |
| `@hyperframes/parsers/gsap-parser-acorn` | Acorn-based GSAP parser (browser-safe, read path) |
| `@hyperframes/parsers/gsap-writer-acorn` | Acorn-based GSAP writer (mutation helpers) |
| `@hyperframes/parsers/gsap-parser-recast` | Recast-based GSAP parser/writer (legacy implementation) |
| `@hyperframes/parsers/gsap-constants` | `SUPPORTED_PROPS`, `SUPPORTED_EASES`, property groups |
| `@hyperframes/parsers/spring-ease` | Spring-ease curve generation |
| `@hyperframes/parsers/hf-ids` | Deterministic element id stamping |

<Info>
The package ships subpath entries so consumers tree-shake to what they use — importing `@hyperframes/parsers/hf-ids` (a couple KB) does **not** pull in the GSAP AST machinery (recast/babel/acorn).
</Info>

## HTML Parsing

Round-trip between HTML and structured data:

```typescript
import {
parseHtml,
extractCompositionMetadata,
validateCompositionHtml,
} from '@hyperframes/parsers';
import type { ParsedHtml, CompositionMetadata } from '@hyperframes/parsers';

// Parse HTML into structured data
const parsed: ParsedHtml = parseHtml(htmlString);
// parsed.elements, parsed.gsapScript, parsed.styles, parsed.resolution, parsed.keyframes

// Extract composition metadata (id, duration, dimensions, variables)
const meta: CompositionMetadata = extractCompositionMetadata(htmlString);

// Validate HTML structure
const result = validateCompositionHtml(htmlString);
// result.valid, result.errors
```

### Modifying HTML

```typescript
import {
updateElementInHtml,
addElementToHtml,
removeElementFromHtml,
} from '@hyperframes/parsers';

const updated = updateElementInHtml(html, 'el-1', { start: 5 });
const added = addElementToHtml(html, newElement);
const cleaned = removeElementFromHtml(html, 'el-1');
```

## GSAP Script Parsing

The acorn parser/writer is the primary path (browser-safe). Parse a timeline script, mutate it, and serialize it back without losing surrounding code:

```typescript
import { parseGsapScriptAcorn, extractGsapLabels } from '@hyperframes/parsers/gsap-parser-acorn';
import {
updateAnimationInScript,
addAnimationToScript,
removeAnimationFromScript,
updateKeyframeInScript,
addKeyframeToScript,
shiftPositionsInScript,
scalePositionsInScript,
} from '@hyperframes/parsers/gsap-writer-acorn';
import type { GsapAnimation, GsapMethod, ParsedGsap } from '@hyperframes/parsers';

const parsed: ParsedGsap = parseGsapScriptAcorn(scriptContent);
// parsed.animations, parsed.timelineVar, parsed.preamble, parsed.postamble

// Mutation helpers operate on the script text and preserve unrelated code
const next = updateAnimationInScript(scriptContent, animationId, { duration: 2 });
```

High-level serialize / validate / keyframe-conversion helpers are on the main entry:

```typescript
import {
serializeGsapAnimations,
getAnimationsForElementId,
validateCompositionGsap,
keyframesToGsapAnimations,
gsapAnimationsToKeyframes,
} from '@hyperframes/parsers';
```

### GSAP Constants

```typescript
import {
SUPPORTED_PROPS, // animatable properties
SUPPORTED_EASES, // available easing functions
PROPERTY_GROUPS,
} from '@hyperframes/parsers/gsap-constants';
import type { PropertyGroupName } from '@hyperframes/parsers/gsap-constants';
```

## hf-ids

Deterministic element identity for stable diffing and editing:

```typescript
import { ensureHfIds, mintHfId } from '@hyperframes/parsers/hf-ids';

// Stamp hf-id attributes onto every editable element in a document
const withIds = ensureHfIds(htmlString);
```

## Spring Ease

```typescript
import { generateSpringEaseData, SPRING_PRESETS } from '@hyperframes/parsers/spring-ease';
```

## Related Packages

<CardGroup cols={2}>
<Card title="@hyperframes/core" icon="cube" href="/packages/core">
Types, generators, runtime, and compiler — re-exports the parser API it needs.
</Card>
<Card title="@hyperframes/lint" icon="circle-check" href="/packages/lint">
The composition linter, built on the parsers.
</Card>
<Card title="@hyperframes/studio-server" icon="server" href="/packages/studio-server">
The studio preview server, built on the parsers.
</Card>
<Card title="CLI" icon="terminal" href="/packages/cli">
Create, preview, lint, and render compositions.
</Card>
</CardGroup>
Loading
Loading