Files
nexu-io-open-design/plugins/_official/examples/kami-deck/example.html
2026-06-29 15:00:45 +00:00

1141 lines
35 KiB
HTML
Raw Permalink 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'>
<head>
<meta charset='utf-8' />
<meta name='viewport' content='width=device-width, initial-scale=1' />
<title>Open Design · kami deck — Vol. 01 / Issue Nº 26</title>
<meta name='description' content='Open Design as a kami slide deck. Warm parchment with ink-blue cover and chapter slides, serif at one weight, no italic.' />
<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=Source+Serif+4:wght@400;500&family=Source+Sans+3:wght@400;500&family=JetBrains+Mono:wght@400;500&display=swap' rel='stylesheet' />
<style>
/*
* kami-deck — single-file slide deck stylesheet.
*
* Kami token language (warm parchment, ink-blue accent, serif at one
* weight, no italic) — but laid out as a horizontal swipe deck. Macro
* tokens are scaled × ~1.6 vs. print baseline; letter-spacing scaled
* × ~0.6 (per design-systems/kami/DESIGN.md §3).
*
* Navigation model is borrowed from skills/guizang-ppt — same flex
* track + transform translateX, same key/wheel/touch handlers.
*/
:root {
/* surface */
--parchment: #f5f4ed;
--ivory: #faf9f5;
/* brand (single chromatic accent) */
--brand: #1B365D;
--brand-light: #2D5A8A;
--brand-steel: #B5C8DC; /* highlight ink on navy: cover/end .hl */
/* text */
--near-black: #141413;
--dark-warm: #3d3d3a;
--olive: #504e49;
--stone: #6b6a64;
/* border */
--border: #e8e6dc;
--border-soft: #e5e3d8;
/* tag tints (solid hex, NEVER rgba) */
--tag-08: #EEF2F7;
--tag-14: #E4ECF5;
/* type */
--serif: 'Source Serif 4', Charter, Georgia, Palatino, 'Times New Roman', serif;
--sans: 'Source Sans 3', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
--mono: 'JetBrains Mono', 'SF Mono', 'Fira Code', Consolas, Monaco, monospace;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html, body {
width: 100%; height: 100%;
overflow: hidden;
background: var(--parchment);
color: var(--near-black);
font-family: var(--serif);
font-weight: 400;
-webkit-font-smoothing: antialiased;
}
strong { font-weight: 500; }
/* ---------- deck flex track ---------- */
#deck {
position: fixed; inset: 0;
height: 100vh;
display: flex;
flex-wrap: nowrap;
transition: transform 0.9s cubic-bezier(0.77, 0, 0.175, 1);
z-index: 5;
will-change: transform;
}
.slide {
width: 100vw; height: 100vh;
flex: 0 0 100vw;
position: relative;
padding: 80px 96px;
display: flex;
flex-direction: column;
overflow: hidden;
background: var(--parchment);
color: var(--near-black);
}
.slide.dark {
background: var(--brand);
color: var(--ivory);
}
.slide-inner {
max-width: 1280px;
margin: 0 auto;
width: 100%;
height: 100%;
display: grid;
align-content: center;
gap: 24px;
position: relative;
min-height: 0;
}
/* ---------- per-slide chrome strip ---------- */
.slide-chrome {
position: absolute;
top: 28px; left: 0; right: 0;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 96px;
font-family: var(--sans);
font-size: 11px;
font-weight: 500;
letter-spacing: 0.6px;
text-transform: uppercase;
color: var(--stone);
z-index: 4;
pointer-events: none;
}
.slide.dark .slide-chrome { color: rgba(250, 249, 245, 0.74); } /* 11px caps on navy: keep >= AA */
.slide-chrome b { color: var(--near-black); font-weight: 500; }
.slide.dark .slide-chrome b { color: var(--ivory); }
.slide-chrome .left { display: inline-flex; align-items: center; gap: 12px; }
.slide-chrome .right {
display: inline-flex; align-items: center; gap: 12px;
font-variant-numeric: tabular-nums;
}
.slide-chrome .mark {
/* printer's mark: square hairline seal, not a generic pill chip */
height: 22px;
padding: 0 9px;
border-radius: 2px;
border: 1px solid currentColor;
display: inline-flex;
align-items: center;
justify-content: center;
font-family: var(--serif);
font-weight: 500;
font-size: 11px;
letter-spacing: 0.5px;
text-transform: lowercase;
opacity: 0.85;
}
.slide-foot {
position: absolute;
bottom: 28px; left: 0; right: 0;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 96px;
font-family: var(--mono);
font-size: 10.5px;
letter-spacing: 0.4px;
color: var(--stone);
font-variant-numeric: tabular-nums;
z-index: 4;
pointer-events: none;
}
.slide.dark .slide-foot { color: rgba(250, 249, 245, 0.74); } /* 10.5px mono on navy: keep >= AA */
.slide-foot .counter {
font-family: var(--mono);
letter-spacing: 0.04em;
color: var(--near-black);
background: var(--ivory);
padding: 4px 8px;
border: 1px solid var(--border);
border-radius: 2px; /* match the square hairline language of the mark */
}
.slide.dark .slide-foot .counter {
color: var(--ivory);
background: rgba(250, 249, 245, 0.08);
border-color: rgba(250, 249, 245, 0.22);
}
/* ---------- progress bar ---------- */
.deck-progress {
position: fixed;
left: 0; right: 0; bottom: 0;
height: 2px;
background: rgba(27, 54, 93, 0.08);
z-index: 30;
}
.deck-progress .bar {
height: 100%;
background: var(--brand);
width: 0%;
transition: width 0.6s cubic-bezier(0.77, 0, 0.175, 1);
}
/* ---------- dot nav ---------- */
#nav {
position: fixed;
left: 50%;
bottom: 40px;
transform: translateX(-50%);
z-index: 30;
display: flex;
gap: 9px;
padding: 8px 14px;
/* flat parchment strip with a hairline, square corners: the glassy
blurred pill was outside the kami print language */
border-radius: 2px;
background: rgba(245, 244, 237, 0.92);
border: 1px solid var(--border);
}
#nav .dot {
width: 7px; height: 7px;
border-radius: 50%;
background: rgba(27, 54, 93, 0.22);
cursor: pointer;
transition: background-color 0.3s cubic-bezier(0.16, 1, 0.3, 1),
width 0.3s cubic-bezier(0.16, 1, 0.3, 1),
transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
border: 0;
padding: 0;
}
#nav .dot:hover {
background: rgba(27, 54, 93, 0.5);
transform: scale(1.15);
}
#nav .dot.active {
background: var(--brand);
width: 22px;
border-radius: 1px; /* active marker reads as an ink dash, not a capsule */
}
#hint {
position: fixed;
bottom: 64px; right: 28px;
z-index: 30;
font-family: var(--mono);
font-size: 10px;
letter-spacing: 0.4px;
text-transform: uppercase;
color: var(--stone);
/* hint floats over both parchment and navy slides; bare stone text was
sub-AA on the dark cover/end, so it gets the same parchment hairline
chip language as the nav strip and counter */
background: rgba(245, 244, 237, 0.92);
border: 1px solid var(--border);
border-radius: 2px;
padding: 5px 9px;
}
/* ---------- COVER slide (dark) ---------- */
/* opening beat: transform+opacity only, ease-out, staggered 0.08s.
Scoped to the cover; the swipe track paints every slide at load, so
animating all of them would burn the effect off-screen. */
@keyframes kami-rise {
from { opacity: 0; transform: translateY(18px); }
to { opacity: 1; transform: none; }
}
.s-cover .slide-inner > * {
animation: kami-rise 0.7s cubic-bezier(0.16, 1, 0.3, 1) both;
}
.s-cover .slide-inner > *:nth-child(2) { animation-delay: 0.08s; }
.s-cover .slide-inner > *:nth-child(3) { animation-delay: 0.16s; }
.s-cover .slide-inner > *:nth-child(4) { animation-delay: 0.24s; }
.s-cover .slide-inner {
grid-template-columns: 1fr;
text-align: left;
align-content: center;
gap: 28px;
max-width: 980px;
}
.s-cover .eyebrow {
font-family: var(--sans);
font-size: 12px;
font-weight: 500;
letter-spacing: 1.2px;
text-transform: uppercase;
color: rgba(250, 249, 245, 0.74); /* small caps on navy: keep >= AA */
}
.s-cover h1 {
font-family: var(--serif);
font-weight: 500;
font-size: clamp(60px, 7vw, 110px);
line-height: 1.05;
letter-spacing: -1.2px;
color: var(--ivory);
margin: 0;
}
.s-cover h1 .hl { color: var(--brand-steel); }
.s-cover .tagline {
font-family: var(--serif);
font-weight: 500;
font-size: 21px;
color: rgba(250, 249, 245, 0.75);
max-width: 50ch;
line-height: 1.45;
}
.s-cover .meta {
margin-top: 20px;
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 14px 20px;
font-family: var(--mono);
font-size: 11px;
letter-spacing: 0.4px;
text-transform: uppercase;
color: rgba(250, 249, 245, 0.72); /* 11px mono on navy: keep >= AA */
font-variant-numeric: tabular-nums;
}
.s-cover .meta .rule {
width: 56px; height: 1px;
background: rgba(250, 249, 245, 0.4);
display: inline-block;
}
/* ---------- CHAPTER divider (dark) ---------- */
.s-chapter .slide-inner {
grid-template-columns: 1fr;
text-align: center;
align-content: center;
gap: 36px;
}
.s-chapter .num {
font-family: var(--serif);
font-weight: 500;
font-size: clamp(64px, 8vw, 130px);
color: rgba(250, 249, 245, 0.62); /* ghosted chapter numeral, kept >= 3:1 for large text */
letter-spacing: -0.5px;
line-height: 1;
font-variant-numeric: tabular-nums;
}
.s-chapter h2 {
font-family: var(--serif);
font-weight: 500;
font-size: clamp(48px, 5.4vw, 84px);
line-height: 1.1;
letter-spacing: -0.6px;
color: var(--ivory);
margin: 0 auto;
max-width: 22ch;
}
.s-chapter .lede {
font-family: var(--serif);
font-weight: 500;
font-size: 19px;
color: rgba(250, 249, 245, 0.78);
max-width: 42ch;
margin: 0 auto;
line-height: 1.5;
}
/* ---------- CONTENT slide ---------- */
.s-content .slide-inner {
grid-template-columns: 1fr 2.4fr;
gap: 56px;
align-content: center;
}
.s-content.layout-full .slide-inner { grid-template-columns: 1fr; max-width: 980px; }
.s-content .head { display: flex; flex-direction: column; gap: 16px; }
.s-content .num {
font-family: var(--serif);
font-weight: 500;
font-size: 14px;
letter-spacing: 0.4px;
color: var(--brand);
font-variant-numeric: tabular-nums;
}
.s-content h2 {
font-family: var(--serif);
font-weight: 500;
font-size: clamp(36px, 4vw, 56px);
line-height: 1.1;
letter-spacing: -0.6px;
color: var(--near-black);
margin: 0;
max-width: 14ch;
}
.s-content .lede {
font-family: var(--serif);
font-weight: 500;
font-size: 15px;
color: var(--olive);
max-width: 28ch;
line-height: 1.5;
}
.s-content .body { display: flex; flex-direction: column; gap: 18px; }
.s-content .body p {
font-family: var(--serif);
font-weight: 400;
font-size: 17px;
line-height: 1.55;
color: var(--dark-warm);
max-width: 64ch;
}
.s-content .body p strong { color: var(--near-black); font-weight: 500; }
.s-content .body code {
font-family: var(--mono);
font-size: 14px;
color: var(--brand);
background: var(--tag-08);
padding: 1px 6px;
border-radius: 3px;
}
.s-content ul.dash {
list-style: none; padding: 0; margin: 4px 0 0;
display: flex; flex-direction: column; gap: 10px;
}
.s-content ul.dash li {
position: relative; padding-left: 18px;
font-family: var(--serif);
font-weight: 400;
font-size: 16px;
line-height: 1.55;
color: var(--dark-warm);
}
.s-content ul.dash li::before {
/* hairline tick instead of a literal dash glyph (anti-slop: no -/-- in visible text) */
content: '';
position: absolute; left: 0; top: 0.72em;
width: 10px; height: 1px;
background: var(--brand);
}
.s-content .body .tag-row { margin-top: 4px; }
.s-content .tag {
display: inline-block;
font-family: var(--sans);
font-size: 12px;
font-weight: 500;
padding: 2px 8px;
border-radius: 2px;
color: var(--brand);
background: var(--tag-14);
letter-spacing: 0.4px;
}
/* ---------- STATS slide ---------- */
.s-stats .slide-inner { grid-template-columns: 1fr; gap: 48px; }
.s-stats .head { display: flex; flex-direction: column; gap: 18px; }
.s-stats .num {
font-family: var(--serif);
font-weight: 500;
font-size: 14px;
letter-spacing: 0.4px;
color: var(--brand);
font-variant-numeric: tabular-nums;
}
.s-stats h2 {
font-family: var(--serif);
font-weight: 500;
font-size: clamp(36px, 4.2vw, 60px);
line-height: 1.1;
letter-spacing: -0.6px;
color: var(--near-black);
max-width: 22ch;
margin: 0;
}
.s-stats .grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 0;
border-top: 1px solid var(--border);
border-bottom: 1px solid var(--border);
}
.s-stats .stat {
padding: 32px 24px 28px;
display: flex;
flex-direction: column;
gap: 8px;
border-right: 1px solid var(--border-soft);
}
.s-stats .stat:last-child { border-right: 0; }
.s-stats .stat .v {
font-family: var(--serif);
font-weight: 500;
font-size: clamp(48px, 6vw, 88px);
line-height: 1;
letter-spacing: -0.8px;
color: var(--brand);
font-variant-numeric: tabular-nums;
}
.s-stats .stat .l {
font-family: var(--serif);
font-weight: 500;
font-size: 15px;
color: var(--near-black);
margin-top: 8px;
}
.s-stats .stat .s {
font-family: var(--serif);
font-weight: 400;
font-size: 13px;
color: var(--olive);
line-height: 1.5;
max-width: 28ch;
}
.s-stats .caption {
font-family: var(--mono);
font-size: 11px;
color: var(--stone);
letter-spacing: 0.4px;
font-variant-numeric: tabular-nums;
}
/* ---------- QUOTE slide ---------- */
.s-quote .slide-inner {
grid-template-columns: 1fr;
max-width: 1080px;
gap: 36px;
align-content: center;
}
.s-quote blockquote {
border-left: 2px solid var(--brand);
padding: 6px 0 6px 28px;
font-family: var(--serif);
font-weight: 500;
font-size: clamp(28px, 3.4vw, 42px);
line-height: 1.32;
color: var(--near-black);
margin: 0;
letter-spacing: -0.4px; /* display serif tracks tight, matching h1/h2; loose +tracking was residue */
max-width: 36ch;
}
.s-quote .author {
display: flex;
align-items: center;
gap: 16px;
margin-top: 12px;
}
.s-quote .author .glyph {
/* hanko-style seal: hairline square in brand ink, not a solid avatar disc */
width: 40px; height: 40px;
border-radius: 3px;
border: 1px solid var(--brand);
background: transparent; color: var(--brand);
font-family: var(--serif); font-weight: 500;
font-size: 17px;
display: inline-flex;
align-items: center;
justify-content: center;
text-transform: uppercase;
letter-spacing: 0;
}
.s-quote .author p {
font-family: var(--serif);
font-weight: 500;
font-size: 14px;
color: var(--near-black);
}
.s-quote .author p span {
display: block;
color: var(--olive);
font-weight: 400;
margin-top: 2px;
}
/* ---------- CTA slide ---------- */
.s-cta .slide-inner {
grid-template-columns: 1fr;
max-width: 980px;
gap: 28px;
align-content: center;
text-align: left;
}
.s-cta .eyebrow {
font-family: var(--sans);
font-size: 12px; font-weight: 500;
letter-spacing: 1.2px;
text-transform: uppercase;
color: var(--brand);
}
.s-cta h2 {
font-family: var(--serif);
font-weight: 500;
font-size: clamp(48px, 5.4vw, 88px);
line-height: 1.05;
letter-spacing: -0.6px;
color: var(--near-black);
margin: 0;
}
.s-cta .body {
font-family: var(--serif);
font-weight: 400;
font-size: 17px;
color: var(--dark-warm);
max-width: 50ch;
line-height: 1.55;
}
.s-cta .actions {
display: inline-flex;
gap: 12px;
margin-top: 12px;
align-items: center;
flex-wrap: wrap;
}
.s-cta .btn {
display: inline-flex;
align-items: center;
gap: 8px;
font-family: var(--sans);
font-size: 13px;
font-weight: 500;
letter-spacing: 0.4px;
padding: 11px 18px;
border-radius: 2px;
border: 0;
cursor: pointer;
text-decoration: none;
}
.s-cta .btn-primary {
background: var(--brand);
color: var(--ivory);
box-shadow: 0 0 0 1px var(--brand);
}
.s-cta .btn-primary:hover { background: var(--brand-light); box-shadow: 0 0 0 1px var(--brand-light); }
.s-cta .btn-ghost {
background: transparent;
color: var(--brand);
box-shadow: 0 0 0 1px var(--brand);
}
.s-cta .btn-ghost:hover { background: var(--tag-08); }
/* ---------- END slide (dark) ---------- */
.s-end .slide-inner {
grid-template-columns: 1fr;
align-content: end;
padding-bottom: 24px;
text-align: left;
gap: 18px;
max-width: none;
}
.s-end .word {
font-family: var(--serif);
font-weight: 500;
/* 16vw clipped "Open Design." mid-glyph behind overflow-x: hidden at every
common width (needs ~0.93vw of run length vs ~0.85vw available after
padding); 13vw keeps the full word on screen. */
font-size: clamp(88px, 13vw, 210px);
line-height: 1;
letter-spacing: -1.2px;
color: var(--ivory);
white-space: nowrap;
overflow-x: hidden;
}
.s-end .word .hl { color: var(--brand-steel); }
.s-end .colophon {
border-top: 1px solid rgba(250, 249, 245, 0.22);
padding-top: 22px;
font-family: var(--sans);
font-size: 11px;
font-weight: 500;
letter-spacing: 1.2px;
text-transform: uppercase;
color: rgba(250, 249, 245, 0.74); /* 11px caps colophon on navy: keep >= AA */
font-variant-numeric: tabular-nums;
}
/* ---------- ESC overview ---------- */
#overview {
position: fixed; inset: 0;
z-index: 100;
background: rgba(245, 244, 237, 0.98); /* near-solid parchment sheet, no glass blur */
display: none;
overflow-y: auto;
padding: 60px 56px;
}
#overview .ov-head {
display: flex; justify-content: space-between; align-items: baseline;
margin-bottom: 32px;
font-family: var(--sans); font-size: 11px;
letter-spacing: 1.2px; text-transform: uppercase;
color: var(--stone);
font-variant-numeric: tabular-nums;
}
#overview .ov-head b { color: var(--near-black); font-weight: 500; }
#overview .ov-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 22px;
max-width: 1280px;
margin: 0 auto;
}
#overview .ov-card {
cursor: pointer;
border-radius: 3px;
overflow: hidden;
border: 1px solid var(--border);
transition: border-color 0.2s, transform 0.2s;
background: var(--ivory);
}
#overview .ov-card:hover { border-color: var(--brand); transform: translateY(-2px); }
#overview .ov-card.active { border-color: var(--brand); border-width: 2px; }
#overview .ov-thumb {
width: 100%;
aspect-ratio: 16 / 10;
overflow: hidden;
position: relative;
pointer-events: none;
background: var(--parchment);
}
#overview .ov-thumb .clone {
width: 100vw; height: 100vh;
transform: scale(0.18);
transform-origin: top left;
position: absolute;
top: 0; left: 0;
pointer-events: none;
}
#overview .ov-label {
padding: 8px 12px;
font-family: var(--mono); font-size: 10px;
letter-spacing: 0.4px; text-transform: uppercase;
color: var(--stone);
display: flex; justify-content: space-between; align-items: center;
font-variant-numeric: tabular-nums;
}
#overview .ov-label b { color: var(--near-black); font-weight: 500; }
/* ---------- reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
#deck { transition: none; }
.s-cover .slide-inner > * { animation: none; }
.deck-progress .bar { transition: none; }
#nav .dot { transition: none; }
#overview .ov-card { transition: none; }
#overview .ov-card:hover { transform: none; }
}
/* ---------- responsive ---------- */
@media (max-width: 1080px) {
.slide { padding: 64px 56px; }
.slide-chrome, .slide-foot { padding: 0 56px; }
.s-content .slide-inner { grid-template-columns: 1fr; gap: 28px; }
}
@media (max-width: 640px) {
.slide { padding: 44px 28px; }
.slide-chrome, .slide-foot { padding: 0 28px; font-size: 9.5px; letter-spacing: 0.6px; }
#hint { display: none; }
}
</style>
</head>
<body>
<div id='deck'>
<!-- ===== 01 · COVER (dark) ===== -->
<section class='slide s-cover dark' data-slide-kind='cover'>
<div class='slide-chrome'>
<span class='left'><span class='mark'>kami</span> <b>Open Design</b> · Vol. 01 / Issue Nº 26</span>
<span class='right'>Open Design · kami deck</span>
</div>
<div class='slide-inner'>
<span class='eyebrow'>Open-source · Local · Agent-driven · Nº 01</span>
<h1>Open <span class='hl'>Design</span>.</h1>
<p class='tagline'>The open-source, local, agent-driven design platform. From idea to prototypes, web pages, slides, and HTML video — the full product-design workflow, on your own machine.</p>
<div class='meta'>
<span>Apache-2.0 · Runs Locally · BYOK · No Sign-up</span>
<span class='rule'></span>
<span>github.com/nexu-io/open-design</span>
</div>
</div>
<div class='slide-foot'>
<span>Open Design · MMXXVI</span>
<span class='counter'>01 / 09</span>
</div>
</section>
<!-- ===== 02 · CHAPTER (dark) ===== -->
<section class='slide s-chapter dark' data-slide-kind='chapter'>
<div class='slide-chrome'>
<span class='left'><span class='mark'>kami</span> <b>Open Design</b> · Vol. 01 / Issue Nº 26</span>
<span class='right'>Open Design · kami deck</span>
</div>
<div class='slide-inner'>
<p class='num'>01</p>
<h2>Why Open Design exists.</h2>
<p class='lede'>In April 2026, Claude Design proved an LLM can truly design. But it is closed-source, paid, and cloud-only. Open Design sets that capability free.</p>
</div>
<div class='slide-foot'>
<span>Open Design · MMXXVI</span>
<span class='counter'>02 / 09</span>
</div>
</section>
<!-- ===== 03 · CONTENT ===== -->
<section class='slide s-content' data-slide-kind='content'>
<div class='slide-chrome'>
<span class='left'><span class='mark'>kami</span> <b>Open Design</b> · Vol. 01 / Issue Nº 26</span>
<span class='right'>Open Design · kami deck</span>
</div>
<div class='slide-inner'>
<div class='head'>
<p class='num'>01.1</p>
<h2>What it is.</h2>
<p class='lede'>Frontier AI design, back on every creator's desk.</p>
</div>
<div class='body'>
<p>
Open Design is the <strong>open-source, local, agent-driven design platform</strong>. It runs on your machine. Claude Code, Codex, and Cursor are already powerful — Open Design wires them into a complete design workflow that produces real runnable files: prototypes, web pages, slides, and HTML video.
</p>
<ul class='dash'>
<li>Desktop-native — local files, Figma exports, and code repos directly readable; agents get full terminal power.</li>
<li>Plug in agents, don't rebuild them — the CLIs on your machine drive the whole workflow.</li>
<li>It learns your taste — every choice becomes design systems, preferences, and memory.</li>
</ul>
<div class='tag-row'>
<span class='tag'>Apache-2.0</span>
<span class='tag'>Local-first</span>
<span class='tag'>BYOK</span>
</div>
</div>
</div>
<div class='slide-foot'>
<span>Open Design · MMXXVI</span>
<span class='counter'>03 / 09</span>
</div>
</section>
<!-- ===== 04 · CONTENT ===== -->
<section class='slide s-content' data-slide-kind='content'>
<div class='slide-chrome'>
<span class='left'><span class='mark'>kami</span> <b>Open Design</b> · Vol. 01 / Issue Nº 26</span>
<span class='right'>Open Design · kami deck</span>
</div>
<div class='slide-inner'>
<div class='head'>
<p class='num'>01.2</p>
<h2>How it works.</h2>
<p class='lede'>From idea to delivery in 5 steps.</p>
</div>
<div class='body'>
<p>
Describe your goal in one sentence, or start from a template or plugin. Once a visual direction is set, palette, type, and spacing flow into generation automatically. <strong>The agent reads full context and produces real runnable files</strong>, previewed and edited in a sandbox.
</p>
<p>
Ship it, or film it — hand off to engineering, or turn it into a marketing video with HyperFrames. Memory compounds: every choice becomes context for the next run.
</p>
<ul class='dash'>
<li>Pick a starting point → set the visual direction → generate the artifact.</li>
<li>Ship it, or film it — engineering handoff or HyperFrames video.</li>
<li>Memory compounds — every run lands closer to what you want.</li>
</ul>
</div>
</div>
<div class='slide-foot'>
<span>Open Design · MMXXVI</span>
<span class='counter'>04 / 09</span>
</div>
</section>
<!-- ===== 05 · STATS ===== -->
<section class='slide s-stats' data-slide-kind='stats'>
<div class='slide-chrome'>
<span class='left'><span class='mark'>kami</span> <b>Open Design</b> · Vol. 01 / Issue Nº 26</span>
<span class='right'>Open Design · kami deck</span>
</div>
<div class='slide-inner'>
<div class='head'>
<p class='num'>01.3</p>
<h2>By the numbers.</h2>
</div>
<div class='grid'>
<div class='stat'>
<div class='v'>60K+</div>
<div class='l'>GitHub Stars</div>
<div class='s'>open source under Apache-2.0.</div>
</div>
<div class='stat'>
<div class='v'>217+</div>
<div class='l'>Plugins</div>
<div class='s'>prototypes, slides, posters, dashboards.</div>
</div>
<div class='stat'>
<div class='v'>129</div>
<div class='l'>Design systems</div>
<div class='s'>import from GitHub, Figma, or local.</div>
</div>
<div class='stat'>
<div class='v'>21</div>
<div class='l'>Coding agents</div>
<div class='s'>auto-detected on your $PATH; zero config.</div>
</div>
</div>
<p class='caption'>Open Design · Apache-2.0 · 300+ contributors · github.com/nexu-io/open-design</p>
</div>
<div class='slide-foot'>
<span>Open Design · MMXXVI</span>
<span class='counter'>05 / 09</span>
</div>
</section>
<!-- ===== 06 · CHAPTER (dark) ===== -->
<section class='slide s-chapter dark' data-slide-kind='chapter'>
<div class='slide-chrome'>
<span class='left'><span class='mark'>kami</span> <b>Open Design</b> · Vol. 01 / Issue Nº 26</span>
<span class='right'>Open Design · kami deck</span>
</div>
<div class='slide-inner'>
<p class='num'>02</p>
<h2>What can you make with it.</h2>
<p class='lede'>Prototypes, live artifacts, slides, images, HTML-to-MP4 marketing shorts, and cinematic generative footage.</p>
</div>
<div class='slide-foot'>
<span>Open Design · MMXXVI</span>
<span class='counter'>06 / 09</span>
</div>
</section>
<!-- ===== 07 · QUOTE ===== -->
<section class='slide s-quote' data-slide-kind='quote'>
<div class='slide-chrome'>
<span class='left'><span class='mark'>kami</span> <b>Open Design</b> · Vol. 01 / Issue Nº 26</span>
<span class='right'>Open Design · kami deck</span>
</div>
<div class='slide-inner'>
<blockquote>
File-system semantics plus git-diffable design artifacts — design is finally under version control.
</blockquote>
<div class='author'>
<span class='glyph'>i</span>
<p>
Indie developer
<span>Open Design community</span>
</p>
</div>
</div>
<div class='slide-foot'>
<span>Open Design · MMXXVI</span>
<span class='counter'>07 / 09</span>
</div>
</section>
<!-- ===== 08 · CTA ===== -->
<section class='slide s-cta' data-slide-kind='cta'>
<div class='slide-chrome'>
<span class='left'><span class='mark'>kami</span> <b>Open Design</b> · Vol. 01 / Issue Nº 26</span>
<span class='right'>Open Design · kami deck</span>
</div>
<div class='slide-inner'>
<span class='eyebrow'>Open · Local · Agent-native</span>
<h2>Frontier AI design, back on every creator's desk.</h2>
<p class='body'>
Download Open Design for macOS or Windows, or star the repo on GitHub. github.com/nexu-io/open-design · discord.gg/mHAjSMV6gz · x.com/nexudotio
</p>
<div class='actions'>
<a class='btn btn-primary' href='https://open-design.ai/' target='_blank' rel='noreferrer noopener'>Download Open Design</a>
<a class='btn btn-ghost' href='https://github.com/nexu-io/open-design'>Star on GitHub</a>
</div>
</div>
<div class='slide-foot'>
<span>Open Design · MMXXVI</span>
<span class='counter'>08 / 09</span>
</div>
</section>
<!-- ===== 09 · END (dark) ===== -->
<section class='slide s-end dark' data-slide-kind='end'>
<div class='slide-chrome'>
<span class='left'><span class='mark'>kami</span> <b>Open Design</b> · Vol. 01 / Issue Nº 26</span>
<span class='right'>Open Design · kami deck</span>
</div>
<div class='slide-inner'>
<div class='word'>Open <span class='hl'>Design.</span></div>
<p class='colophon'>Apache-2.0 · MMXXVI · Open · Local · Agent-native · github.com/nexu-io/open-design · Composed in kami</p>
</div>
<div class='slide-foot'>
<span>Open Design · MMXXVI</span>
<span class='counter'>09 / 09</span>
</div>
</section>
</div>
<div id='nav'></div>
<div id='hint'>← / → · esc · swipe</div>
<div class='deck-progress'><div class='bar'></div></div>
<script>
(function () {
var deck = document.getElementById('deck');
if (!deck) return;
var slides = Array.prototype.slice.call(deck.querySelectorAll('.slide'));
var nav = document.getElementById('nav');
var bar = document.querySelector('.deck-progress .bar');
var total = slides.length;
var idx = 0, lock = false;
deck.style.width = (total * 100) + 'vw';
slides.forEach(function (s, i) {
var b = document.createElement('button');
b.className = 'dot';
b.dataset.i = i;
b.setAttribute('aria-label', 'Slide ' + (i + 1));
b.onclick = function () { go(i); };
nav.appendChild(b);
});
/* Unthrottled state update. The interaction throttle (`lock`) only
guards wheel/key/touch so a fast input burst doesn't overshoot the
transition; host- and observer-driven sync must bypass it, otherwise
a host message or restoreInitialSlide that lands inside the 700ms
window after go(0) silently no-ops and the deck stays on slide 1
while the host counter advances. */
function applySlide(n) {
idx = Math.max(0, Math.min(total - 1, n));
deck.style.transform = 'translateX(' + (-idx * 100) + 'vw)';
/* load-bearing: .slide.active is read by Open Design's host bridge
(src/runtime/srcdoc.ts findActiveByClass) to drive the slide
counter. No CSS targets it — do not remove. */
slides.forEach(function (s, i) { s.classList.toggle('active', i === idx); });
nav.querySelectorAll('.dot').forEach(function (d, i) {
d.classList.toggle('active', i === idx);
});
if (bar) bar.style.width = (((idx + 1) / total) * 100) + '%';
}
function go(n) {
if (lock) return;
applySlide(n);
lock = true;
setTimeout(function () { lock = false; }, 700);
}
/* ESC overview */
var overviewOn = false;
var ov = document.createElement('div');
ov.id = 'overview';
document.body.appendChild(ov);
function buildOverview() {
ov.innerHTML = '';
var head = document.createElement('div');
head.className = 'ov-head';
head.innerHTML = '<span><b>Slide overview</b> · esc to close</span><span>' +
String(idx + 1).padStart(2, '0') + ' / ' + String(total).padStart(2, '0') + '</span>';
ov.appendChild(head);
var grid = document.createElement('div');
grid.className = 'ov-grid';
slides.forEach(function (s, i) {
var card = document.createElement('div');
card.className = 'ov-card' + (i === idx ? ' active' : '');
var thumb = document.createElement('div');
thumb.className = 'ov-thumb';
var clone = s.cloneNode(true);
clone.className = clone.className + ' clone';
clone.style.transform = 'scale(0.18)';
thumb.appendChild(clone);
var label = document.createElement('div');
label.className = 'ov-label';
label.innerHTML = '<b>' + String(i + 1).padStart(2, '0') + '</b><span>' +
(s.dataset.slideKind || '') + '</span>';
card.appendChild(thumb);
card.appendChild(label);
card.onclick = function () { toggleOverview(); go(i); };
grid.appendChild(card);
});
ov.appendChild(grid);
}
function toggleOverview() {
overviewOn = !overviewOn;
if (overviewOn) { buildOverview(); ov.style.display = 'block'; }
else { ov.style.display = 'none'; }
}
addEventListener('keydown', function (e) {
if (e.key === 'Escape') { e.preventDefault(); toggleOverview(); return; }
if (overviewOn) return;
if (e.key === 'ArrowRight' || e.key === 'PageDown' || e.key === ' ' || e.key === 'ArrowDown') {
e.preventDefault(); go(idx + 1);
} else if (e.key === 'ArrowLeft' || e.key === 'PageUp' || e.key === 'ArrowUp') {
e.preventDefault(); go(idx - 1);
} else if (e.key === 'Home') {
e.preventDefault(); go(0);
} else if (e.key === 'End') {
e.preventDefault(); go(total - 1);
}
});
var wheelTO = null, wheelAcc = 0;
addEventListener('wheel', function (e) {
if (overviewOn) return;
wheelAcc += e.deltaY + e.deltaX;
if (Math.abs(wheelAcc) > 60) {
go(idx + (wheelAcc > 0 ? 1 : -1));
wheelAcc = 0;
}
clearTimeout(wheelTO);
wheelTO = setTimeout(function () { wheelAcc = 0; }, 150);
}, { passive: true });
var tx = 0, ty = 0;
addEventListener('touchstart', function (e) {
tx = e.touches[0].clientX; ty = e.touches[0].clientY;
}, { passive: true });
addEventListener('touchend', function (e) {
if (overviewOn) return;
var dx = e.changedTouches[0].clientX - tx;
var dy = e.changedTouches[0].clientY - ty;
if (Math.abs(dx) > 50 && Math.abs(dx) > Math.abs(dy)) {
go(idx + (dx < 0 ? 1 : -1));
}
}, { passive: true });
/* Host-driven navigation: Open Design's host bridge classifies this deck
as class-driven (because go() toggles .slide.active) but the visible
slide is moved by deck.style.transform, which the bridge can't drive.
Two cooperating handlers keep the deck in sync with the host:
1. An od:slide message listener routes host nav through go() and
calls stopImmediatePropagation() so the bridge's own listener
(registered after this one) doesn't run a second time and
overshoot by re-reading the freshly-toggled .active class.
2. A MutationObserver on each slide watches .active and pulls the
deck transform onto the active index for class changes that
don't come through a message — chiefly the bridge's
restoreInitialSlide path, which calls setActive() directly. */
addEventListener('message', function (e) {
var data = e && e.data;
if (!data || data.type !== 'od:slide') return;
if (typeof e.stopImmediatePropagation === 'function') e.stopImmediatePropagation();
if (data.action === 'go' && typeof data.index === 'number') applySlide(data.index);
else if (data.action === 'next') applySlide(idx + 1);
else if (data.action === 'prev') applySlide(idx - 1);
else if (data.action === 'first') applySlide(0);
else if (data.action === 'last') applySlide(total - 1);
});
if (typeof MutationObserver !== 'undefined') {
var syncFromActiveClass = function () {
for (var i = 0; i < slides.length; i++) {
if (slides[i].classList && slides[i].classList.contains('active') && i !== idx) {
applySlide(i);
return;
}
}
};
var mo = new MutationObserver(syncFromActiveClass);
slides.forEach(function (s) { mo.observe(s, { attributes: true, attributeFilter: ['class'] }); });
}
applySlide(0);
})();
</script>
</body>
</html>