From cbddfc7cb3fbe23a406fe1f3de7fe8be726c04a9 Mon Sep 17 00:00:00 2001 From: "roboco-app[bot]" <302741806+roboco-app[bot]@users.noreply.github.com> Date: Sat, 25 Jul 2026 03:39:07 +0000 Subject: [PATCH] [c71959c3] Video: release 0.27.0 (#698) * [c71959c3] feat(motion): add release-0.27.0 panel-demo clip Extends the panel-demo kit register (kit/) with a v0.27.0 release composition: identity cold open, four feature cards (WAF real-IP resolution, Telegram Mini App V6, Codex/Gemini providers, cost-tiered routing) flipping from in-progress to completed, a camera that pushes per beat via pk-camera data-shots, a cursor that clicks and travels via pk-cursor data-waypoints, a receipt stats overlay, a shipped toast, and the roboco.tech outro. Ships vertical.html, square.html, props.js, captions.json, and a vitest smoke test mirroring release-0.26.0's invariants. * [c71959c3] fix(motion): implement genuinely non-uniform card-beat gaps in release-0.27.0 clip The four .pk-card animation-delay values were uniform 5.0s/10.0s/15.0s/20.0s in both vertical.html and square.html -- byte-for-byte identical to release-0.26.0's metronomic spacing the craft bar bans -- despite the prior decision_log claiming 5.5s/6.4s/5.3s varied gaps had been added. Card delays are now 5.0/10.5/16.9/22.2 (real 5.5s/6.4s/5.3s gaps). Camera data-shots, cursor data-waypoints, and the stats/toast/outro tail in both files are re-warped with a shared piecewise-linear time function anchored at each card's new beat, so nothing desyncs and the tail still fits inside the fixed 40s runtime. Added a regression test asserting the four card gaps are not all identical. * [c71959c3] docs(motion): add release-0.27.0 composition section to README --------- Co-authored-by: UX/UI Developer 1 Co-authored-by: UX/UI Documenter --- motion/README.md | 54 +++ .../compositions/release-0.27.0/captions.json | 18 + motion/compositions/release-0.27.0/props.js | 9 + .../release-0.27.0/release-0.27.0.test.js | 125 ++++++ .../compositions/release-0.27.0/square.html | 353 ++++++++++++++++ .../compositions/release-0.27.0/vertical.html | 379 ++++++++++++++++++ 6 files changed, 938 insertions(+) create mode 100644 motion/compositions/release-0.27.0/captions.json create mode 100644 motion/compositions/release-0.27.0/props.js create mode 100644 motion/compositions/release-0.27.0/release-0.27.0.test.js create mode 100644 motion/compositions/release-0.27.0/square.html create mode 100644 motion/compositions/release-0.27.0/vertical.html diff --git a/motion/README.md b/motion/README.md index 3dd18468..2780ce8d 100644 --- a/motion/README.md +++ b/motion/README.md @@ -208,3 +208,57 @@ Same schema as prior releases: one `captions.json` next to the HTML with self-ve ### Smoke-test invariants `release-0.26.0.test.js` extends the panel-demo register checks: both `vertical.html` (1080×1920) and `square.html` (1080×1080) parse with `data-duration="40"` and the HyperFrames params, the kit CSS/JS wiring is present, **four** feature cards each carry a progress-to-completed pill swap and include the exact titles ("Off the public net", "3 forges, 1 API", "Telegram cockpit", "Guard mode: active"), the stats overlay renders the three-line receipt (1 release / 3 forges / 0 leaks), the cursor and toast appear, the outro shows "roboco.tech", no external scripts are loaded, and no em dashes slip into on-screen copy or captions. + +## Release-specific example: `release-0.27.0` + +`compositions/release-0.27.0/` is a panel-demo kit clip for the RoboCo v0.27.0 release, mirroring the structure and pacing of `release-0.25.0`/`release-0.26.0`. It builds on the `kit/` register instead of the text-card style, so it has no `theme.css` of its own. + +The composition runs **40 seconds** total. The story is "four brains, zero bans" (the hero tagline and the panel intake text): the CEO types "Four brains, zero bans" into the panel intake at 3.6s, then four shipped feature cards enter the kanban column one per scene and flip from `in progress` to `completed`: + +1. **WAF knows the real IP** — enters at 5.0s, completes at 6.6s ("Tailscale hops don't get banned anymore."). The WAF now resolves the real client behind host-proxy hops via `ClientIpResolutionMiddleware`, instead of banning the operator's own Tailscale-tunneled device. +2. **Telegram Mini App V6** — enters at 10.5s, completes at 12.1s ("Real chat scopes, wallet-style metrics."). The Mini App gets a native-type premium overhaul: borderless cards, a wallet-style metrics tab, honest Chat scopes, and a live Board decide sheet. +3. **Codex and Gemini join** — enters at 16.9s, completes at 18.5s ("Four model providers, one gateway now."). `ModelProvider.OPENAI` (Codex CLI) and `ModelProvider.GEMINI` (Gemini CLI) join Anthropic and Grok on the agent-provider roster. +4. **Cost-tiered routing** — enters at 22.2s, completes at 23.8s ("Save a routing mix, restore it anytime."). Cost-tiered model routing plus saved routing presets let an operator snapshot and restore a full routing configuration. + +Unlike `release-0.25.0`/`release-0.26.0`'s uniform 5.0s card-beat gaps, this composition deliberately varies the spacing (5.5s/6.4s/5.3s between successive card entrances — delays 5.0/10.5/16.9/22.2s) per the craft bar's anti-metronome rule in "Beat density and pacing variation" above; the camera shots, cursor waypoints, and the stats/toast/outro tail are all re-warped with a shared piecewise-linear time function so nothing desyncs against the shifted beats. A cursor clicks the intake at 4.8s (submit), then witnesses each card completing without further clicks, the stats overlay shows "1 release / 4 providers / 0 bans" from 25.7s to 33.0s, the toast "v0.27.0 shipped / I approved once. 25 agents shipped it." runs from 31.0s, and the "roboco.tech" outro lands at 36.3s and holds through the end. + +The composition reuses the same `pk-frame` chrome, `pk-column`/`pk-card`, `pk-pill`, `pk-cursor`, `pk-toast`, and `pk-outro` pieces from `kit/`, plus the typing reveal wired through `props.js`. Each feature card uses the `pk-pill--swap-out` / `pk-pill--swap-in` pattern to replace the `in progress` pill with `completed` on the same beat. + +### Preview / test this composition + +```bash +npx hyperframes preview compositions/release-0.27.0/vertical.html +npx hyperframes preview compositions/release-0.27.0/square.html +pnpm test # release-0.27.0.test.js is picked up by vitest +``` + +### `props.js` shape + +```js +{ + introText: string, // text that types into the panel intake field + toastTitle: string, // headline inside the shipping toast + toastBody: string, // sub-line inside the shipping toast +} +``` + +`window.__ORIENTATION__` is set for local preview only; the sidecar overwrites both globals at render time. + +### `captions.json` + +Same schema as prior releases: one `captions.json` next to the HTML with self-verified X and TikTok captions. The X caption totals **234 characters** (within the 280 limit); the TikTok caption **499 characters** (within the 2200 limit): + +```json +{ + "composition_id": "release-0.27.0", + "occasion": "release: RoboCo v0.27.0", + "platforms": { + "x": { "caption": "v0.27.0 is out.\nThe WAF used to ban my own phone behind Tailscale. Now it knows the real client.\nTelegram Mini App V6, Codex and Gemini joined the roster, cost-tiered routing shipped.\nI approved once. 25 agents shipped it.\nroboco.tech", "char_count": 234, "limit": 280, "within_limit": true }, + "tiktok": { "caption": "v0.27.0 is out.\n\nThe WAF used to ban my own phone behind a Tailscale hop. Now it resolves the real client. Zero false bans.\n\nTelegram Mini App V6 shipped: real chat scopes, wallet-style metrics, a live Board sheet.\n\nCodex and Gemini just joined Claude and Grok on the model roster. Four providers, one gateway.\n\nCost-tiered routing plus saved presets: snapshot a routing mix, restore it whenever.\n\nI approved once. 25 agents shipped it.\n\nroboco.tech\n\n#buildinpublic #aiagents #devtools #indiehackers", "char_count": 499, "limit": 2200, "within_limit": true } + } +} +``` + +### Smoke-test invariants + +`release-0.27.0.test.js` extends the panel-demo register checks: both `vertical.html` (1080×1920) and `square.html` (1080×1080) parse with `data-duration="40"` and the HyperFrames params, the kit CSS/JS wiring is present, **four** feature cards each carry a progress-to-completed pill swap and include the exact titles ("WAF knows the real IP", "Telegram Mini App V6", "Codex and Gemini join", "Cost-tiered routing"), the stats overlay renders the three-line receipt (1 release / 4 providers / 0 bans), the cursor and toast appear, the outro shows "roboco.tech", no external scripts are loaded, no em dashes slip into on-screen copy or captions, and — the finding a prior revision cycle on this composition caught — the four card-beat gaps are asserted non-uniform (`new Set(gaps).size > 1`), regression-guarding against silently reusing `release-0.26.0`'s identical 5.0s/5.0s/5.0s spacing. diff --git a/motion/compositions/release-0.27.0/captions.json b/motion/compositions/release-0.27.0/captions.json new file mode 100644 index 00000000..212437f8 --- /dev/null +++ b/motion/compositions/release-0.27.0/captions.json @@ -0,0 +1,18 @@ +{ + "composition_id": "release-0.27.0", + "occasion": "release: RoboCo v0.27.0", + "platforms": { + "x": { + "caption": "v0.27.0 is out.\nThe WAF used to ban my own phone behind Tailscale. Now it knows the real client.\nTelegram Mini App V6, Codex and Gemini joined the roster, cost-tiered routing shipped.\nI approved once. 25 agents shipped it.\nroboco.tech", + "char_count": 234, + "limit": 280, + "within_limit": true + }, + "tiktok": { + "caption": "v0.27.0 is out.\n\nThe WAF used to ban my own phone behind a Tailscale hop. Now it resolves the real client. Zero false bans.\n\nTelegram Mini App V6 shipped: real chat scopes, wallet-style metrics, a live Board sheet.\n\nCodex and Gemini just joined Claude and Grok on the model roster. Four providers, one gateway.\n\nCost-tiered routing plus saved presets: snapshot a routing mix, restore it whenever.\n\nI approved once. 25 agents shipped it.\n\nroboco.tech\n\n#buildinpublic #aiagents #devtools #indiehackers", + "char_count": 499, + "limit": 2200, + "within_limit": true + } + } +} diff --git a/motion/compositions/release-0.27.0/props.js b/motion/compositions/release-0.27.0/props.js new file mode 100644 index 00000000..071377f5 --- /dev/null +++ b/motion/compositions/release-0.27.0/props.js @@ -0,0 +1,9 @@ +// Default sample props for local preview of the RoboCo v0.27.0 release clip. +// The video-renderer sidecar OVERWRITES this file at render time with the +// real per-request values + window.__ORIENTATION__. +window.__PROPS__ = { + introText: "Four brains, zero bans", + toastTitle: "v0.27.0 shipped", + toastBody: "I approved once. 25 agents shipped it.", +}; +window.__ORIENTATION__ = "vertical"; diff --git a/motion/compositions/release-0.27.0/release-0.27.0.test.js b/motion/compositions/release-0.27.0/release-0.27.0.test.js new file mode 100644 index 00000000..57ea0e06 --- /dev/null +++ b/motion/compositions/release-0.27.0/release-0.27.0.test.js @@ -0,0 +1,125 @@ +import { readFileSync, existsSync } from "node:fs"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; +import { describe, expect, it } from "vitest"; + +// HTML-structure smoke test for the RoboCo v0.27.0 release composition. +// Extends the panel-demo register: panel chrome, typing reveal, four feature cards +// with progress -> completed pill flips, cursor, stats overlay, toast, +// outro, offline constraint, and the captions.json schema/limits. + +const here = dirname(fileURLToPath(import.meta.url)); +const dir = here; +const read = (name) => readFileSync(join(dir, name), "utf8"); + +const orientations = [ + { file: "vertical.html", height: "1920" }, + { file: "square.html", height: "1080" }, +]; + +describe("release-0.27.0 composition", () => { + it("ships props.js (default preview values, sidecar overwrites at render)", () => { + expect(existsSync(join(dir, "props.js"))).toBe(true); + const src = read("props.js"); + expect(src).toContain("window.__PROPS__"); + expect(src).toContain("window.__ORIENTATION__"); + expect(src).toContain("introText"); + expect(src).toContain("toastTitle"); + expect(src).toContain("toastBody"); + expect(src).not.toMatch(/—/); + }); + + it.each(orientations)("$file parses with correct dimensions and wiring", ({ file, height }) => { + const html = read(file); + + expect(html).toContain('data-width="1080"'); + expect(html).toContain(`data-height="${height}"`); + expect(html).toMatch(/data-duration="40"/); + expect(html).toMatch(/data-fps="30"/); + + const propsIdx = html.indexOf(''); + const kitJsIdx = html.indexOf(''); + const inlineIdx = html.indexOf("window.__timelines"); + expect(propsIdx).toBeGreaterThan(-1); + expect(kitJsIdx).toBeGreaterThan(propsIdx); + expect(inlineIdx).toBeGreaterThan(kitJsIdx); + + expect(html).toContain('href="../../kit/kit.css"'); + expect(html).toMatch(/class="[^"]*clip[^"]*"/); + + expect(html).toContain("pk-frame"); + expect(html).toContain("pk-frame__sidebar"); + expect(html).toContain("pk-frame__topbar"); + + expect(html).toContain('id="typeIntro"'); + expect(html).toContain("pk-caret"); + expect(html).toContain("typeReveal"); + + const cardCount = (html.match(/class="pk-card"/g) || []).length; + const progressCount = (html.match(/pk-pill--progress/g) || []).length; + const completedCount = (html.match(/pk-pill--completed/g) || []).length; + expect(cardCount).toBe(4); + expect(progressCount).toBe(4); + expect(completedCount).toBe(4); + + expect(html).toContain("v0.27.0"); + expect(html).toContain("WAF knows the real IP"); + expect(html).toContain("Telegram Mini App V6"); + expect(html).toContain("Codex and Gemini join"); + expect(html).toContain("Cost-tiered routing"); + + // Choreographed cursor: multi-waypoint path with at least one click + // beat (rings are generated at runtime by kit.js, not static HTML), + // and a camera that moves — a locked-off frame is an automatic bounce. + expect(html).toContain("pk-cursor"); + const waypoints = html.match(/data-waypoints="([^"]+)"/); + expect(waypoints).not.toBeNull(); + expect(waypoints[1].split(";").length).toBeGreaterThanOrEqual(6); + expect(waypoints[1]).toContain("click"); + const shots = html.match(/data-shots="([^"]+)"/); + expect(shots).not.toBeNull(); + expect(shots[1].split(";").length).toBeGreaterThanOrEqual(4); + expect(html).toContain("choreographAllCursors"); + expect(html).toContain("choreographAllCameras"); + + expect(html).toContain("pk-toast"); + expect(html).toContain('id="toastTitle"'); + expect(html).toContain('id="toastBody"'); + + expect(html).toContain("pk-outro"); + expect(html).toContain("roboco.tech"); + + expect(html).not.toMatch(/]+src="https?:\/\//); + expect(html).not.toMatch(/href="https?:\/\//); + // on-screen copy only; the document may carry an em dash as + // metadata (matches release-0.25.0's precedent) — it never renders. + const body = html.slice(html.indexOf("<body")); + expect(body).not.toMatch(/—/); + + // Card-beat gaps must be genuinely varied, not the metronomic identical + // 5.0s/5.0s/5.0s spacing the craft bar bans (a real prior revision cycle + // on this composition). + const cardDelays = [...html.matchAll(/class="pk-card" style="animation-delay: ([\d.]+)s;"/g)].map((m) => + parseFloat(m[1]), + ); + expect(cardDelays.length).toBe(4); + const gaps = cardDelays.slice(1).map((t, i) => Math.round((t - cardDelays[i]) * 100) / 100); + expect(new Set(gaps).size).toBeGreaterThan(1); + }); + + it("ships captions.json within X and TikTok platform limits", () => { + expect(existsSync(join(dir, "captions.json"))).toBe(true); + const captions = JSON.parse(read("captions.json")); + + expect(captions.composition_id).toBe("release-0.27.0"); + expect(captions.platforms.x.char_count).toBe(captions.platforms.x.caption.length); + expect(captions.platforms.x.char_count).toBeLessThanOrEqual(captions.platforms.x.limit); + expect(captions.platforms.x.within_limit).toBe(true); + expect(captions.platforms.tiktok.char_count).toBe(captions.platforms.tiktok.caption.length); + expect(captions.platforms.tiktok.char_count).toBeLessThanOrEqual(captions.platforms.tiktok.limit); + expect(captions.platforms.tiktok.within_limit).toBe(true); + + expect(captions.platforms.x.caption).not.toMatch(/—/); + expect(captions.platforms.tiktok.caption).not.toMatch(/—/); + }); +}); diff --git a/motion/compositions/release-0.27.0/square.html b/motion/compositions/release-0.27.0/square.html new file mode 100644 index 00000000..87b7a1f6 --- /dev/null +++ b/motion/compositions/release-0.27.0/square.html @@ -0,0 +1,353 @@ +<!doctype html> +<html lang="en" data-composition-id="release-0.27.0" data-composition-duration="40" data-fps="30"> + <head> + <meta charset="utf-8" /> + <title>RoboCo v0.27.0 Release - square (1080×1080) + + + + + + +
+ +
+
+ RoboCo +
+
+
v0.27.0
+
Four brains, zero bans
+
+ + +
+
+ + +
+ +
+
+ + Live +
+ CEO · Renzo +
+
+ +
+
+
New task
+
Four brains, zero bans
+
+ +
+
Shipped in v0.27.0
+ + +
+
WAF knows the real IP
+
Tailscale hops don't get banned anymore.
+
+ fastapi-guard +
+
+ in progress + completed +
+
+ +
+
Telegram Mini App V6
+
Real chat scopes, wallet-style metrics.
+
+ telegram +
+
+ in progress + completed +
+
+ +
+
Codex and Gemini join
+
Four model providers, one gateway now.
+
+ providers +
+
+ in progress + completed +
+
+ +
+
Cost-tiered routing
+
Save a routing mix, restore it anytime.
+
+ routing +
+
+ in progress + completed +
+
+
+ + +
+
+
+ +
+
1 release
+
4 providers
+
0 bans
+
+ +
+
+
+
v0.27.0 shipped
+
I approved once. 25 agents shipped it.
+
+
+ +
+ + roboco.tech +
+
+
+
+
+ + + + diff --git a/motion/compositions/release-0.27.0/vertical.html b/motion/compositions/release-0.27.0/vertical.html new file mode 100644 index 00000000..6c98e221 --- /dev/null +++ b/motion/compositions/release-0.27.0/vertical.html @@ -0,0 +1,379 @@ + + + + + RoboCo v0.27.0 Release - vertical (1080×1920) + + + + + + +
+ + +
+
+ RoboCo +
+
+
v0.27.0
+
Four brains, zero bans
+
+ + +
+
+ + +
+ +
+
+ + Live +
+ CEO · Renzo +
+
+ +
+ +
+
New task
+
Four brains, zero bans
+
+ + +
+
Shipped in v0.27.0
+ +
+
WAF knows the real IP
+
Tailscale hops don't get banned anymore.
+
+ fastapi-guard +
+
+ in progress + completed +
+
+ +
+
Telegram Mini App V6
+
Real chat scopes, wallet-style metrics.
+
+ telegram +
+
+ in progress + completed +
+
+ +
+
Codex and Gemini join
+
Four model providers, one gateway now.
+
+ providers +
+
+ in progress + completed +
+
+ +
+
Cost-tiered routing
+
Save a routing mix, restore it anytime.
+
+ routing +
+
+ in progress + completed +
+
+
+ + +
+
+
+ + +
+
1 release
+
4 providers
+
0 bans
+
+ + +
+
+
+
v0.27.0 shipped
+
I approved once. 25 agents shipped it.
+
+
+ +
+ + roboco.tech +
+
+
+
+
+ + + +