From 6267472ca3fdd9e9f4e2ebee3d055d3545ad002d Mon Sep 17 00:00:00 2001 From: Miguel Angel Simon Sierra Date: Sat, 27 Jun 2026 12:13:55 -0400 Subject: [PATCH] docs: add package pages for parsers, lint, and studio-server 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. --- docs/docs.json | 3 + docs/packages/core.mdx | 20 +++- docs/packages/lint.mdx | 112 +++++++++++++++++++++++ docs/packages/parsers.mdx | 157 ++++++++++++++++++++++++++++++++ docs/packages/studio-server.mdx | 96 +++++++++++++++++++ 5 files changed, 385 insertions(+), 3 deletions(-) create mode 100644 docs/packages/lint.mdx create mode 100644 docs/packages/parsers.mdx create mode 100644 docs/packages/studio-server.mdx diff --git a/docs/docs.json b/docs/docs.json index c6ae310bea..6048e8322c 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -323,6 +323,9 @@ "group": "Packages", "pages": [ "packages/core", + "packages/parsers", + "packages/lint", + "packages/studio-server", "packages/sdk", "packages/engine", "packages/player", diff --git a/docs/packages/core.mdx b/docs/packages/core.mdx index 22e41c7988..1938d5848a 100644 --- a/docs/packages/core.mdx +++ b/docs/packages/core.mdx @@ -177,6 +177,10 @@ const result = validateCompositionHtml(html); ### GSAP Script Parsing + + 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. + + ```typescript import { parseGsapScript, @@ -243,6 +247,10 @@ const styles = getStageStyles('portrait'); ## Linter + + 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. + + 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 + + The standalone GSAP + HTML parsing layer extracted from core. + + + The composition linter as a standalone library. + + + The mountable studio preview/editor backend. + The easiest way to create, preview, lint, and render compositions. @@ -440,7 +457,4 @@ import type { Full rendering pipeline built on top of core and engine. - - Visual composition editor that embeds the core runtime for preview. - diff --git a/docs/packages/lint.mdx b/docs/packages/lint.mdx new file mode 100644 index 0000000000..2c8ea68c85 --- /dev/null +++ b/docs/packages/lint.mdx @@ -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 + + + 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. + + +**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 + + + `@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. + + +## 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 + + + 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). + + +## Related Packages + + + + The HTML + GSAP parsing layer the linter builds on. + + + Types and runtime; re-exports the linter for back-compat. + + + `npx hyperframes lint` wraps this package. + + + Surfaces lint findings in the editor. + + diff --git a/docs/packages/parsers.mdx b/docs/packages/parsers.mdx new file mode 100644 index 0000000000..658be7ea5a --- /dev/null +++ b/docs/packages/parsers.mdx @@ -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 + + + **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. + + +**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 | + + + 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). + + +## 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 + + + + Types, generators, runtime, and compiler — re-exports the parser API it needs. + + + The composition linter, built on the parsers. + + + The studio preview server, built on the parsers. + + + Create, preview, lint, and render compositions. + + diff --git a/docs/packages/studio-server.mdx b/docs/packages/studio-server.mdx new file mode 100644 index 0000000000..bb64483a19 --- /dev/null +++ b/docs/packages/studio-server.mdx @@ -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 + + + **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. + + +**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 + + + `@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. + + +## 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 + + + + The browser editor UI this server backs. + + + The HTML + GSAP parsing layer it builds on. + + + Types and runtime; re-exports the studio API for back-compat. + + + `npx hyperframes preview` wires this server up for you. + +