diff --git a/.fallowrc.jsonc b/.fallowrc.jsonc index 470ee2c31..09f615b95 100644 --- a/.fallowrc.jsonc +++ b/.fallowrc.jsonc @@ -238,6 +238,21 @@ // that naturally converges and is unlikely to diverge; extraction would // require intrusive middleware changes beyond this PR's scope. "minLines": 6, + "ignore": [ + // slideshowPanelHelpers.ts: setSlideNotes/addFragment/addHotspot share an + // intentional parallel shape (signature + mapSlidesIn → exists-check → + // map/append); the per-slide mutation differs, so a shared abstraction + // would obscure more than it dedupes. + "packages/studio/src/components/panels/slideshowPanelHelpers.ts", + // SlideshowPanel.test.ts: parallel arrange/act/assert test cases — collapsing + // them would hurt readability of what each case verifies. + "packages/studio/src/components/panels/SlideshowPanel.test.ts", + // present.ts mirrors play.ts's server startup + console-output block. The + // shared low-level pieces (resolve*/injectRuntime/listenOnFreePort) are in + // utils/compositionServer.ts; the remaining clone is per-command logging text + // (different labels/help lines) — extracting it would over-abstract. + "packages/cli/src/commands/present.ts", + ], }, "health": { // executeGsapMutation (introduced by Phase 3b / acorn-parser stack, already @@ -260,6 +275,18 @@ "ignore": [ "packages/core/src/studio-api/routes/files.ts", "packages/core/src/parsers/gsapParser.ts", + // SlideshowPanel.tsx: top-level editor panel that wires several independent + // sections (slides/inspector/branches/hotspot). Its cyclomatic count comes + // from that fan-out; splitting it would scatter shared state without + // reducing real complexity. File-level exemption (not an inline comment) + // avoids the line-shift fingerprint problem noted above. + "packages/studio/src/components/panels/SlideshowPanel.tsx", + // play.ts / present.ts: CLI command entrypoints whose cyclomatic count is + // browser/arg validation + server wiring (same shape as preview.ts). The + // serving logic is factored into utils/compositionServer.ts; the remaining + // body is linear validation that reads clearly inline. + "packages/cli/src/commands/play.ts", + "packages/cli/src/commands/present.ts", ], }, } diff --git a/.prettierignore b/.prettierignore index d52ee1264..bcb50614d 100644 --- a/.prettierignore +++ b/.prettierignore @@ -14,3 +14,14 @@ skills/**/assets/vendor/ skills/**/*.min.js # reference snippets with intentional pseudo-markup (literal "..." attributes) skills/graphic-overlays/references/frames/polaroid.html + +# Generated demo compositions — large video-pipeline output (GSAP/Three/WebGL +# embedded), not hand-authored source; reformatting them is churn + risk. Listed +# explicitly (not registry/examples/**/*.html) so hand-authored example HTML still +# gets formatted. +registry/examples/airbnb-deck/index.html +registry/examples/airbnb-deck/demo.html +registry/examples/startup-pitch/index.html +registry/examples/startup-pitch/demo.html +registry/examples/slideshow-demo/index.html +registry/examples/warm-grain/compositions/captions.html diff --git a/packages/cli/src/cli.ts b/packages/cli/src/cli.ts index ffe3c6521..23261f206 100644 --- a/packages/cli/src/cli.ts +++ b/packages/cli/src/cli.ts @@ -114,6 +114,7 @@ const commandLoaders = { add: () => import("./commands/add.js").then((m) => m.default), catalog: () => import("./commands/catalog.js").then((m) => m.default), play: () => import("./commands/play.js").then((m) => m.default), + present: () => import("./commands/present.js").then((m) => m.default), preview: () => import("./commands/preview.js").then((m) => m.default), publish: () => import("./commands/publish.js").then((m) => m.default), render: () => import("./commands/render.js").then((m) => m.default), diff --git a/packages/cli/src/commands/play.ts b/packages/cli/src/commands/play.ts index e9f254976..ca23b55e5 100644 --- a/packages/cli/src/commands/play.ts +++ b/packages/cli/src/commands/play.ts @@ -13,7 +13,7 @@ export const examples: Example[] = [ "hyperframes play --browser-path /usr/bin/chromium --user-data-dir /tmp/hf-profile --remote-debugging-port 9222", ], ]; -import { resolve, dirname } from "node:path"; +import { resolve } from "node:path"; import * as clack from "@clack/prompts"; import { c } from "../ui/colors.js"; import { resolveProject } from "../utils/project.js"; @@ -22,6 +22,13 @@ import { parseRemoteDebuggingPort, validateRemoteDebuggingPortDeps, } from "../utils/openBrowser.js"; +import { + resolveRuntimePath, + resolvePlayerPath, + listenOnFreePort, + injectRuntime, + assetContentType, +} from "../utils/compositionServer.js"; export default defineCommand({ meta: { name: "play", description: "Play a composition in a lightweight browser player" }, @@ -121,7 +128,7 @@ export default defineCommand({ }); // Serve composition files (HTML + assets) - app.get("/composition/*", async (ctx) => { + app.get("/composition/*", (ctx) => { const reqPath = ctx.req.path.replace("/composition/", ""); const filePath = resolve(project.dir, reqPath); @@ -131,33 +138,11 @@ export default defineCommand({ // shares the project-dir prefix (e.g. `