docs: add package pages for parsers, lint, and studio-server (#1772)

New docs pages for the three packages extracted from core (#1755, #1756,
#1757), wired into the Packages nav after @hyperframes/core. Each covers
when-to-use, exports, and API with cross-links. Core's parser/lint sections
now point at the dedicated packages and its Related Packages lists all three.
This commit is contained in:
Miguel Ángel
2026-06-27 12:18:03 -04:00
committed by GitHub
parent fb4d49d248
commit 7e0a4cd02e
5 changed files with 385 additions and 3 deletions
+3
View File
@@ -323,6 +323,9 @@
"group": "Packages",
"pages": [
"packages/core",
"packages/parsers",
"packages/lint",
"packages/studio-server",
"packages/sdk",
"packages/engine",
"packages/player",
+17 -3
View File
@@ -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,
@@ -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
@@ -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>
@@ -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
View File
@@ -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
View File
@@ -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>
+96
View File
@@ -0,0 +1,96 @@
---
title: "@hyperframes/studio-server"
description: "The studio preview/editor backend — a mountable Hono API, extracted from core."
---
The studio-server package is the HTTP backend that powers studio preview and editing — project routes, file serving, preview bundling, thumbnails, and source-mutation helpers. It was extracted from `@hyperframes/core/studio-api` into a dedicated package so an embedder can mount the studio backend **without** depending on core's full surface, and so core no longer ships a web server it doesn't need at render time.
```bash
npm install @hyperframes/studio-server
```
## When to Use
<Tip>
**Most users do not need this package directly.** The [CLI](/packages/cli) (`npx hyperframes preview`) and [studio](/packages/studio) wire it up for you. Reach for it when you're **embedding** the studio backend into your own server.
</Tip>
**Use `@hyperframes/studio-server` when you need to:**
- Mount the studio preview/editing API into an existing Node/Hono server
- Serve project files and bundled preview HTML to a custom frontend
- Drive source mutations (manual edits, draft markers) from your own tooling
<Info>
`@hyperframes/core/studio-api` still resolves (via a back-compat re-export stub), so existing imports keep working. New code should import from `@hyperframes/studio-server` directly.
</Info>
## Package Exports
| Import | Description |
|--------|-------------|
| `@hyperframes/studio-server` | `createStudioApi`, helpers, types |
| `@hyperframes/studio-server/screenshot-clip` | Element screenshot-clip geometry |
| `@hyperframes/studio-server/manual-edits-render-script` | Manual-edits render body script |
| `@hyperframes/studio-server/studio-motion-render-script` | Studio motion render body script |
| `@hyperframes/studio-server/draft-markers` | Draft gesture-marker attributes |
| `@hyperframes/studio-server/finite-mutation` | Finite-mutation safety checks |
## Mounting the API
`createStudioApi` returns a [Hono](https://hono.dev) app you can mount into any server. You supply a `StudioApiAdapter` that tells the API how to resolve projects, bundle preview HTML, and lint:
```typescript
import { createStudioApi } from '@hyperframes/studio-server';
import type { StudioApiAdapter, ResolvedProject } from '@hyperframes/studio-server';
const adapter: StudioApiAdapter = {
listProjects: () => projects,
resolveProject: (id) => projectsById.get(id) ?? null,
bundle: async (projectDir) => bundleToSingleHtml(projectDir),
lint: (html, opts) => lintHyperframeHtml(html, opts),
runtimeUrl: '/hyperframe-runtime.js',
};
const api = createStudioApi(adapter); // → Hono app
// Mount under /api in your own Hono server
app.route('/api', api);
```
The adapter is the seam between the framework-agnostic route logic and your storage / bundling / lint implementation — the [CLI](/packages/cli) supplies a filesystem-backed adapter, but you can back it with anything.
## Helpers
```typescript
import {
createProjectSignature, // cache key for a project's files
isSafePath, // path-traversal guard
walkDir,
getMimeType,
buildSubCompositionHtml,
getElementScreenshotClip,
} from '@hyperframes/studio-server';
import type {
ResolvedProject,
RenderJobState,
LintResult,
ScreenshotClip,
} from '@hyperframes/studio-server';
```
## Related Packages
<CardGroup cols={2}>
<Card title="Studio" icon="palette" href="/packages/studio">
The browser editor UI this server backs.
</Card>
<Card title="@hyperframes/parsers" icon="code" href="/packages/parsers">
The HTML + GSAP parsing layer it builds on.
</Card>
<Card title="@hyperframes/core" icon="cube" href="/packages/core">
Types and runtime; re-exports the studio API for back-compat.
</Card>
<Card title="CLI" icon="terminal" href="/packages/cli">
`npx hyperframes preview` wires this server up for you.
</Card>
</CardGroup>