initial code (#2)

* feat: initial code port from hyperframes-internal

Port all OSS-ready packages from the internal monorepo:
- @hyperframes/core — shared types, HTML generation, GSAP utilities, runtime
- @hyperframes/cli — CLI for creating, previewing, and rendering compositions
- @hyperframes/engine — framework-agnostic rendering engine (BeginFrame + FFmpeg)
- @hyperframes/producer — video rendering pipeline (Puppeteer + FFmpeg)
- @hyperframes/ui-player — browser-based video player component
- @hyperframes/studio — composition editor (React frontend + Hono backend)

Includes regression test suite with Docker-based test harness.

All HeyGen-internal references, deployment infrastructure, and
proprietary assets have been removed. Package names migrated
from @app/* to @hyperframes/*.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: scrub internal codenames and stale references from OSS port

- Replace static.heygen.ai runtime URLs in test fixtures
- Remove internal CDN publish script (publish-hyperframe-runtime.ts)
- Replace sandbox-studio, sandbox-interceptor, __magicEditRuntime
  with neutral names (studio, hyperframe-runtime, __hyperframeRuntime)
- Fix stale Vault API / localhost references in docs
- Remove broken deprecated_studio link

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: remove remaining internal codenames and stale references

- Delete stale producer README.md and PIPELINE.md (referenced nonexistent files)
- Replace "Cerberus" codename with "HyperFrames" in test design reviews
- Replace magic-edit postMessage identifiers with hf-preview/hf-parent
- Rename debug-magic-edit-timeline.ts to debug-timeline.ts
- Replace "Motion Cut" with "HyperFrames" in Timeline comments
- Fix studio/CLI references to nonexistent archive package
  (use local data/projects/ dir, stub render proxy)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Vance Ingalls
2026-03-21 22:43:56 -07:00
committed by GitHub
co-authored by Claude Opus 4.6
parent 10621e7903
commit 9f8e5ba5a1
401 changed files with 54545 additions and 2 deletions
@@ -0,0 +1,116 @@
import { useRef, useCallback, memo } from "react";
import { EditorView, keymap, lineNumbers, highlightActiveLine, highlightActiveLineGutter } from "@codemirror/view";
import { EditorState } from "@codemirror/state";
import { defaultKeymap, history, historyKeymap } from "@codemirror/commands";
import { bracketMatching, foldGutter, indentOnInput } from "@codemirror/language";
import { closeBrackets, closeBracketsKeymap } from "@codemirror/autocomplete";
import { highlightSelectionMatches, searchKeymap } from "@codemirror/search";
import { oneDark } from "@codemirror/theme-one-dark";
import { html } from "@codemirror/lang-html";
import { css } from "@codemirror/lang-css";
import { javascript } from "@codemirror/lang-javascript";
function getLanguageExtension(language: string) {
switch (language) {
case "html":
return html();
case "css":
return css();
case "javascript":
case "js":
case "typescript":
case "ts":
return javascript({ typescript: language === "typescript" || language === "ts" });
default:
return html();
}
}
function detectLanguage(filePath: string): string {
const ext = filePath.split(".").pop()?.toLowerCase() ?? "";
const map: Record<string, string> = {
html: "html",
htm: "html",
css: "css",
js: "javascript",
ts: "typescript",
jsx: "javascript",
tsx: "typescript",
json: "javascript",
};
return map[ext] ?? "html";
}
interface SourceEditorProps {
content: string;
filePath?: string;
language?: string;
onChange?: (content: string) => void;
readOnly?: boolean;
}
export const SourceEditor = memo(function SourceEditor({
content,
filePath,
language,
onChange,
readOnly = false,
}: SourceEditorProps) {
const editorRef = useRef<EditorView | null>(null);
const containerRef = useRef<HTMLDivElement | null>(null);
const onChangeRef = useRef(onChange);
onChangeRef.current = onChange;
const mountEditor = useCallback(
(node: HTMLDivElement | null) => {
if (editorRef.current) {
editorRef.current.destroy();
editorRef.current = null;
}
if (!node) return;
containerRef.current = node;
const lang = language ?? (filePath ? detectLanguage(filePath) : "html");
const updateListener = EditorView.updateListener.of((update) => {
if (update.docChanged && onChangeRef.current) {
onChangeRef.current(update.state.doc.toString());
}
});
const state = EditorState.create({
doc: content,
extensions: [
lineNumbers(),
highlightActiveLine(),
highlightActiveLineGutter(),
history(),
foldGutter(),
indentOnInput(),
bracketMatching(),
closeBrackets(),
highlightSelectionMatches(),
keymap.of([
...closeBracketsKeymap,
...defaultKeymap,
...searchKeymap,
...historyKeymap,
]),
getLanguageExtension(lang),
oneDark,
updateListener,
EditorState.readOnly.of(readOnly),
EditorView.theme({
"&": { height: "100%" },
".cm-scroller": { overflow: "auto" },
}),
],
});
editorRef.current = new EditorView({ state, parent: node });
},
[content, filePath, language, readOnly],
);
return <div ref={mountEditor} className="h-full w-full overflow-hidden" />;
});