Files
f1a0b60c6c chore: unify product name display to OpenDesign repo-wide (#6998)
* chore: unify product name display to OpenDesign repo-wide

Rename the user-facing product name from "Open Design" to "OpenDesign"
across documentation, web/desktop UI strings, i18n locales, prompts,
plugin/skill/design-system content, changelogs, and specs, matching the
landing-page rename already in flight.

Deliberately excluded so installed-app identity stays untouched:
- packages/release PRODUCT_NAME and everything derived from it
  (app bundle names, installer/registry identity, updater feeds)
- tools/pack, tools/release, apps/packaged, landing page (PR #6983)
- mocks/ recorded traces and LICENSE
- test fixtures and comments that encode real on-disk install paths
  (Open Design.app, Program Files\Open Design, AppData paths)

Validated with pnpm guard, pnpm typecheck, and targeted web/desktop/host
test runs over the renamed strings.

* fix(web): keep two-letter author monogram for CamelCase brand names

authorInitials split words on whitespace only, so the renamed single-token
author name "OpenDesign" produced a one-letter monogram. Treat lower-to-upper
CamelCase boundaries as word breaks so the avatar fallback stays "OD".

* fix(release): restore spaced Windows source artifact names in win.ps1

tools/pack still derives builder outputs from the unchanged PRODUCT_NAME
("Open Design"), so the asset script must look for the spaced filenames.
Matches the mac/mac-intel/linux asset scripts, which were already kept on
the original names.

---------

Co-authored-by: Joey <236967869+joeylee12629-star@users.noreply.github.com>
2026-08-18 07:09:45 +00:00

949 lines
34 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Teach an AI CLI Workflow like a Developer-Tools Educator - AI literacy</title>
<!--
Terminal Mono — OpenDesign community deck plugin (ve-terminal-mono).
Based on nicobailon/visual-explainer slide-deck.html, Terminal Mono aesthetic
(references/slide-patterns.md). Developer-native, monospace-everything,
near-black ground, Dracula-green accent, faint dot grid. Zero skeuomorphism:
no prompt glyphs, no window chrome, no scanlines — typographic discipline only.
- All fonts Geist Mono; titles are large weight-400 mono, never bold display
- Dual theme via prefers-color-scheme (dark-first #0a0e14/#50fa7b,
light #f4f6f8/#0d7a3e) — the visual-explainer family signature
- Mermaid page replaced with a pure CSS/SVG pipeline diagram: zero external JS
- SlideEngine: keyboard/touch nav, progress bar, dots, counter, hints,
#/<n> hash routing with deep-link restore
-->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Geist+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
/* ============ THEME: Terminal Mono (dark-first) ============ */
:root {
--font-body: 'Geist Mono', 'SF Mono', Consolas, monospace;
--font-mono: 'Geist Mono', 'SF Mono', Consolas, monospace;
--bg: #0a0e14;
--surface: #12161e;
--surface2: #1a1f2a;
--surface-elevated: #222836;
--border: rgba(80, 250, 123, 0.06);
--border-bright: rgba(80, 250, 123, 0.12);
--text: #c8d6e5;
--text-dim: #7d8c9b;
--accent: #50fa7b;
--accent-dim: rgba(80, 250, 123, 0.08);
--code-bg: #060a10;
--code-text: #c8d6e5;
--dot: rgba(80, 250, 123, 0.05);
}
@media (prefers-color-scheme: light) {
:root {
--bg: #f4f6f8;
--surface: #ffffff;
--surface2: #eaecf0;
--surface-elevated: #f8f9fa;
--border: rgba(0, 80, 40, 0.08);
--border-bright: rgba(0, 80, 40, 0.16);
--text: #1a2332;
--text-dim: #5a6a7a;
--accent: #0d7a3e;
--accent-dim: rgba(13, 122, 62, 0.08);
--code-bg: #1a2332;
--code-text: #c8d6e5;
--dot: rgba(13, 122, 62, 0.07);
}
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: var(--font-body);
color: var(--text);
background: var(--bg);
overflow: hidden;
}
/* ============ DECK ENGINE ============ */
.deck {
height: 100dvh;
overflow-y: auto;
scroll-snap-type: y mandatory;
scroll-behavior: smooth;
-webkit-overflow-scrolling: touch;
}
.slide {
height: 100dvh;
scroll-snap-align: start;
overflow: hidden;
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
padding: clamp(40px, 6vh, 80px) clamp(40px, 8vw, 120px);
isolation: isolate;
opacity: 0;
transform: translateY(40px) scale(0.98);
transition:
opacity 0.6s cubic-bezier(0.16, 1, 0.3, 1),
transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
/* signature: faint dot grid on every slide */
background-image: radial-gradient(var(--dot) 1px, transparent 1px);
background-size: 24px 24px;
}
.slide.visible {
opacity: 1;
transform: none;
}
.slide .reveal {
opacity: 0;
transform: translateY(20px);
transition:
opacity 0.5s cubic-bezier(0.16, 1, 0.3, 1),
transform 0.5s cubic-bezier(0.16, 1, 0.3, 1);
}
.slide.visible .reveal { opacity: 1; transform: none; }
.slide.visible .reveal:nth-child(1) { transition-delay: 0.1s; }
.slide.visible .reveal:nth-child(2) { transition-delay: 0.2s; }
.slide.visible .reveal:nth-child(3) { transition-delay: 0.3s; }
.slide.visible .reveal:nth-child(4) { transition-delay: 0.4s; }
.slide.visible .reveal:nth-child(5) { transition-delay: 0.5s; }
.slide.visible .reveal:nth-child(6) { transition-delay: 0.6s; }
@media (prefers-reduced-motion: reduce) {
.deck { scroll-behavior: auto; }
.slide, .slide .reveal {
opacity: 1 !important;
transform: none !important;
transition: none !important;
}
.deck-progress, .deck-dot, .deck-hints, .data-table tbody tr {
transition: none !important;
}
}
/* ============ NAV CHROME ============ */
.deck-progress {
position: fixed; top: 0; left: 0; height: 2px;
background: var(--accent); z-index: 100;
transition: width 0.3s ease; pointer-events: none;
}
.deck-dots {
position: fixed; right: clamp(12px, 2vw, 24px); top: 50%;
transform: translateY(-50%); display: flex; flex-direction: column;
gap: 8px; z-index: 100; padding: 8px;
background: color-mix(in srgb, var(--bg) 60%, transparent 40%);
border: 1px solid var(--border);
border-radius: 2px;
backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
}
.deck-dot {
width: 8px; height: 8px; border-radius: 0;
background: var(--text-dim); opacity: 0.3; border: none; padding: 0;
cursor: pointer; transition: opacity 0.2s ease, transform 0.2s ease;
}
.deck-dot:hover { opacity: 0.6; }
.deck-dot.active { opacity: 1; transform: scale(1.4); background: var(--accent); }
.deck-counter {
position: fixed; bottom: clamp(12px, 2vh, 24px); right: clamp(12px, 2vw, 24px);
font-family: var(--font-mono); font-size: 12px; color: var(--text-dim);
z-index: 100; font-variant-numeric: tabular-nums;
letter-spacing: 1px;
}
.deck-hints {
position: fixed; bottom: clamp(12px, 2vh, 24px); left: 50%;
transform: translateX(-50%); font-family: var(--font-mono);
font-size: 11px; color: var(--text-dim); opacity: 1; z-index: 100;
transition: opacity 0.5s ease; white-space: nowrap;
}
.deck-hints.faded { opacity: 0; pointer-events: none; }
/* ============ SHARED SLIDE ELEMENTS ============ */
/* Mono discipline: titles are large weight-400 mono, never bold display. */
.slide__display {
font-size: clamp(36px, 7vw, 88px);
font-weight: 400;
letter-spacing: -2px;
line-height: 1.05;
text-wrap: balance;
}
.slide__heading {
font-size: clamp(24px, 4vw, 42px);
font-weight: 400;
letter-spacing: -1px;
line-height: 1.2;
text-wrap: balance;
}
.slide__body {
font-size: clamp(15px, 2vw, 20px);
line-height: 1.65;
color: var(--text-dim);
text-wrap: pretty;
}
.slide__subtitle {
font-family: var(--font-mono);
font-size: clamp(12px, 1.4vw, 16px);
font-weight: 400;
color: var(--text-dim);
letter-spacing: 1px;
text-transform: uppercase;
}
.slide__label {
font-family: var(--font-mono);
font-size: clamp(10px, 1.2vw, 13px);
font-weight: 600;
text-transform: uppercase;
letter-spacing: 2px;
color: var(--accent);
margin-bottom: 12px;
}
/* ============ DECORATIVE (restrained: corner brackets only) ============ */
.slide__decor {
position: absolute;
pointer-events: none;
z-index: 0;
}
/* ============ SLIDE TYPE: TITLE ============ */
.slide--title {
justify-content: center;
align-items: center;
text-align: center;
}
.slide--title .slide__display { color: var(--accent); }
/* ============ SLIDE TYPE: DIVIDER ============ */
.slide--divider { justify-content: center; }
.slide--divider .slide__number {
font-size: clamp(100px, 22vw, 260px);
font-weight: 400;
line-height: 0.85;
opacity: 0.05;
position: absolute;
top: 50%; left: 50%;
transform: translate(-50%, -55%);
pointer-events: none;
font-variant-numeric: tabular-nums;
color: var(--accent);
}
/* ============ SLIDE TYPE: CONTENT ============ */
.slide--content .slide__inner {
display: grid;
grid-template-columns: 3fr 2fr;
gap: clamp(24px, 4vw, 60px);
align-items: center;
width: 100%;
}
.slide__bullets {
list-style: none;
padding: 0;
}
.slide__bullets li {
padding: 10px 0 10px 26px;
position: relative;
font-size: clamp(15px, 1.9vw, 20px);
line-height: 1.55;
color: var(--text-dim);
}
/* square tick, not round — no softness */
.slide__bullets li::before {
content: '';
position: absolute;
left: 0; top: 19px;
width: 7px; height: 7px;
background: var(--accent);
}
.slide__aside {
display: flex;
align-items: center;
justify-content: center;
min-height: 200px;
}
/* ============ SLIDE TYPE: SPLIT ============ */
.slide--split { padding: 0; background-image: none; }
.slide--split .slide__panels {
display: grid;
grid-template-columns: 1fr 1fr;
height: 100%;
}
.slide--split .slide__panel {
padding: clamp(40px, 6vh, 80px) clamp(32px, 4vw, 60px);
display: flex;
flex-direction: column;
justify-content: center;
background-image: radial-gradient(var(--dot) 1px, transparent 1px);
background-size: 24px 24px;
}
.slide--split .slide__panel--primary { background-color: var(--surface); }
.slide--split .slide__panel--secondary {
background-color: var(--surface2);
border-left: 1px solid var(--border-bright);
}
/* ============ SLIDE TYPE: DIAGRAM (pure CSS pipeline) ============ */
.slide--diagram {
padding: clamp(24px, 4vh, 48px) clamp(24px, 4vw, 60px);
}
.slide--diagram .slide__heading { margin-bottom: clamp(8px, 1.5vh, 20px); }
.pipeline-wrap {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 2px;
padding: clamp(20px, 4vh, 40px) clamp(16px, 3vw, 40px);
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
justify-content: center;
gap: clamp(20px, 4vh, 40px);
background-image: radial-gradient(var(--dot) 1px, transparent 1px);
background-size: 24px 24px;
}
.pipeline-row {
display: flex;
align-items: stretch;
justify-content: center;
gap: 0;
}
.pipe-node {
background: var(--surface2);
border: 1px solid var(--border-bright);
border-radius: 2px;
padding: clamp(12px, 2vh, 20px) clamp(12px, 1.6vw, 22px);
min-width: clamp(110px, 14vw, 170px);
text-align: center;
display: flex;
flex-direction: column;
justify-content: center;
gap: 6px;
}
.pipe-node--accent {
border-color: var(--accent);
background: var(--accent-dim);
}
.pipe-node__name {
font-size: clamp(13px, 1.5vw, 17px);
font-weight: 500;
color: var(--text);
}
.pipe-node--accent .pipe-node__name { color: var(--accent); }
.pipe-node__meta {
font-size: clamp(9px, 1vw, 12px);
letter-spacing: 1px;
text-transform: uppercase;
color: var(--text-dim);
}
.pipe-link {
display: flex;
align-items: center;
padding: 0 2px;
flex: 0 1 clamp(24px, 4vw, 64px);
min-width: 20px;
}
/* labeled connectors get more run so edge labels clear the node boxes */
.pipe-link:has(.pipe-link__label) {
flex: 0 1 clamp(72px, 9vw, 128px);
min-width: 56px;
}
.pipe-link__line {
width: 100%;
height: 1px;
background: var(--border-bright);
position: relative;
}
.pipe-link__line::after {
content: '';
position: absolute;
right: 0; top: -3px;
border-left: 6px solid var(--text-dim);
border-top: 3.5px solid transparent;
border-bottom: 3.5px solid transparent;
}
.pipe-link--dashed .pipe-link__line {
background: none;
border-top: 1px dashed var(--border-bright);
height: 0;
}
.pipe-link__label {
position: absolute;
top: -22px; left: 50%;
transform: translateX(-50%);
font-size: clamp(8px, 0.9vw, 11px);
letter-spacing: 1px;
text-transform: uppercase;
color: var(--text-dim);
white-space: nowrap;
}
.pipeline-legend {
display: flex;
justify-content: center;
gap: clamp(16px, 3vw, 40px);
font-size: clamp(9px, 1vw, 12px);
letter-spacing: 1px;
text-transform: uppercase;
color: var(--text-dim);
}
.pipeline-legend .key {
display: inline-block;
width: 8px; height: 8px;
margin-right: 8px;
vertical-align: baseline;
}
.pipeline-legend .key--accent { background: var(--accent); }
.pipeline-legend .key--plain { border: 1px solid var(--border-bright); }
/* ============ SLIDE TYPE: DASHBOARD ============ */
.slide--dashboard .slide__kpis {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(clamp(140px, 20vw, 220px), 1fr));
gap: clamp(12px, 2vw, 24px);
margin-top: clamp(12px, 2vh, 28px);
}
.slide__kpi {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 2px;
padding: clamp(16px, 3vh, 32px) clamp(16px, 2vw, 24px);
min-width: 0;
overflow: hidden;
}
.slide__kpi-val {
font-size: clamp(30px, 5vw, 56px);
font-weight: 400;
letter-spacing: -1.5px;
line-height: 1.1;
font-variant-numeric: tabular-nums;
white-space: nowrap;
}
.slide__kpi-label {
font-family: var(--font-mono);
font-size: clamp(9px, 1.2vw, 13px);
font-weight: 600;
text-transform: uppercase;
letter-spacing: 1.5px;
color: var(--text-dim);
margin-top: 8px;
}
.slide__kpi-trend {
font-family: var(--font-mono);
font-size: 12px;
margin-top: 4px;
color: var(--text-dim);
}
/* ============ SLIDE TYPE: TABLE ============ */
.slide--table { padding: clamp(24px, 4vh, 48px) clamp(24px, 4vw, 60px); }
.table-wrap {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 2px;
overflow: hidden;
flex: 1;
min-height: 0;
}
.table-scroll { overflow-x: auto; }
.data-table { width: 100%; border-collapse: collapse; }
.data-table th {
background: var(--surface2);
font-family: var(--font-mono);
font-size: clamp(10px, 1.3vw, 14px);
font-weight: 600;
text-transform: uppercase;
letter-spacing: 1px;
color: var(--text-dim);
text-align: left;
padding: clamp(10px, 1.5vh, 16px) clamp(14px, 2vw, 24px);
border-bottom: 1px solid var(--border-bright);
white-space: nowrap;
}
.data-table td {
padding: clamp(10px, 1.5vh, 16px) clamp(14px, 2vw, 24px);
border-bottom: 1px solid var(--border);
font-size: clamp(13px, 1.7vw, 18px);
vertical-align: top;
}
.data-table tbody tr:last-child td { border-bottom: none; }
.data-table tbody tr:nth-child(even) { background: var(--surface2); }
.data-table tbody tr { transition: background 0.15s; }
.data-table tbody tr:hover { background: var(--accent-dim); }
.data-table code {
font-family: var(--font-mono); font-size: 0.85em;
background: var(--accent-dim); color: var(--accent);
padding: 1px 5px; border-radius: 2px;
}
/* ============ SLIDE TYPE: CODE ============ */
.slide--code { align-items: center; }
.slide__code-block {
background: var(--code-bg);
border: 1px solid var(--border-bright);
border-radius: 2px;
padding: clamp(24px, 4vh, 48px) clamp(24px, 4vw, 48px);
max-width: 900px;
width: 100%;
position: relative;
}
.slide__code-filename {
position: absolute;
top: -12px; left: 24px;
font-family: var(--font-mono);
font-size: 11px; font-weight: 600;
letter-spacing: 1px;
padding: 4px 12px; border-radius: 2px;
background: var(--accent); color: var(--bg);
}
@media (prefers-color-scheme: light) {
.slide__code-filename { color: #f4f6f8; }
}
.slide__code-block pre { margin: 0; overflow-x: auto; }
.slide__code-block code {
font-family: var(--font-mono);
font-size: clamp(13px, 1.5vw, 17px);
line-height: 1.7;
color: var(--code-text);
}
.slide__code-block .hl { color: var(--accent); }
.slide__code-block .cm { color: var(--text-dim); }
@media (prefers-color-scheme: light) {
.slide__code-block .hl { color: #50fa7b; }
/* code stays dark in light mode; comments keep the dark-theme dim tone for AA contrast */
.slide__code-block .cm { color: #7d8c9b; }
}
/* ============ SLIDE TYPE: QUOTE ============ */
.slide--quote {
justify-content: center;
align-items: center;
text-align: center;
padding: clamp(60px, 10vh, 120px) clamp(60px, 12vw, 200px);
}
.slide__quote-mark {
font-size: clamp(60px, 10vw, 140px);
line-height: 0.6;
opacity: 0.08;
font-family: var(--font-mono);
pointer-events: none;
margin-bottom: -10px;
color: var(--accent);
}
.slide--quote blockquote {
font-size: clamp(20px, 3.4vw, 40px);
font-weight: 400;
line-height: 1.4;
letter-spacing: -0.5px;
}
.slide--quote cite {
font-family: var(--font-mono);
font-size: clamp(11px, 1.4vw, 14px);
font-style: normal;
margin-top: clamp(16px, 3vh, 32px);
display: block;
letter-spacing: 1.5px;
text-transform: uppercase;
color: var(--text-dim);
}
/* ============ SLIDE TYPE: CLOSING ============ */
.slide--closing {
justify-content: center;
align-items: flex-start;
border-top: 1px solid var(--border-bright);
}
.slide--closing .slide__display {
font-size: clamp(32px, 5.5vw, 72px);
}
.slide--closing .slide__display em {
font-style: normal;
color: var(--accent);
}
/* ============ RESPONSIVE ============ */
@media (max-height: 700px) {
.slide { padding: clamp(24px, 4vh, 40px) clamp(32px, 6vw, 80px); }
.slide__display { font-size: clamp(30px, 6vw, 60px); }
.slide--divider .slide__number { font-size: clamp(80px, 16vw, 160px); }
}
@media (max-height: 600px) {
.slide__decor { display: none; }
.slide--quote { padding: clamp(32px, 6vh, 60px) clamp(40px, 8vw, 100px); }
.slide__quote-mark { display: none; }
}
@media (max-height: 500px) {
.slide { padding: clamp(16px, 3vh, 24px) clamp(24px, 5vw, 48px); }
.deck-dots { display: none; }
.slide__display { font-size: clamp(24px, 6vw, 40px); }
}
@media (max-width: 768px) {
.slide--content .slide__inner { grid-template-columns: 1fr; }
.slide--content .slide__aside { display: none; }
.slide--split .slide__panels { grid-template-columns: 1fr; }
.slide--split .slide__panel--secondary { border-left: none; border-top: 1px solid var(--border-bright); }
.slide--dashboard .slide__kpis { grid-template-columns: repeat(2, 1fr); }
.pipeline-row { flex-wrap: wrap; gap: 12px; }
.pipe-link { display: none; }
}
</style>
<style id="od-no-pager">.deck-controls,#counter,.deck-counter{display:none!important}</style>
</head>
<body>
<div class="deck">
<!-- SLIDE 1: TITLE -->
<section class="slide slide--title">
<svg class="slide__decor" style="top:0;right:0;" width="120" height="120" viewBox="0 0 120 120">
<line x1="120" y1="0" x2="120" y2="40" stroke="var(--accent)" stroke-width="1.5" opacity="0.25"/>
<line x1="80" y1="0" x2="120" y2="0" stroke="var(--accent)" stroke-width="1.5" opacity="0.25"/>
</svg>
<svg class="slide__decor" style="bottom:0;left:0;" width="120" height="120" viewBox="0 0 120 120">
<line x1="0" y1="80" x2="0" y2="120" stroke="var(--accent)" stroke-width="1.5" opacity="0.25"/>
<line x1="0" y1="120" x2="40" y2="120" stroke="var(--accent)" stroke-width="1.5" opacity="0.25"/>
</svg>
<div class="reveal">
<p class="slide__subtitle" style="margin-bottom:clamp(16px,2vh,32px);">AI Literacy &middot; CLI Curriculum &middot; For Engineering Teams</p>
</div>
<h1 class="slide__display reveal">Teach the <code style="font-family:inherit;">od</code> Workflow</h1>
<div class="reveal">
<p class="slide__subtitle" style="margin-top:clamp(16px,2vh,32px);">OpenDesign from the command line &mdash; scripted, composable, agent-ready</p>
</div>
</section>
<!-- SLIDE 2: SECTION DIVIDER -->
<section class="slide slide--divider">
<span class="slide__number">01</span>
<div>
<h2 class="slide__heading reveal">Why Now</h2>
<p class="slide__subtitle reveal" style="margin-top:12px;">Design is the last unscripted tool left in the stack</p>
</div>
</section>
<!-- SLIDE 3: CONTENT (left-heavy asymmetric) -->
<section class="slide slide--content">
<div class="slide__inner">
<div>
<p class="slide__label reveal">Q3 2026 training backlog</p>
<h2 class="slide__heading reveal">Engineers Already Script Everything Else</h2>
<ul class="slide__bullets">
<li class="reveal">Deploys, migrations, and CI all run from the terminal &mdash; design still means a mouse and a shared Figma seat</li>
<li class="reveal">New hires ask why there's a <code>git</code> for code but no equivalent for design work</li>
<li class="reveal">Agent-native CLIs (Claude Code, Codex, Cursor) already live in every engineer's shell today</li>
<li class="reveal">No onboarding path teaches design as a scriptable, agent-driven step in the pipeline</li>
</ul>
</div>
<div class="slide__aside reveal">
<svg viewBox="0 0 160 160" width="160" height="160">
<rect x="20" y="20" width="120" height="120" fill="none" stroke="var(--accent)" stroke-width="1" opacity="0.3"/>
<rect x="40" y="40" width="80" height="80" fill="none" stroke="var(--accent)" stroke-width="1" opacity="0.2" stroke-dasharray="4 4"/>
<rect x="74" y="74" width="12" height="12" fill="var(--accent)" opacity="0.5"/>
<text x="80" y="150" text-anchor="middle" font-family="Geist Mono, monospace" font-size="10" letter-spacing="1" fill="var(--text-dim)">GUI-ONLY</text>
</svg>
</div>
</div>
</section>
<!-- SLIDE 4: SPLIT (before/after) -->
<section class="slide slide--split">
<div class="slide__panels">
<div class="slide__panel slide__panel--primary">
<p class="slide__label reveal" style="color:var(--text-dim);">Before &mdash; GUI Habit</p>
<h2 class="slide__heading reveal" style="font-size:clamp(20px,3vw,32px);">One Designer, One Screen</h2>
<ul class="slide__bullets" style="margin-top:16px;">
<li class="reveal">Every request queues behind a single Figma seat</li>
<li class="reveal">No way to template or script a repeat layout</li>
<li class="reveal">Handoff means screenshots dropped in Slack</li>
<li class="reveal">No audit trail of who changed what, or when</li>
</ul>
</div>
<div class="slide__panel slide__panel--secondary">
<p class="slide__label reveal">Pilot &mdash; Week 1&ndash;6</p>
<h2 class="slide__heading reveal" style="font-size:clamp(20px,3vw,32px);">Any Engineer, One Command</h2>
<ul class="slide__bullets" style="margin-top:16px;">
<li class="reveal">14 engineers ran <code>od project create</code> in week one, zero onboarding tickets</li>
<li class="reveal">Design specs live as git-diffable files, reviewed in normal PRs</li>
<li class="reveal"><code>od plugin apply</code> scripts a full page from a design system in under 90s</li>
<li class="reveal">Full shell history doubles as the change-audit trail</li>
</ul>
</div>
</div>
</section>
<!-- SLIDE 5: SECTION DIVIDER -->
<section class="slide slide--divider">
<span class="slide__number">02</span>
<div>
<h2 class="slide__heading reveal">The Workflow Map</h2>
<p class="slide__subtitle reveal" style="margin-top:12px;">Five commands, one continuous loop</p>
</div>
</section>
<!-- SLIDE 6: DIAGRAM (pure CSS/SVG pipeline — no mermaid, no external JS) -->
<section class="slide slide--diagram">
<h2 class="slide__heading reveal">Five Commands, One Loop</h2>
<div class="pipeline-wrap reveal">
<div class="pipeline-row">
<div class="pipe-node">
<div class="pipe-node__name">od init</div>
<div class="pipe-node__meta">new project</div>
</div>
<div class="pipe-link"><div class="pipe-link__line"></div></div>
<div class="pipe-node">
<div class="pipe-node__name">od design</div>
<div class="pipe-node__meta">import system</div>
</div>
<div class="pipe-link"><div class="pipe-link__line"><span class="pipe-link__label">design system</span></div></div>
<div class="pipe-node pipe-node--accent">
<div class="pipe-node__name">od agent</div>
<div class="pipe-node__meta">run task</div>
</div>
<div class="pipe-link"><div class="pipe-link__line"><span class="pipe-link__label">sandbox</span></div></div>
<div class="pipe-node">
<div class="pipe-node__name">od export</div>
<div class="pipe-node__meta">ship files</div>
</div>
</div>
<div class="pipeline-row">
<div class="pipe-node">
<div class="pipe-node__name">od plugin</div>
<div class="pipe-node__meta">apply template</div>
</div>
<div class="pipe-link pipe-link--dashed"><div class="pipe-link__line"><span class="pipe-link__label">or preview</span></div></div>
<div class="pipe-node">
<div class="pipe-node__name">od preview</div>
<div class="pipe-node__meta">html &rarr; live</div>
</div>
<div class="pipe-link"><div class="pipe-link__line"></div></div>
<div class="pipe-node pipe-node--accent">
<div class="pipe-node__name">od skill</div>
<div class="pipe-node__meta">learns style</div>
</div>
<div class="pipe-link"><div class="pipe-link__line"></div></div>
<div class="pipe-node">
<div class="pipe-node__name">next run</div>
<div class="pipe-node__meta">more precise</div>
</div>
</div>
<div class="pipeline-legend">
<span><span class="key key--accent"></span>learns your taste</span>
<span><span class="key key--plain"></span>workflow stage</span>
</div>
</div>
</section>
<!-- SLIDE 7: DASHBOARD -->
<section class="slide slide--dashboard">
<h2 class="slide__heading reveal">Pilot Results, Six Weeks In</h2>
<div class="slide__kpis">
<div class="slide__kpi reveal">
<div class="slide__kpi-val" style="color:var(--accent);">14</div>
<div class="slide__kpi-label">Engineers Onboarded</div>
<div class="slide__kpi-trend">zero design-tool tickets filed</div>
</div>
<div class="slide__kpi reveal">
<div class="slide__kpi-val" style="color:var(--accent);">38</div>
<div class="slide__kpi-label">Pages Shipped via CLI</div>
<div class="slide__kpi-trend">reviewed in PRs, not Slack</div>
</div>
<div class="slide__kpi reveal">
<div class="slide__kpi-val">6 min</div>
<div class="slide__kpi-label">Median Cycle Time</div>
<div class="slide__kpi-trend">prompt to merged PR</div>
</div>
<div class="slide__kpi reveal">
<div class="slide__kpi-val">-71%</div>
<div class="slide__kpi-label">Design Backlog</div>
<div class="slide__kpi-trend">queue length, week 1 &rarr; week 6</div>
</div>
</div>
</section>
<!-- SLIDE 8: TABLE -->
<section class="slide slide--table">
<h2 class="slide__heading reveal">Guardrails Before Rollout</h2>
<div class="table-wrap reveal" style="flex:1; min-height:0; margin-top:clamp(8px,1.5vh,20px);">
<div class="table-scroll">
<table class="data-table">
<thead><tr><th>Control</th><th>Detail</th><th>Surface</th><th>Status</th></tr></thead>
<tbody>
<tr><td>Sandboxed runs</td><td>Agent writes only inside the project workspace, never the host</td><td><code>sandbox</code></td><td style="color:var(--accent);">shipped</td></tr>
<tr><td>BYOK keys</td><td>Each engineer's provider key stays in their local env, never centralized</td><td><code>byok</code></td><td style="color:var(--accent);">shipped</td></tr>
<tr><td>Git-diffable output</td><td>Every generated file reviewable in a normal pull request</td><td><code>diff</code></td><td style="color:var(--accent);">shipped</td></tr>
<tr><td>Command allowlist</td><td><code>od</code> subcommands scoped per role through CI policy</td><td><code>policy</code></td><td style="color:var(--accent);">shipped</td></tr>
<tr><td>Local-first data</td><td>No design content leaves the laptop unless explicitly exported</td><td><code>local</code></td><td style="color:var(--accent);">shipped</td></tr>
<tr><td>Rollback via git</td><td>A bad agent run reverts with a plain <code>git checkout</code></td><td><code>rollback</code></td><td style="color:var(--text-dim);">evolving</td></tr>
</tbody>
</table>
</div>
</div>
</section>
<!-- SLIDE 9: CODE -->
<section class="slide slide--code">
<h2 class="slide__heading reveal" style="text-align:center;">The Five Commands to Teach First</h2>
<div class="slide__code-block reveal" style="margin-top:clamp(12px,2vh,24px);">
<span class="slide__code-filename">od-101.md</span>
<pre><code><span class="hl">[week 1]</span>
init = <span class="hl">"od project create &lt;name&gt;"</span> <span class="cm"># first command every hire runs</span>
import = <span class="hl">"od design import &lt;repo&gt;"</span>
<span class="hl">[week 2]</span>
run = <span class="hl">"od agent run --prompt-file brief.md"</span> <span class="cm"># --json pipes into CI</span>
apply = <span class="hl">"od plugin apply &lt;template&gt;"</span>
<span class="hl">[week 3]</span>
ship = <span class="hl">"od file export --to ./dist"</span> <span class="cm"># git-diffable, PR-ready</span></code></pre>
</div>
</section>
<!-- SLIDE 10: QUOTE -->
<section class="slide slide--quote">
<div class="slide__quote-mark reveal">&gt;</div>
<blockquote class="reveal">
The moment <code style="font-family:inherit;">od agent run --json</code> piped cleanly into our CI, design stopped being the one GUI-shaped exception in an otherwise scripted stack.
</blockquote>
<cite class="reveal">&mdash; Staff engineer, pilot cohort</cite>
</section>
<!-- SLIDE 11: CLOSING -->
<section class="slide slide--closing">
<svg class="slide__decor" style="top:0;right:0;" width="120" height="120" viewBox="0 0 120 120">
<line x1="120" y1="0" x2="120" y2="40" stroke="var(--accent)" stroke-width="1.5" opacity="0.25"/>
<line x1="80" y1="0" x2="120" y2="0" stroke="var(--accent)" stroke-width="1.5" opacity="0.25"/>
</svg>
<p class="slide__label reveal">Rollout &middot; Weeks 7&ndash;12</p>
<h2 class="slide__display reveal">Ship the curriculum,<br><em>not just the tool.</em></h2>
<p class="slide__subtitle reveal" style="margin-top:clamp(16px,2vh,32px);">Week 7: guild office hours &mdash; Week 9: <code style="font-family:inherit;">od</code> added to onboarding checklist &mdash; Week 12: org-wide, CLI-first</p>
</section>
</div><!-- /deck -->
<script>
// SlideEngine — keyboard/touch nav, progress bar, dots, counter, hints,
// and #/<n> hash routing. No external dependencies.
function SlideEngine(){
this.deck=document.querySelector('.deck');
this.slides=[].slice.call(document.querySelectorAll('.slide'));
this.current=0;
this.total=this.slides.length;
this.buildChrome();
this.bindEvents();
this.observe();
this.restoreHash();
this.update();
}
SlideEngine.prototype.buildChrome=function(){
var bar=document.createElement('div');bar.className='deck-progress';document.body.appendChild(bar);this.bar=bar;
var dots=document.createElement('div');dots.className='deck-dots';var self=this;
this.slides.forEach(function(_,i){var d=document.createElement('button');d.className='deck-dot';d.title='Slide '+(i+1);d.onclick=function(){self.goTo(i);};dots.appendChild(d);});
document.body.appendChild(dots);this.dots=[].slice.call(dots.children);
var ctr=document.createElement('div');ctr.className='deck-counter';document.body.appendChild(ctr);this.counter=ctr;
var hints=document.createElement('div');hints.className='deck-hints';hints.textContent='← → or scroll to navigate';document.body.appendChild(hints);this.hints=hints;
this.hintTimer=setTimeout(function(){hints.classList.add('faded');},4000);
};
SlideEngine.prototype.bindEvents=function(){
var self=this;
document.addEventListener('keydown',function(e){
if(e.target.closest('.table-scroll,.code-scroll,input,textarea,[contenteditable]'))return;
if(['ArrowDown','ArrowRight',' ','PageDown'].indexOf(e.key)>-1){e.preventDefault();self.next();}
else if(['ArrowUp','ArrowLeft','PageUp'].indexOf(e.key)>-1){e.preventDefault();self.prev();}
else if(e.key==='Home'){e.preventDefault();self.goTo(0);}
else if(e.key==='End'){e.preventDefault();self.goTo(self.total-1);}
self.fadeHints();
});
var tY;
this.deck.addEventListener('touchstart',function(e){tY=e.touches[0].clientY;},{passive:true});
this.deck.addEventListener('touchend',function(e){var dy=tY-e.changedTouches[0].clientY;if(Math.abs(dy)>50){dy>0?self.next():self.prev();}});
window.addEventListener('hashchange',function(){
var idx=self.parseHash();
if(idx!==null&&idx!==self.current)self.goTo(idx);
});
};
SlideEngine.prototype.observe=function(){
var self=this;
var obs=new IntersectionObserver(function(entries){entries.forEach(function(entry){if(entry.isIntersecting){entry.target.classList.add('visible');self.current=self.slides.indexOf(entry.target);self.update();}});},{threshold:0.5});
this.slides.forEach(function(s){obs.observe(s);});
};
SlideEngine.prototype.parseHash=function(){
var m=location.hash.match(/^#\/(\d+)$/);
if(!m)return null;
var idx=parseInt(m[1],10)-1;
if(isNaN(idx)||idx<0||idx>=this.total)return null;
return idx;
};
SlideEngine.prototype.restoreHash=function(){
var idx=this.parseHash();
if(idx!==null&&idx>0){
var self=this;
setTimeout(function(){self.slides[idx].scrollIntoView({behavior:'auto'});},0);
this.current=idx;
}
};
SlideEngine.prototype.goTo=function(i){this.slides[Math.max(0,Math.min(i,this.total-1))].scrollIntoView({behavior:'smooth'});};
SlideEngine.prototype.next=function(){if(this.current<this.total-1)this.goTo(this.current+1);};
SlideEngine.prototype.prev=function(){if(this.current>0)this.goTo(this.current-1);};
SlideEngine.prototype.update=function(){
this.bar.style.width=((this.current+1)/this.total*100)+'%';
var c=this.current;this.dots.forEach(function(d,i){d.classList.toggle('active',i===c);});
this.counter.textContent=(this.current+1)+' / '+this.total;
var h='#/'+(this.current+1);
if(location.hash!==h){try{history.replaceState(null,'',h);}catch(e){}}
};
SlideEngine.prototype.fadeHints=function(){clearTimeout(this.hintTimer);this.hints.classList.add('faded');};
new SlideEngine();
</script>
</body>
</html>