Files
roboco/motion/compositions/release-0.25.0/vertical.html
T
797847e379 [1dae04a7] Video: release 0.25.0 (revision) (#536)
* fix(release): CI wait polls the prod rung; escape the header tooltip apostrophe

get_latest_ci_conclusion defaults to the ladder's head rung, so
wait_for_ci searched slave for a release commit that lives on master
and timed out after 40 minutes with the run already green. The wait
now passes the prod branch explicitly. Also fixes the
react/no-unescaped-entities error that turned master's Panel CI red.

* fix(panel,video): dead dialog triggers behind tooltips; dotted composition ids render

HelpTip nested inside a Dialog/AlertDialog trigger puts the trigger's
click handler on the Tooltip root, which renders no DOM — the agents
Spawn item and the KB Reindex-All / Delete-index confirms were dead.
Tooltips now wrap the triggers. The video renderer accepts interior
single dots in composition ids (release-0.25.0) with '..' still
unrepresentable, and propose_video refuses an unrenderable id at
authoring time.

* fix(dispatch): restart-safe PM review turns

A leaf task in awaiting_pm_review had no periodic pickup: the closure
dispatcher bailed on childless tasks and skipped PR-bearing review
tasks as already-promoted, assuming the submit-time PM session was
still alive — an assumption every restart breaks. Proven live on the
docs-sync leaf after the 0.25.0 redeploy, which also dependency-blocked
its sibling dev task. Childless awaiting_pm_review tasks now flow to
the PM's review turn, and the merge turn respawns its PM when none is
active.

* [1dae04a7] Revise release-0.25.0 composition to 40s scene-based pacing with four feature cards

* [1dae04a7] docs(motion): update release-0.25.0 README section for 40s four-card revision

---------

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
Co-authored-by: UX/UI Developer 1 <ux-dev-1@roboco.tech>
Co-authored-by: UX/UI Documenter <ux-doc@roboco.tech>
2026-07-16 17:15:12 +02:00

344 lines
14 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="en" data-composition-id="release-0.25.0" data-composition-duration="40" data-fps="30">
<head>
<meta charset="utf-8" />
<title>RoboCo v0.25.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.25.0 release clip - panel-demo register. 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 -------------------------------------------- */
.r25-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: r25-hero-out 0.6s var(--pk-ease) 2.6s forwards;
}
@keyframes r25-hero-out { to { opacity: 0; visibility: hidden; } }
.r25-hero__markwrap { position: relative; width: 520px; height: 520px; }
.r25-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: r25-mark-in 1s var(--pk-ease) 0.2s forwards;
}
@keyframes r25-mark-in { to { transform: scale(1); opacity: 1; } }
.r25-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: r25-ring-in 0.3s linear 0.9s forwards, r25-ring-spin 1.4s cubic-bezier(0.5, 0, 0.3, 1) 0.9s forwards;
}
@keyframes r25-ring-in { to { opacity: 1; } }
@keyframes r25-ring-spin { to { transform: rotate(360deg); opacity: 0; } }
.r25-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;
}
.r25-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: r25-side-in 0.7s var(--pk-ease) 2.8s forwards;
}
@keyframes r25-side-in { to { transform: translateX(0); opacity: 1; } }
.r25-side__logo {
width: 44px;
height: 44px;
border-radius: 12px;
background: #f4f6f8;
display: flex;
align-items: center;
justify-content: center;
margin: 0 0 22px 4px;
}
.r25-side__logo img { width: 34px; height: 34px; }
.r25-nav {
display: flex;
align-items: center;
height: 52px;
padding: 0 16px;
border-radius: 10px;
font-size: 21px;
color: var(--pk-text-muted);
}
.r25-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; }
.r25-user {
display: flex;
align-items: center;
gap: 12px;
color: var(--pk-text-muted);
font-size: 20px;
}
.r25-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; }
.r25-sub {
margin-top: 10px;
font-size: 22px;
line-height: 1.35;
color: var(--pk-text-muted);
}
/* Receipt stats overlay. */
.r25-stats {
position: absolute;
right: 64px;
bottom: 320px;
text-align: right;
font-family: var(--pk-font-display);
}
.r25-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;
}
.r25-stats__line--accent { color: var(--pk-accent); }
.r25-stats { animation: r25-stats-out 0.5s var(--pk-ease) 32.0s forwards; }
@keyframes r25-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;
}
.r25-outro__logo {
width: 52px;
height: 52px;
border-radius: 14px;
background: #f4f6f8;
display: flex;
align-items: center;
justify-content: center;
}
.r25-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.25.0" data-width="1080" data-height="1920" data-start="0" data-duration="40" data-fps="30">
<!-- Beat 1: identity cold open. -->
<div class="r25-hero clip" data-start="0" data-duration="3.2" data-track-index="16">
<div class="r25-hero__markwrap">
<img class="r25-hero__mark" src="../../public/roboco-logo-darkmode.png" alt="RoboCo" />
<div class="r25-hero__ring"></div>
</div>
<div class="r25-hero__version">v0.25.0</div>
<div class="r25-hero__tag">governance gets a better UI</div>
</div>
<!-- Beat 2: the panel assembles. -->
<div class="pk-frame clip" data-start="2.6" data-duration="37.4" data-track-index="1">
<aside class="pk-frame__sidebar">
<div class="r25-side__logo"><img src="../../public/roboco-logo.png" alt="" /></div>
<div class="r25-nav">Overview</div>
<div class="r25-nav">Business</div>
<div class="r25-nav">Social</div>
<div class="r25-nav r25-nav--active">Tasks</div>
<div class="r25-nav">Kanban</div>
<div class="r25-nav">Git</div>
<div class="r25-nav">Agents</div>
<div class="r25-nav">Metrics</div>
</aside>
<header class="pk-frame__topbar">
<div class="pk-frame__search">Search tasks, agents...</div>
<div class="r25-user">
<div class="pk-frame__status clip" data-start="2.6" data-duration="37.4" data-track-index="0">
<span class="pk-frame__statusdot"></span>
<span>Live</span>
</div>
<span class="r25-user__chip">CEO · Renzo</span>
</div>
</header>
<div class="pk-frame__content">
<!-- Beat 3: the hook types into intake. -->
<div class="pk-intake clip" data-start="3.6" data-duration="36.4" data-track-index="2" style="animation-delay: 3.6s;">
<div class="pk-intake__label">New task</div>
<div class="pk-intake__field"><span id="typeIntro">Governance gets a better UI</span><span class="pk-caret"></span></div>
</div>
<!-- Beat 4: four feature cards, one per ~5s scene, each fully visible before the next enters. -->
<div class="pk-column">
<div class="pk-column__header">Shipped in v0.25.0</div>
<div class="pk-card clip" data-start="5.0" data-duration="35" data-track-index="3" style="animation-delay: 5.0s;">
<div class="pk-card__title">Env ladder</div>
<div class="r25-sub">Dev to prod, one rung at a time.</div>
<div class="pk-card__meta">
<span class="pk-chip pk-chip--gray">project settings</span>
</div>
<div class="pk-card__status">
<span class="pk-pill pk-pill--progress pk-pill--swap-out clip" data-start="5.0" data-duration="1.6" data-track-index="4" 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 clip" data-start="6.6" data-duration="33.4" data-track-index="5" style="--pk-pill-enter-delay: 6.6s;">completed</span>
</div>
</div>
<div class="pk-card clip" data-start="10.0" data-duration="30" data-track-index="6" style="animation-delay: 10.0s;">
<div class="pk-card__title">Collision map</div>
<div class="r25-sub">See who touched what before you review.</div>
<div class="pk-card__meta">
<span class="pk-chip pk-chip--gray">task detail</span>
</div>
<div class="pk-card__status">
<span class="pk-pill pk-pill--progress pk-pill--swap-out clip" data-start="10.0" data-duration="1.6" data-track-index="7" style="--pk-pill-enter-delay: 10.0s; --pk-pill-exit-delay: 11.4s;">in progress</span>
<span class="pk-pill pk-pill--completed pk-pill--swap-in clip" data-start="11.6" data-duration="28.4" data-track-index="8" style="--pk-pill-enter-delay: 11.6s;">completed</span>
</div>
</div>
<div class="pk-card clip" data-start="15.0" data-duration="25" data-track-index="9" style="animation-delay: 15.0s;">
<div class="pk-card__title">Metrics donut</div>
<div class="r25-sub">90 days of real task flow.</div>
<div class="pk-card__meta">
<span class="pk-chip pk-chip--gray">performance tab</span>
</div>
<div class="pk-card__status">
<span class="pk-pill pk-pill--progress pk-pill--swap-out clip" data-start="15.0" data-duration="1.6" data-track-index="10" style="--pk-pill-enter-delay: 15.0s; --pk-pill-exit-delay: 16.4s;">in progress</span>
<span class="pk-pill pk-pill--completed pk-pill--swap-in clip" data-start="16.6" data-duration="23.4" data-track-index="11" style="--pk-pill-enter-delay: 16.6s;">completed</span>
</div>
</div>
<div class="pk-card clip" data-start="20.0" data-duration="20" data-track-index="12" style="animation-delay: 20.0s;">
<div class="pk-card__title">Notification bell</div>
<div class="r25-sub">Real read/ack actions on every alert.</div>
<div class="pk-card__meta">
<span class="pk-chip pk-chip--gray">notifications</span>
</div>
<div class="pk-card__status">
<span class="pk-pill pk-pill--progress pk-pill--swap-out clip" data-start="20.0" data-duration="1.6" data-track-index="13" style="--pk-pill-enter-delay: 20.0s; --pk-pill-exit-delay: 21.4s;">in progress</span>
<span class="pk-pill pk-pill--completed pk-pill--swap-in clip" data-start="21.6" data-duration="18.4" data-track-index="14" style="--pk-pill-enter-delay: 21.6s;">completed</span>
</div>
</div>
</div>
<!-- Cursor glide to the newest card. -->
<div class="pk-cursor clip" data-start="22.0" data-duration="6" data-track-index="15" style="--pk-cursor-delay: 22.0s; --pk-cursor-x0: 720px; --pk-cursor-y0: 300px; --pk-cursor-x1: 200px; --pk-cursor-y1: 1090px;">
<div class="pk-cursor__glyph"></div>
<div class="pk-cursor__ring" style="--pk-click-delay: 23.4s;"></div>
</div>
<!-- Beat 5: receipt stats. -->
<div class="r25-stats clip" data-start="24.0" data-duration="8" data-track-index="17">
<div class="r25-stats__line" style="animation-delay: 24.0s;">1 release</div>
<div class="r25-stats__line r25-stats__line--accent" style="animation-delay: 24.3s;">25 agents</div>
<div class="r25-stats__line" style="animation-delay: 24.6s;">1 human</div>
</div>
<!-- Beat 6: confirmation toast, then lockup. -->
<div class="pk-toast clip" data-start="30.0" data-duration="8" data-track-index="18" style="animation-delay: 30.0s;">
<div class="pk-toast__icon"></div>
<div class="pk-toast__body">
<div class="pk-toast__title" id="toastTitle">v0.25.0 shipped</div>
<div class="pk-toast__text" id="toastBody">I approved once. 25 agents did the rest.</div>
</div>
</div>
<div class="pk-outro clip" data-start="36.0" data-duration="4" data-track-index="19" style="animation-delay: 36.0s;">
<span class="r25-outro__logo"><img src="../../public/roboco-logo.png" alt="" /></span>
<span>roboco.tech</span>
</div>
</div>
</div>
</div>
<script>
window.__timelines = window.__timelines || {};
window.__timelines["release-0.25.0"] = {
id: "release-0.25.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);
}
})();
</script>
</body>
</html>