Skip to content

Commit b12df27

Browse files
Merge pull request #39 from posecode-dev/feat/launch-showcase
Launch showcase: Mixamo clips on hero, playground default, and README GIFs
2 parents 51f35ed + c186a18 commit b12df27

8 files changed

Lines changed: 32 additions & 15 deletions

File tree

docs/media/deadlift.gif

97 KB
Loading

docs/media/jumping-jacks.gif

51.7 KB
Loading

docs/media/lateral-raise.gif

97.4 KB
Loading

docs/media/squat.gif

-67.1 KB
Loading

playground/src/clips.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* Showcase mocap-clip map: clip name (as written in a doc's `clip "<name>"`
3+
* directive) → retargeted animation asset URL. Shared by the playground viewer
4+
* and the landing hero so both play the same Mixamo-sourced motion for the
5+
* marketing surfaces, while the procedural DSL stays the source of truth for
6+
* every un-clipped movement.
7+
*
8+
* The FBX binaries live in `public/clips/` (gitignored, served from storage/CDN
9+
* in production). A movement plays its clip only when it declares `clip "<name>"`
10+
* AND the skinned character is active; anything missing falls back to procedural.
11+
*/
12+
export const SHOWCASE_CLIPS: Record<string, string> = {
13+
walk: "/clips/walk.fbx",
14+
squat: "/clips/back-squat.fbx",
15+
"bicycle-crunch": "/clips/bicycle-crunch.fbx",
16+
"jab-cross": "/clips/jab-cross.fbx",
17+
"jumping-jacks": "/clips/jumping-jacks.fbx",
18+
shuffling: "/clips/shuffling.fbx",
19+
};

playground/src/landing.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import { parse } from "posecode-parser";
99
import { inject } from "@vercel/analytics";
1010
import { PRESETS } from "./presets.js";
11+
import { SHOWCASE_CLIPS } from "./clips.js";
1112
import llmPrompt from "../../spec/llm-authoring.md?raw";
1213

1314
inject();
@@ -32,6 +33,9 @@ function initHero(): void {
3233
// Realistic skinned figure without flashing the procedural fallback.
3334
characterUrl: "/models/character.glb",
3435
showProceduralWhileLoading: false,
36+
// Marketing surface: the hero movement declares `clip "jumping-jacks"`, so
37+
// it plays the retargeted Mixamo mocap for maximum polish on first paint.
38+
clips: SHOWCASE_CLIPS,
3539
});
3640
const phaseEl = document.getElementById("hero-phase");
3741
viewer.onPhase(({ phaseName }) => {

playground/src/main.ts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
} from "./nice-share.js";
1919
import type { PosecodeEditor } from "./editor.js";
2020
import { PRESETS } from "./presets.js";
21+
import { SHOWCASE_CLIPS } from "./clips.js";
2122
import { renderWarnings } from "./warnings.js";
2223
import llmPrompt from "../../spec/llm-authoring.md?raw";
2324

@@ -548,18 +549,7 @@ void import("posecode-render").then(({ createViewer }) => {
548549
// clips.ts). Only fetched when a loaded movement names the clip, so this
549550
// never slows the default page. Disabled with the classic figure, which has
550551
// no skinned mesh to retarget onto.
551-
...(classicFigure
552-
? {}
553-
: {
554-
clips: {
555-
walk: "/clips/walk.fbx",
556-
squat: "/clips/back-squat.fbx",
557-
"bicycle-crunch": "/clips/bicycle-crunch.fbx",
558-
"jab-cross": "/clips/jab-cross.fbx",
559-
"jumping-jacks": "/clips/jumping-jacks.fbx",
560-
shuffling: "/clips/shuffling.fbx",
561-
},
562-
}),
552+
...(classicFigure ? {} : { clips: SHOWCASE_CLIPS }),
563553
});
564554
// Exposed for capture/e2e tooling (frame capture drives README GIFs).
565555
(window as unknown as Record<string, unknown>).__posecodeViewer = viewer;

scripts/capture-gifs.mjs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,13 @@ if (targets.length === 0) {
5353

5454
const server = await createServer({
5555
configFile: resolve(repoRoot, "playground/vite.config.ts"),
56-
server: { port: 0 },
56+
server: { port: 0, host: "127.0.0.1" },
5757
logLevel: "error",
5858
});
5959
await server.listen();
60-
const port = server.config.server.port ?? server.httpServer.address().port;
60+
// Use the ACTUAL bound port: with `port: 0`, config.server.port stays 0 (and
61+
// `0 ?? …` keeps 0), so read the listening socket instead.
62+
const port = server.httpServer.address().port;
6163
const origin = `http://127.0.0.1:${port}`;
6264

6365
const browser = await chromium.launch({ executablePath: chromiumPath() });
@@ -66,7 +68,9 @@ page.on("pageerror", (e) => console.error("[page]", e.message));
6668

6769
for (const t of targets) {
6870
const [w, h] = t.size;
69-
await page.goto(`${origin}/play/${t.id}`, { waitUntil: "load" });
71+
// `/play/<id>` is a production rewrite (vercel); in the vite dev server used
72+
// here it doesn't resolve, so use the SPA entry + hash which loads the doc.
73+
await page.goto(`${origin}/play.html#doc=${t.id}`, { waitUntil: "load" });
7074
await page.reload({ waitUntil: "load" });
7175
await page.waitForFunction(() => window.__posecodeViewer?.duration > 0, null, {
7276
timeout: 60000,

0 commit comments

Comments
 (0)