mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-08 02:36:10 +00:00
* refactor: split useTimelinePlayer.ts and hyperframes-player.ts into focused modules (<500 LOC each) * fix(ci): scope 500 LOC check to packages/studio, add allowlist for grandfathered files * feat(cli): Linux ARM64 support — auto-install Chromium on DGX Spark / GB10 / Jetson Chrome Headless Shell has no Linux ARM64 binary. On arm64 Linux: - Detects the platform automatically - Tries to auto-install system Chromium via apt-get (works on Ubuntu/Debian ARM) - Falls back to clear manual instructions with exact commands - 'hyperframes browser ensure' guides through the setup interactively - After setup, all render commands work without any flags * fix(ci): disable Windows Defender real-time monitoring to prevent EPERM builds Path exclusions are insufficient — Defender re-scans new files created during bun install before the exclusion takes effect. Disable real-time monitoring for the entire job duration instead (standard CI practice). * refactor(studio): split all files >500 LOC + extract useToast, delete allowlist All 11 large files split into focused modules under 500 LOC. App.tsx extracted toast logic into useToast hook (493 LOC now). .filesize-allowlist deleted — no longer needed. * fix: remove unused imports from split files, extract useToast from App.tsx App.tsx: 504 → 493 lines (toast logic extracted to useToast hook) timelineDOM.ts: remove unused imports from re-export pattern MotionPanel.tsx: remove unused clampStudioCustomEasePoints import studioMotionOps.ts: remove unused StudioGsapMotionDirection import * fix(ci): use Set-MpPreference to fully disable Windows Defender (both jobs) * fix(producer): use node --experimental-strip-types instead of tsx for build:fonts Eliminates the tsx binary dependency that Windows Defender locks during bun install, causing EPERM errors. Node 22.6+ strips TypeScript types natively with no external binary. * chore: remove .filesize-allowlist — App.tsx is now 493 lines (<500) * fix(ci): disable Windows Defender before checkout to prevent all EPERM races * fix(producer): skip build:fonts if fontData.generated.ts already exists The generated file is tracked in git, so CI doesn't need to regenerate it. This avoids @fontsource/inter node_modules access on Windows which triggers EPERM from Defender scanning during bun install.
98 lines
3.0 KiB
TypeScript
98 lines
3.0 KiB
TypeScript
/**
|
|
* Agent prompt builder for HyperFrames element edit requests.
|
|
*/
|
|
import { formatTime } from "../../player/lib/time";
|
|
import type { DomEditSelection, DomEditTextField } from "./domEditingTypes";
|
|
|
|
function formatBoundingBox(bounds: DomEditSelection["boundingBox"]): string {
|
|
return `x=${Math.round(bounds.x)}, y=${Math.round(bounds.y)}, width=${Math.round(bounds.width)}, height=${Math.round(bounds.height)}`;
|
|
}
|
|
|
|
function formatStyleBlock(styles: Record<string, string>): string {
|
|
return Object.entries(styles)
|
|
.filter(([, value]) => value && value !== "initial")
|
|
.map(([key, value]) => `${key}: ${value}`)
|
|
.join("\n");
|
|
}
|
|
|
|
function formatTextFields(fields: DomEditTextField[]): string {
|
|
return fields
|
|
.map(
|
|
(field) =>
|
|
`- key=${field.key}; tag=<${field.tagName}>; source=${field.source}; text=${JSON.stringify(field.value)}`,
|
|
)
|
|
.join("\n");
|
|
}
|
|
|
|
export function buildElementAgentPrompt({
|
|
selection,
|
|
currentTime,
|
|
tagSnippet,
|
|
selectionContext,
|
|
userInstruction,
|
|
sourceFilePath,
|
|
}: {
|
|
selection: DomEditSelection;
|
|
currentTime: number;
|
|
tagSnippet?: string;
|
|
selectionContext?: string;
|
|
userInstruction?: string;
|
|
sourceFilePath?: string;
|
|
}): string {
|
|
const displayedSourceFile = sourceFilePath?.trim() || selection.sourceFile;
|
|
const lines = [
|
|
"## HyperFrames element edit request v1",
|
|
"Schema version: 1",
|
|
"",
|
|
userInstruction?.trim() || "Edit this selected HyperFrames element.",
|
|
"",
|
|
`Composition: ${selection.compositionPath}`,
|
|
`Playback time: ${formatTime(currentTime)}`,
|
|
`Source file: ${displayedSourceFile}`,
|
|
`DOM id: ${selection.id ?? "(none)"}`,
|
|
`Selector: ${selection.selector ?? "(none)"}`,
|
|
`Selector index: ${selection.selectorIndex ?? 0}`,
|
|
`Tag: <${selection.tagName}>`,
|
|
`Bounds: ${formatBoundingBox(selection.boundingBox)}`,
|
|
];
|
|
|
|
if (selection.textContent) {
|
|
lines.push(`Text: ${selection.textContent}`);
|
|
}
|
|
|
|
const trimmedSelectionContext = selectionContext?.trim();
|
|
if (trimmedSelectionContext) {
|
|
lines.push("", "Selection context:", trimmedSelectionContext);
|
|
}
|
|
|
|
const textFieldsBlock = formatTextFields(selection.textFields);
|
|
if (textFieldsBlock) {
|
|
lines.push("", "Text fields:", textFieldsBlock);
|
|
}
|
|
|
|
const inlineStyleBlock = formatStyleBlock(selection.inlineStyles);
|
|
if (inlineStyleBlock) {
|
|
lines.push("", "Inline styles:", inlineStyleBlock);
|
|
}
|
|
|
|
const computedStyleBlock = formatStyleBlock(selection.computedStyles);
|
|
if (computedStyleBlock) {
|
|
lines.push("", "Computed styles (browser-resolved):", computedStyleBlock);
|
|
}
|
|
|
|
if (tagSnippet) {
|
|
lines.push("", "Target HTML:", tagSnippet);
|
|
}
|
|
|
|
lines.push(
|
|
"",
|
|
"Guardrails:",
|
|
"- Make a targeted change to this element only.",
|
|
"- Preserve the rest of the composition and its timing.",
|
|
"- Do not modify other elements' data-* attributes or positioning.",
|
|
"- Prefer existing inline styles or existing CSS rules for this element over adding unrelated selectors.",
|
|
);
|
|
|
|
return lines.join("\n");
|
|
}
|