Files
2026-07-13 21:37:02 +08:00

1102 lines
33 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='zh-CN'>
<head>
<meta charset='utf-8' />
<meta name='viewport' content='width=device-width, initial-scale=1' />
<title>开放设计 · kami 幻灯片 — 第 01 卷 / 第 26 期</title>
<meta name='description' content='开放设计以 kami 幻灯片形式呈现。温暖的羊皮纸底色搭配墨蓝封面与章节页,单一字重的衬线体,无斜体。' />
<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;600&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;
--warm-sand: #e8e6dc;
--deep-dark: #141413;
/* brand (single chromatic accent) */
--brand: #1B365D;
--brand-light: #2D5A8A;
/* 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;
--tag-22: #D0DCE9;
/* 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.55); }
.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 {
width: 22px; height: 22px;
border-radius: 50%;
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;
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.55); }
.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: 4px;
}
.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;
border-radius: 999px;
background: rgba(245, 244, 237, 0.78);
border: 1px solid var(--border);
backdrop-filter: blur(8px);
}
#nav .dot {
width: 7px; height: 7px;
border-radius: 50%;
background: rgba(27, 54, 93, 0.22);
cursor: pointer;
transition: all 0.3s ease;
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: 999px;
}
#hint {
position: fixed;
bottom: 36px; right: 28px;
z-index: 30;
font-family: var(--mono);
font-size: 10px;
letter-spacing: 0.4px;
text-transform: uppercase;
color: var(--stone);
opacity: 0.75;
}
/* ---------- COVER slide (dark) ---------- */
.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.65);
}
.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: #B5C8DC; }
.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;
gap: 20px;
font-family: var(--mono);
font-size: 11px;
letter-spacing: 0.4px;
text-transform: uppercase;
color: rgba(250, 249, 245, 0.6);
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.55);
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.7);
max-width: 42ch;
margin: 0 auto;
line-height: 1.5;
letter-spacing: 0.05em;
}
/* ---------- 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.4px;
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 {
content: '\2013';
position: absolute; left: 0;
color: 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: 4px;
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.4px;
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.35;
color: var(--near-black);
margin: 0;
letter-spacing: 0.05em;
max-width: 36ch;
}
.s-quote .author {
display: flex;
align-items: center;
gap: 16px;
margin-top: 12px;
}
.s-quote .author .glyph {
width: 44px; height: 44px;
border-radius: 50%;
background: var(--brand); color: var(--ivory);
font-family: var(--serif); font-weight: 500;
font-size: 18px;
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: 10px 16px;
border-radius: 8px;
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;
font-size: clamp(96px, 16vw, 240px);
line-height: 1;
letter-spacing: -1.2px;
color: var(--ivory);
white-space: nowrap;
overflow-x: hidden;
}
.s-end .word .hl { color: #B5C8DC; }
.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.65);
font-variant-numeric: tabular-nums;
}
/* ---------- ESC overview ---------- */
#overview {
position: fixed; inset: 0;
z-index: 100;
background: rgba(245, 244, 237, 0.96);
backdrop-filter: blur(12px);
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: 8px;
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; }
/* ---------- 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>开放设计</b> · 第 01 卷 / 第 26 期</span>
<span class='right'>开放设计 · kami 幻灯片</span>
</div>
<div class='slide-inner'>
<span class='eyebrow'>开源设计工作室 · 第 01 号</span>
<h1>在温暖的<span class='hl'>纸上</span>设计智能。</h1>
<p class='tagline'>面向编辑文档与幻灯片的开源工作室——由你的编程智能体排版。</p>
<div class='meta'>
<span>柏林 · 52.5200° N · 13.4050° E</span>
<span class='rule'></span>
<span>MMXXVI · Apache-2.0</span>
</div>
</div>
<div class='slide-foot'>
<span>柏林 · 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>开放设计</b> · 第 01 卷 / 第 26 期</span>
<span class='right'>开放设计 · kami 幻灯片</span>
</div>
<div class='slide-inner'>
<p class='num'>01</p>
<h2>为什么设计还需要另一种工具。</h2>
<p class='lede'>因为最强大的智能体已经生活在你的笔记本电脑上——它们值得一个真正的工作流,而不是一个聊天窗口。</p>
</div>
<div class='slide-foot'>
<span>柏林 · 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>开放设计</b> · 第 01 卷 / 第 26 期</span>
<span class='right'>开放设计 · kami 幻灯片</span>
</div>
<div class='slide-inner'>
<div class='head'>
<p class='num'>01.1</p>
<h2>它是什么。</h2>
<p class='lede'>为你已信任的智能体量身打造的一个本地优先的设计工作室。</p>
</div>
<div class='body'>
<p>
Open Design 是 <strong>Anthropic 的 Claude Design 的开源替代方案</strong>。它在你的笔记本电脑上运行。你的智能体读取一个包含 <code>SKILL.md</code> 文件的文件夹和一个包含 <code>DESIGN.md</code> 系统的文件夹,然后生成真实的文件——着陆页、幻灯片、白皮书、仪表盘。
</p>
<ul class='dash'>
<li>文件,而非不透明的提示词——每项技能都是一个 Markdown 文件夹。</li>
<li>确定性的视觉方向,而非随机生成。</li>
<li>沙箱化 iframe 预览、真实 <code>cwd</code>、可导出的工件。</li>
</ul>
<div class='tag-row'>
<span class='tag'>Apache-2.0</span>
<span class='tag'>本地优先</span>
<span class='tag'>自带密钥</span>
</div>
</div>
</div>
<div class='slide-foot'>
<span>柏林 · 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>开放设计</b> · 第 01 卷 / 第 26 期</span>
<span class='right'>开放设计 · kami 幻灯片</span>
</div>
<div class='slide-inner'>
<div class='head'>
<p class='num'>01.2</p>
<h2>使用体验如何。</h2>
<p class='lede'>编辑规范,而非聊天窗口式的即兴发挥。</p>
</div>
<div class='body'>
<p>
一个新项目从一份 30 秒的问题表单开始:品牌、受众、规模、语言。智能体从五种视觉方向中选定一种,锁定字体栈,然后将工件写入磁盘。<strong>你可以阅读它触碰过的每一个文件。</strong>
</p>
<p>
每一次迭代都在一个带有注释模式锚点的沙箱化 iframe 中审查,锚点覆盖每个可编辑元素。重复运行是确定性的——相同的简报,相同的输出。
</p>
<ul class='dash'>
<li>简报 → 30 秒问题表单锁定品牌 + 受众 + 规模。</li>
<li>方向 → 以 OKLch 颜色空间呈现的 5 种视觉方向 + 锁定字体栈。</li>
<li>工件 → 磁盘上的真实文件、沙箱化预览、注释锚点。</li>
</ul>
</div>
</div>
<div class='slide-foot'>
<span>柏林 · 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>开放设计</b> · 第 01 卷 / 第 26 期</span>
<span class='right'>开放设计 · kami 幻灯片</span>
</div>
<div class='slide-inner'>
<div class='head'>
<p class='num'>01.3</p>
<h2>数据一览。</h2>
</div>
<div class='grid'>
<div class='stat'>
<div class='v'>31</div>
<div class='l'>技能</div>
<div class='s'>基于文件,即刻可用,即插即用。</div>
</div>
<div class='stat'>
<div class='v'>72</div>
<div class='l'>设计系统</div>
<div class='s'>可移植的 <code>DESIGN.md</code> 令牌——Linear、Vercel、Stripe、kami……</div>
</div>
<div class='stat'>
<div class='v'>12</div>
<div class='l'>智能体 CLI</div>
<div class='s'><code>$PATH</code> 上自动检测;即时切换后端。</div>
</div>
<div class='stat'>
<div class='v'>3</div>
<div class='l'>命令</div>
<div class='s'><code>git clone</code> 到第一个工件,全部本地完成。</div>
</div>
</div>
<p class='caption'>Open Design v0.2.0 · Apache-2.0 · MMXXVI · 数据截至第 26 期。</p>
</div>
<div class='slide-foot'>
<span>柏林 · 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>开放设计</b> · 第 01 卷 / 第 26 期</span>
<span class='right'>开放设计 · kami 幻灯片</span>
</div>
<div class='slide-inner'>
<p class='num'>02</p>
<h2>下一步交付什么。</h2>
<p class='lede'>2026 年第二季度——打包、多租户令牌、守护进程加固。路线图公开透明。</p>
</div>
<div class='slide-foot'>
<span>柏林 · 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>开放设计</b> · 第 01 卷 / 第 26 期</span>
<span class='right'>开放设计 · kami 幻灯片</span>
</div>
<div class='slide-inner'>
<blockquote>
Open Design 帮助我们把模糊的 AI 想法转化为一个锐利、可信且真正新颖的视觉系统——全程无需打开一个聊天窗口。
</blockquote>
<div class='author'>
<span class='glyph'>m</span>
<p>
Mina Kovac
<span>创意总监 · North Form,柏林</span>
</p>
</div>
</div>
<div class='slide-foot'>
<span>柏林 · 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>开放设计</b> · 第 01 卷 / 第 26 期</span>
<span class='right'>开放设计 · kami 幻灯片</span>
</div>
<div class='slide-inner'>
<span class='eyebrow'>开启对话 · 第 03 号</span>
<h2>让我们共建一些开放且视觉难忘的东西。</h2>
<p class='body'>
在 GitHub 上标星仓库,在 issues 中留言,或者今晚就运行 <code>pnpm tools-dev</code>。三条命令,这个循环就是你的了。
</p>
<div class='actions'>
<a class='btn btn-primary' href='https://github.com/nexu-io/open-design'>在 GitHub 上标星</a>
<a class='btn btn-ghost' href='https://github.com/nexu-io/open-design/issues'>提交 issue</a>
</div>
</div>
<div class='slide-foot'>
<span>柏林 · 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>开放设计</b> · 第 01 卷 / 第 26 期</span>
<span class='right'>开放设计 · kami 幻灯片</span>
</div>
<div class='slide-inner'>
<div class='word'>开放 <span class='hl'>设计。</span></div>
<p class='colophon'>Apache-2.0 · MMXXVI · 柏林 · 52.5200° N · 13.4050° E · 以 kami 编排</p>
</div>
<div class='slide-foot'>
<span>柏林 · MMXXVI</span>
<span class='counter'>09 / 09</span>
</div>
</section>
</div>
<div id='nav'></div>
<div id='hint'>← / → · esc · 滑动</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', '幻灯片 ' + (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>幻灯片概览</b> · 按 esc 关闭</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>