mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 23:03:09 +00:00
fix: address QA report P0-P2 issues for 10/10 agent experience (#208)
## Summary
Addresses all 8 issues from the QA report to improve agent and user experience.
### P0 — Must Fix
- **Blank template broken captions**: Removed `compositions/captions.html` and its reference from the blank template. Every agent (10/10) hit 404 errors during render.
- **Inner-wrapper example**: Added a clear structural comment in the blank template showing the correct `class="clip"` + inner wrapper pattern.
- **Sub-composition introspection**: `hyperframes compositions` now reads external HTML files referenced via `data-composition-src` and shows their real duration/element count instead of `0.0s / 0 elements`.
### P1 — Fix Soon
- **Font mapping warnings**: Now lists all mapped fonts, suggests alternatives (use a mapped font, add @font-face, install locally), and links to docs.
- **Browser 404s**: Non-font "Failed to load resource" 404s now prefixed with `[non-blocking]` instead of `[Browser:ERROR]`.
- **Render concurrency**: Default workers increased from `cores/2` (max 4) to `cores*3/4` (max 6). Added `--concurrency` alias.
### P2 — Nice to Have
- **Transform conflict fix suggestion**: `gsap_css_transform_conflict` now suggests exact GSAP property replacements (e.g., `xPercent: -50, yPercent: -50`).
- **Upgrade --yes**: Now actually runs the install instead of just printing the command.
## Before / After
### Font mapping warning
**Before:**
```
[Compiler] No deterministic font mapping for: DM Sans
```
**After:**
```
[Compiler] No deterministic font mapping for: DM Sans
Mapped fonts: arial → inter, courier → jetbrains-mono, ...
To fix, pick one:
1. Use a mapped font name instead (see list above)
2. Add a @font-face block in your HTML with a local or hosted font file
3. Install the font locally on the render machine (Docker: add to Dockerfile)
4. Add an alias to FONT_ALIASES in deterministicFonts.ts (for contributors)
```
### Browser 404s during render
**Before:** `[Browser:ERROR] Failed to load resource: the server responded with a status of 404`
**After:** `[non-blocking] Failed to load resource: the server responded with a status of 404`
### Transform conflict lint
**Before:** `Fix: Remove the transform from CSS and use tl.fromTo...`
**After:** `Fix: Remove transform: translate(-50%, -50%) from CSS and replace with GSAP properties: xPercent: -50, yPercent: -50`
### Compositions command
**Before:**
```
overlay 0.0s 1920×1080 0 elements
```
**After:**
```
overlay 8.0s 1920×1080 2 elements ← compositions/overlay.html
```
## Test plan
- [x] All 422 core tests pass
- [x] TypeScript compiles cleanly (all 4 packages)
- [x] Full monorepo build succeeds
- [x] `hyperframes init --template blank` ships without broken captions reference
This commit is contained in:
@@ -7,7 +7,7 @@ export const examples: Example[] = [
|
||||
["Render transparent WebM overlay", "hyperframes render --format webm --output overlay.webm"],
|
||||
["High quality at 60fps", "hyperframes render --fps 60 --quality high --output hd.mp4"],
|
||||
["Deterministic render via Docker", "hyperframes render --docker --output deterministic.mp4"],
|
||||
["Parallel rendering with 4 workers", "hyperframes render --workers 4 --output fast.mp4"],
|
||||
["Parallel rendering with 6 workers", "hyperframes render --workers 6 --output fast.mp4"],
|
||||
];
|
||||
import { cpus, freemem } from "node:os";
|
||||
import { resolve, dirname, join } from "node:path";
|
||||
@@ -28,9 +28,9 @@ const VALID_FORMAT = new Set(["mp4", "webm"]);
|
||||
|
||||
const CPU_CORE_COUNT = cpus().length;
|
||||
|
||||
/** Half of CPU cores, capped at 4. Each worker spawns a Chrome process (~256 MB). */
|
||||
/** 3/4 of CPU cores, capped at 8. Each worker spawns a Chrome process (~256 MB). */
|
||||
function defaultWorkerCount(): number {
|
||||
return Math.max(1, Math.min(Math.floor(CPU_CORE_COUNT / 2), 4));
|
||||
return Math.max(1, Math.min(Math.floor((CPU_CORE_COUNT * 3) / 4), 8));
|
||||
}
|
||||
|
||||
export default defineCommand({
|
||||
@@ -66,8 +66,8 @@ export default defineCommand({
|
||||
workers: {
|
||||
type: "string",
|
||||
description:
|
||||
"Parallel render workers (1-8 or 'auto'). Default: half your CPU cores, max 4. " +
|
||||
"Each worker launches a separate Chrome process.",
|
||||
"Parallel render workers (number or 'auto'). Default: auto. " +
|
||||
"Each worker launches a separate Chrome process (~256 MB RAM).",
|
||||
},
|
||||
docker: {
|
||||
type: "boolean",
|
||||
@@ -123,8 +123,8 @@ export default defineCommand({
|
||||
let workers: number | undefined;
|
||||
if (args.workers != null && args.workers !== "auto") {
|
||||
const parsed = parseInt(args.workers, 10);
|
||||
if (isNaN(parsed) || parsed < 1 || parsed > 8) {
|
||||
errorBox("Invalid workers", `Got "${args.workers}". Must be 1-8 or "auto".`);
|
||||
if (isNaN(parsed) || parsed < 1) {
|
||||
errorBox("Invalid workers", `Got "${args.workers}". Must be a positive number or "auto".`);
|
||||
process.exit(1);
|
||||
}
|
||||
workers = parsed;
|
||||
@@ -155,7 +155,7 @@ export default defineCommand({
|
||||
const workerLabel =
|
||||
args.workers != null
|
||||
? `${workerCount} workers`
|
||||
: `${workerCount} workers (auto \u2014 half of ${CPU_CORE_COUNT} cores)`;
|
||||
: `${workerCount} workers (auto — ${CPU_CORE_COUNT} cores detected)`;
|
||||
console.log("");
|
||||
console.log(
|
||||
c.accent("\u25C6") +
|
||||
|
||||
Reference in New Issue
Block a user