mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
* [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 <ux-dev-1@roboco.tech> Co-authored-by: UX/UI Documenter <ux-doc@roboco.tech>
380 lines
15 KiB
HTML
380 lines
15 KiB
HTML
<!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 - vertical (1080×1920)</title>
|
||
<link rel="stylesheet" href="../../kit/kit.css" />
|
||
<script src="props.js"></script>
|
||
<script src="../../kit/kit.js"></script>
|
||
<style>
|
||
/* v0.27.0 release clip - panel-demo register, same shape as
|
||
release-0.26.0: identity cold open, panel assembles, four feature
|
||
cards flip to completed one per scene, cursor click, receipt
|
||
stats, toast, lockup. Total 40s. */
|
||
|
||
/* ---- Identity cold open -------------------------------------------- */
|
||
.r27-hero {
|
||
position: absolute;
|
||
inset: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 38px;
|
||
background: var(--pk-bg);
|
||
z-index: 30;
|
||
animation: r27-hero-out 0.6s var(--pk-ease) 2.6s forwards;
|
||
}
|
||
@keyframes r27-hero-out { to { opacity: 0; visibility: hidden; } }
|
||
|
||
.r27-hero__markwrap { position: relative; width: 520px; height: 520px; }
|
||
.r27-hero__mark {
|
||
width: 520px;
|
||
height: 520px;
|
||
transform: scale(0.82);
|
||
opacity: 0;
|
||
filter: drop-shadow(0 12px 60px rgba(255, 90, 31, 0.18));
|
||
animation: r27-mark-in 1s var(--pk-ease) 0.2s forwards;
|
||
}
|
||
@keyframes r27-mark-in { to { transform: scale(1); opacity: 1; } }
|
||
|
||
.r27-hero__ring {
|
||
position: absolute;
|
||
inset: 6px;
|
||
border-radius: 50%;
|
||
padding: 3px;
|
||
background: conic-gradient(from 0deg, transparent 0 78%, var(--pk-accent) 92%, transparent 100%);
|
||
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
|
||
-webkit-mask-composite: xor;
|
||
mask-composite: exclude;
|
||
opacity: 0;
|
||
animation: r27-ring-in 0.3s linear 0.9s forwards, r27-ring-spin 1.4s cubic-bezier(0.5, 0, 0.3, 1) 0.9s forwards;
|
||
}
|
||
@keyframes r27-ring-in { to { opacity: 1; } }
|
||
@keyframes r27-ring-spin { to { transform: rotate(360deg); opacity: 0; } }
|
||
|
||
.r27-hero__version {
|
||
font-family: var(--pk-font-display);
|
||
font-size: 120px;
|
||
color: var(--pk-text);
|
||
opacity: 0;
|
||
transform: translateY(18px);
|
||
animation: pk-enter-rise 0.7s var(--pk-ease) 1.2s forwards;
|
||
}
|
||
.r27-hero__tag {
|
||
font-size: 30px;
|
||
color: var(--pk-text-muted);
|
||
opacity: 0;
|
||
transform: translateY(14px);
|
||
animation: pk-enter-rise 0.7s var(--pk-ease) 1.5s forwards;
|
||
}
|
||
|
||
/* ---- Panel chrome --------------------------------------------------- */
|
||
.pk-frame { animation-delay: 2.6s; }
|
||
.pk-frame__sidebar {
|
||
width: 250px;
|
||
align-items: stretch;
|
||
gap: 6px;
|
||
padding: 28px 18px 0 18px;
|
||
transform: translateX(-40px);
|
||
opacity: 0;
|
||
animation: r27-side-in 0.7s var(--pk-ease) 2.8s forwards;
|
||
}
|
||
@keyframes r27-side-in { to { transform: translateX(0); opacity: 1; } }
|
||
|
||
.r27-side__logo {
|
||
width: 44px;
|
||
height: 44px;
|
||
border-radius: 12px;
|
||
background: #f4f6f8;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin: 0 0 22px 4px;
|
||
}
|
||
.r27-side__logo img { width: 34px; height: 34px; }
|
||
|
||
.r27-nav {
|
||
display: flex;
|
||
align-items: center;
|
||
height: 52px;
|
||
padding: 0 16px;
|
||
border-radius: 10px;
|
||
font-size: 21px;
|
||
color: var(--pk-text-muted);
|
||
}
|
||
.r27-nav--active { background: var(--pk-active-bg); color: var(--pk-active-fg); font-weight: 600; }
|
||
|
||
.pk-frame__topbar { left: 250px; }
|
||
.pk-frame__content { left: 250px; }
|
||
.r27-user {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
color: var(--pk-text-muted);
|
||
font-size: 20px;
|
||
}
|
||
.r27-user__chip {
|
||
background: var(--pk-surface-raised);
|
||
border: 1px solid var(--pk-border);
|
||
border-radius: 999px;
|
||
padding: 8px 18px;
|
||
color: var(--pk-text);
|
||
}
|
||
|
||
/* ---- Content placement --------------------------------------------- */
|
||
.pk-intake { --pk-intake-top: 32px; }
|
||
.pk-column { --pk-column-top: 220px; width: 720px; }
|
||
.pk-column .pk-card {
|
||
position: static;
|
||
margin-bottom: 20px;
|
||
/* Springy entrance with a hint of overshoot; a flat fade on every
|
||
card is the metronome that makes the cut feel like a slideshow. */
|
||
animation-duration: 0.55s;
|
||
animation-timing-function: cubic-bezier(0.34, 1.4, 0.64, 1);
|
||
}
|
||
.r27-sub {
|
||
margin-top: 10px;
|
||
font-size: 22px;
|
||
line-height: 1.35;
|
||
color: var(--pk-text-muted);
|
||
}
|
||
|
||
/* Receipt stats overlay. */
|
||
.r27-stats {
|
||
position: absolute;
|
||
right: 64px;
|
||
bottom: 320px;
|
||
text-align: right;
|
||
font-family: var(--pk-font-display);
|
||
}
|
||
.r27-stats__line {
|
||
font-size: 64px;
|
||
line-height: 1.22;
|
||
color: var(--pk-text);
|
||
opacity: 0;
|
||
transform: translateY(24px) scale(0.96);
|
||
animation: pk-enter-rise-scale 0.55s var(--pk-ease) forwards;
|
||
}
|
||
.r27-stats__line--accent { color: var(--pk-accent); }
|
||
.r27-stats { animation: r27-stats-out 0.5s var(--pk-ease) 33.0s forwards; }
|
||
@keyframes r27-stats-out { to { opacity: 0; } }
|
||
|
||
.pk-toast { --pk-toast-bottom: 140px; }
|
||
|
||
/* Closing lockup. */
|
||
.pk-outro {
|
||
--pk-outro-bottom: 56px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 20px;
|
||
}
|
||
.r27-outro__logo {
|
||
width: 52px;
|
||
height: 52px;
|
||
border-radius: 14px;
|
||
background: #f4f6f8;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
.r27-outro__logo img { width: 40px; height: 40px; }
|
||
|
||
#typeIntro { display: inline-block; overflow: hidden; white-space: pre; vertical-align: bottom; width: 0; }
|
||
@keyframes type-reveal { to { width: var(--type-ch, 20ch); } }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div id="stage" data-composition-id="release-0.27.0" data-width="1080" data-height="1920" data-start="0" data-duration="40" data-fps="30">
|
||
|
||
<!-- Beat 1: identity cold open. -->
|
||
<div class="r27-hero clip" data-start="0" data-duration="3.2" data-track-index="16">
|
||
<div class="r27-hero__markwrap">
|
||
<img class="r27-hero__mark" src="../../public/roboco-logo-darkmode.png" alt="RoboCo" />
|
||
<div class="r27-hero__ring"></div>
|
||
</div>
|
||
<div class="r27-hero__version">v0.27.0</div>
|
||
<div class="r27-hero__tag">Four brains, zero bans</div>
|
||
</div>
|
||
|
||
<!-- Beat 2: the panel assembles, and the camera lives on it: start a
|
||
touch tight, push toward each card as it completes, pull wide for
|
||
the receipt, ease onto the toast, settle for the lockup. -->
|
||
<div class="pk-camera"
|
||
data-shots="2.6 0 14 1.025; 4.8 0 8 1.03;
|
||
6.5 34 96 1.055; 9.6 30 88 1.05;
|
||
11.0 30 30 1.06; 15.1 26 24 1.055;
|
||
17.3 32 -52 1.065; 20.7 28 -58 1.06;
|
||
22.6 30 -150 1.065; 24.5 26 -156 1.06;
|
||
26.6 0 0 1.0; 30.3 0 0 1.0;
|
||
31.7 -26 -120 1.035; 34.0 -22 -116 1.03;
|
||
37.2 0 0 1.0; 39.6 0 6 1.005">
|
||
<div class="pk-frame clip" data-start="0" data-duration="40" data-track-index="1">
|
||
<aside class="pk-frame__sidebar">
|
||
<div class="r27-side__logo"><img src="../../public/roboco-logo.png" alt="" /></div>
|
||
<div class="r27-nav">Overview</div>
|
||
<div class="r27-nav">Business</div>
|
||
<div class="r27-nav">Social</div>
|
||
<div class="r27-nav r27-nav--active">Tasks</div>
|
||
<div class="r27-nav">Kanban</div>
|
||
<div class="r27-nav">Git</div>
|
||
<div class="r27-nav">Agents</div>
|
||
<div class="r27-nav">Metrics</div>
|
||
</aside>
|
||
|
||
<header class="pk-frame__topbar">
|
||
<div class="pk-frame__search">Search tasks, agents...</div>
|
||
<div class="r27-user">
|
||
<div class="pk-frame__status clip" data-start="0" data-duration="40" data-track-index="0">
|
||
<span class="pk-frame__statusdot"></span>
|
||
<span>Live</span>
|
||
</div>
|
||
<span class="r27-user__chip">CEO · Renzo</span>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="pk-frame__content">
|
||
<!-- Beat 3: the hook types into intake. -->
|
||
<div class="pk-intake" style="animation-delay: 3.6s;">
|
||
<div class="pk-intake__label">New task</div>
|
||
<div class="pk-intake__field"><span id="typeIntro">Four brains, zero bans</span><span class="pk-caret"></span></div>
|
||
</div>
|
||
|
||
<!-- Beat 4: four feature cards on varied beat spacing (5.5s/6.4s/5.3s
|
||
gaps, not the metronomic identical 5.0s the craft bar bans),
|
||
each fully visible before the next enters. -->
|
||
<div class="pk-column">
|
||
<div class="pk-column__header">Shipped in v0.27.0</div>
|
||
|
||
<div class="pk-card" style="animation-delay: 5.0s;">
|
||
<div class="pk-card__title">WAF knows the real IP</div>
|
||
<div class="r27-sub">Tailscale hops don't get banned anymore.</div>
|
||
<div class="pk-card__meta">
|
||
<span class="pk-chip pk-chip--gray">fastapi-guard</span>
|
||
</div>
|
||
<div class="pk-card__status">
|
||
<span class="pk-pill pk-pill--progress pk-pill--swap-out" style="--pk-pill-enter-delay: 5.0s; --pk-pill-exit-delay: 6.4s;">in progress</span>
|
||
<span class="pk-pill pk-pill--completed pk-pill--swap-in" style="--pk-pill-enter-delay: 6.6s;">completed</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="pk-card" style="animation-delay: 10.5s;">
|
||
<div class="pk-card__title">Telegram Mini App V6</div>
|
||
<div class="r27-sub">Real chat scopes, wallet-style metrics.</div>
|
||
<div class="pk-card__meta">
|
||
<span class="pk-chip pk-chip--gray">telegram</span>
|
||
</div>
|
||
<div class="pk-card__status">
|
||
<span class="pk-pill pk-pill--progress pk-pill--swap-out" style="--pk-pill-enter-delay: 10.5s; --pk-pill-exit-delay: 11.9s;">in progress</span>
|
||
<span class="pk-pill pk-pill--completed pk-pill--swap-in" style="--pk-pill-enter-delay: 12.1s;">completed</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="pk-card" style="animation-delay: 16.9s;">
|
||
<div class="pk-card__title">Codex and Gemini join</div>
|
||
<div class="r27-sub">Four model providers, one gateway now.</div>
|
||
<div class="pk-card__meta">
|
||
<span class="pk-chip pk-chip--gray">providers</span>
|
||
</div>
|
||
<div class="pk-card__status">
|
||
<span class="pk-pill pk-pill--progress pk-pill--swap-out" style="--pk-pill-enter-delay: 16.9s; --pk-pill-exit-delay: 18.3s;">in progress</span>
|
||
<span class="pk-pill pk-pill--completed pk-pill--swap-in" style="--pk-pill-enter-delay: 18.5s;">completed</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="pk-card" style="animation-delay: 22.2s;">
|
||
<div class="pk-card__title">Cost-tiered routing</div>
|
||
<div class="r27-sub">Save a routing mix, restore it anytime.</div>
|
||
<div class="pk-card__meta">
|
||
<span class="pk-chip pk-chip--gray">routing</span>
|
||
</div>
|
||
<div class="pk-card__status">
|
||
<span class="pk-pill pk-pill--progress pk-pill--swap-out" style="--pk-pill-enter-delay: 22.2s; --pk-pill-exit-delay: 23.6s;">in progress</span>
|
||
<span class="pk-pill pk-pill--completed pk-pill--swap-in" style="--pk-pill-enter-delay: 23.8s;">completed</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- The cursor is the CEO's hand: settle on the intake while it
|
||
types, ONE submit click just before the org takes over, then
|
||
travel to witness each card completing (the agents do the
|
||
clicking-free work), drift to the receipt, acknowledge the
|
||
toast, and leave the frame; never freeze, never blink out. -->
|
||
<div class="pk-cursor"
|
||
data-waypoints="4.0 640 210; 4.5 552 152; 4.8 545 148 click;
|
||
5.7 300 330; 6.5 160 405; 7.9 178 420;
|
||
10.1 260 520; 11.0 190 628; 13.1 172 642;
|
||
16.4 250 760; 17.3 162 848; 19.0 180 862;
|
||
21.8 255 985; 22.6 190 1068; 24.0 174 1082;
|
||
25.4 420 1180; 26.4 560 1250; 29.8 585 1268;
|
||
30.7 615 1420; 31.7 612 1462 click;
|
||
33.8 700 1520; 35.4 940 1660">
|
||
<div class="pk-cursor__glyph"></div>
|
||
</div>
|
||
|
||
<!-- Beat 5: receipt stats. -->
|
||
<div class="r27-stats">
|
||
<div class="r27-stats__line" style="animation-delay: 25.7s;">1 release</div>
|
||
<div class="r27-stats__line r27-stats__line--accent" style="animation-delay: 26.0s;">4 providers</div>
|
||
<div class="r27-stats__line" style="animation-delay: 26.3s;">0 bans</div>
|
||
</div>
|
||
|
||
<!-- Beat 6: confirmation toast, then lockup. -->
|
||
<div class="pk-toast" style="animation-delay: 31.0s;">
|
||
<div class="pk-toast__icon"></div>
|
||
<div class="pk-toast__body">
|
||
<div class="pk-toast__title" id="toastTitle">v0.27.0 shipped</div>
|
||
<div class="pk-toast__text" id="toastBody">I approved once. 25 agents shipped it.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="pk-outro" style="animation-delay: 36.3s;">
|
||
<span class="r27-outro__logo"><img src="../../public/roboco-logo.png" alt="" /></span>
|
||
<span>roboco.tech</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
window.__timelines = window.__timelines || {};
|
||
window.__timelines["release-0.27.0"] = {
|
||
id: "release-0.27.0",
|
||
duration: 40,
|
||
fps: 30,
|
||
animations: []
|
||
};
|
||
|
||
(function () {
|
||
var props = (window.__PROPS__ && typeof window.__PROPS__ === "object") ? window.__PROPS__ : {};
|
||
|
||
function setText(id, value) {
|
||
if (typeof value !== "string" || !value) return;
|
||
var el = document.getElementById(id);
|
||
if (el) el.textContent = value;
|
||
}
|
||
|
||
setText("toastTitle", props.toastTitle);
|
||
setText("toastBody", props.toastBody);
|
||
|
||
function typeReveal(el) {
|
||
var n = (el.textContent || "").length || 1;
|
||
el.style.setProperty("--type-ch", (n + 1) + "ch");
|
||
el.style.animation = "type-reveal " + (n * 0.07).toFixed(2) + "s steps(" + n + ", end) 4.0s forwards";
|
||
}
|
||
var typeEl = document.getElementById("typeIntro");
|
||
if (typeEl) {
|
||
if (typeof props.introText === "string" && props.introText) {
|
||
typeEl.textContent = props.introText;
|
||
}
|
||
typeReveal(typeEl);
|
||
}
|
||
|
||
window.PanelKit.choreographAllCursors();
|
||
window.PanelKit.choreographAllCameras();
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|