cursor-animated-sites
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSkill: cursor-animated-sites
Skill: cursor-animated-sites
Build a single-file, self-contained HTML walkthrough that animates a cursor over a folder
tree, step by step. It is a LAYER on top of — reuse that skill's glass
design system (background plane, glass tiers, scrollbar, fonts, ripple, output path
, auto-host). This skill ADDS the interactive walkthrough.
/docs-site-macosllmwiki/html/DDMMYY-<slug>.htmlInherit docs-site-macos's Accessibility & Document Head section too —+<meta viewport>/<title>, inline favicon,descriptionring on the ⏮/⏭/▶ controls, and the global:focus-visibleguard (rule 11 already skips the walkthrough animation; the guard also stills the cursor/typewriter). Do NOT ship the page without viewport meta or its responsive grid breaks on mobile.prefers-reduced-motion
构建一个单文件、自包含 HTML 演示,逐步让光标在文件夹树中移动。它是建立在 之上的一个叠加层——复用该 skill 的玻璃设计系统(背景平面、玻璃层级、滚动条、字体、涟漪、输出路径 、自动托管)。此 skill 仅在现有页面上新增交互式演示。
/docs-site-macosllmwiki/html/DDMMYY-<slug>.html同时继承 docs-site-macos 的 无障碍与文档头部(Accessibility & Document Head) 部分——+<meta viewport>/<title>、内联 favicon、⏮/⏭/▶ 控件上的description焦点环,以及全局:focus-visible防护(规则 11 已会跳过演示动画;该防护也会让光标和打字机效果静止)。不要在缺少 viewport meta 的情况下发布页面,否则移动端的响应式网格会失效。prefers-reduced-motion
WHAT
内容(WHAT)
Purpose và context
目的与上下文
- Purpose: build a single-file, self-contained HTML walkthrough (layer on ) where a gutter cursor moves controller→file step by step, files type in when created, nodes are colored by role, with manual step and auto-play modes and a per-frame caption.
/docs-site-macos - Trigger (when to use):
- Explaining a lifecycle (install → configure → run), a sequence, or a data-flow.
- Any "how does X work, step by step" where the viewer needs to SEE which file each action reads/writes and in what order.
- Trigger words: "hoạt họa", "con trỏ chạy", "life cycle", "từng bước", "transcript", "minh hoạ cây thư mục", "/cursor-animated-sites".
- Non-goals: does not redefine the glass design system (background plane, glass tiers, scrollbar, fonts, ripple, output path, auto-host) — reuse ; this skill only ADDS the interactive walkthrough.
/docs-site-macos
- **目的:**构建一个单文件、自包含 HTML 演示(叠加在 之上),使装订线中的光标逐步从 controller 移动到 file;文件在创建时逐字输入;节点按角色着色;提供手动单步和自动播放模式;每帧配有说明字幕。
/docs-site-macos - 触发条件(何时使用):
- 讲解 lifecycle(安装 → 配置 → 运行)、sequence 或 data-flow。
- 任何需要让观看者看到每个操作按什么顺序读取或写入哪个文件的“X 如何逐步运作”演示。
- 触发词:“hoạt họa”、“con trỏ chạy”、“life cycle”、“từng bước”、“transcript”、“minh hoạ cây thư mục”、“/cursor-animated-sites”。
- 非目标:不重新定义玻璃设计系统(背景平面、玻璃层级、滚动条、字体、涟漪、输出路径、自动托管)——复用 ;此 skill 仅新增交互式演示。
/docs-site-macos
Mental model
心智模型
STEPS[] (ph · sp · h · d · flow · chain · role · marks · leak · verdict) + tree rows (data-born) → prep (accent per step, visibility by born) → animate (caption transcript = master clock, born rows type in, cursor visits chain in order, role colors + seq badges) → rest = full final frameSTEPS[]Input và output contract
输入与输出约定
| Field | Required? | Ý nghĩa | |
|---|---|---|---|
| In | lifecycle/sequence to explain | có | real order of steps + which files each step reads/writes |
| In | folder tree (files + actors) | có | each file has a birth step |
| Out | | có | single file, docs-site-macos base, auto-hosted |
| Out | draft output report + index + log | có | OKF YAML frontmatter |
| 字段 | 是否必填? | 含义 | |
|---|---|---|---|
| 输入 | 要讲解的 lifecycle/sequence | 是 | 真实步骤顺序,以及每一步会读取或写入哪些文件 |
| 输入 | 文件夹树(文件 + actors) | 是 | 每个文件都有一个创建步骤 |
| 输出 | | 是 | 单文件,基于 docs-site-macos,并自动托管 |
| 输出 | 草稿输出报告 + index + log | 是 | 使用 OKF YAML frontmatter |
Rules và capabilities
规则与能力
Hard-won rules (distilled — do NOT relearn these). These are corrections from real use. Violating them makes the page confusing:
- RULE-01 (MUST): Cursor lives in the LEFT GUTTER, never over content. It is a small right-pointing arrow at , moving mostly vertically. A mouse-pointer glyph placed on the row covers the text and reads as clutter. → use
x = rowLeft − ~22px-style arrow in the gutter. Smooth motion:▶andleftMUST share the same duration + easing (e.g.top) — mismatched timings (e.g. left .32s, top .5s) make diagonal moves jerk because x lands before y. Add.5s cubic-bezier(.45,.05,.2,1).will-change:left,top - RULE-02 (MUST): Number every visited node (inline seq badge). When paused, the viewer must still read the order ①②③. A moving cursor alone is unreadable when frozen.
- RULE-03 (MUST): Default at rest = the FULL final frame of the step, not the empty first frame. On load show the complete frame (all nodes hit, caption full). Never show an empty "frame 0" with nothing on it.
- RULE-04 (MUST): Files do not exist until created. Before a file's "born" step it is (absent from the tree — NOT faded/ghost). It appears (types in) exactly at the step that creates it. The tree fills up over time. Keep an explicit empty "before install" step so the empty state is actually visible.
display:none - RULE-05 (MUST): Appear like a TRANSCRIPT, not copy-paste pop. New file rows reveal with a clip typewriter; the caption streams char-by-char. The transcript is the master clock — the frame advances at the transcript's speed, not a fixed timer.
- RULE-06 (MUST): Go SLOW. Reading speed beats motion. ~30ms/char, long dwell at end of frame. People give up if it rushes.
- RULE-07 (MUST): Color by ROLE inside a step, not one color for everything. The biggest confusion: copy-FROM (source) and copy-TO (dest) tinted the same → you can't tell direction. Source = blue "đọc", dest = teal "ghi/tạo", pass = grey, deny = red, ok = green, leak = amber. Put a text tag on the row too.
- RULE-08 (MUST): Per-STEP accent goes on the LEFT list + caption chip only (so steps are distinguishable in the list) — the RIGHT nodes use ROLE colors. Two color systems, two jobs; don't mix them on the same element.
- RULE-09 (MUST): The caption under the frame must NOT duplicate the left bar. Left = compact nav (label + title only). Right caption = the detailed description + flow for the current frame. Full duplication makes people dismiss both as redundant.
- RULE-10 (MUST): Left column is narrow; the animation gets the space. .
grid-template-columns: minmax(190px,.5fr) 1.5fr - RULE-11 (MUST): Two modes: "Tự bước" (⏭ plays one frame's transcript then STOPS) and "Tự chạy" (auto-advance, slow). Default = paused/manual. Respect (skip animation, show full frames).
prefers-reduced-motion - RULE-12 (MUST): Captions = plain language, never jargon/caveman. Each frame's caption () must read as full sentences for someone OUTSIDE the project. Expand every term on first use: a "hook" → "the move the runtime makes before each action"; "R1/R2" → the rule in actual words ("the rule that forbids writing to raw/"); "exit 2 / exit 0" → "code 2 = BLOCK / code 0 = PASS"; "assertion" → "a check that says the result must be X"; "layer=repo" → "the check that runs at commit/PR time, on the changed files". Say what is READ vs WRITTEN and WHY. A terse symbol caption like "PreToolUse → LÕI → R1 → exit 2" reads as cryptic and viewers skip it — write the sentence; let the short
dline carry the shorthand. (Longerflow⇒ lower the per-char type speed, ~18ms, so it doesn't drag.)d - Capabilities: read the skill; write one HTML file + draft/index/log; run a local HTML parse check and open the page via the auto-host server.
/docs-site-macos
这些是实战中总结出的规则(已提炼——不要重复学习)。它们源自实际使用中的修正;违反这些规则会让页面变得令人困惑:
- RULE-01(必须):**光标必须位于左侧装订线区域,绝不能覆盖内容。**它是一个位于 的小型右向箭头,主要沿垂直方向移动。放在行上的鼠标指针字形会遮挡文字,看起来杂乱。→ 使用装订线中的
x = rowLeft − ~22px风格箭头。平滑运动:▶和left必须使用相同的时长与 easing(例如top);时长不一致(例如 left 为 .32s、top 为 .5s)会导致斜向移动卡顿,因为 x 会先于 y 到位。添加.5s cubic-bezier(.45,.05,.2,1)。will-change:left,top - RULE-02(必须):**为每个访问过的节点编号(内联 seq badge)。**暂停时,观看者仍必须能够读出顺序 ①②③。仅有移动光标在画面冻结后无法阅读。
- RULE-03(必须):**静止时的默认状态 = 当前步骤的完整最终画面,而非空白的第一帧。**加载时显示完整画面(所有节点均已命中,字幕完整)。绝不显示没有任何内容的“第 0 帧”。
- RULE-04(必须):**文件在被创建前不存在。**在文件的 born 步骤之前,它应为 (从树中完全缺席,而不是淡化或显示为幽灵)。它只会在创建它的那一步出现(逐字输入)。树会随时间逐步填充。保留一个明确的空白“before install”步骤,让空状态真正可见。
display:none - RULE-05(必须):**呈现效果应像文字稿,而不是复制粘贴式弹出。**新文件行通过 clip typewriter 显现;字幕逐字符流出。文字稿是主时钟——画面按文字稿的速度推进,而不是使用固定计时器。
- RULE-06(必须):**放慢速度。**阅读速度比运动效果更重要。约 30ms/字符,并在每帧末尾留出较长停留时间。节奏太快会让用户放弃观看。
- RULE-07(必须):在步骤内部按角色着色,而不是所有元素使用同一种颜色。最大的困惑来源是 copy-FROM(源)和 copy-TO(目标)使用相同色调,导致无法判断方向。Source = 蓝色 (读取),dest = 青绿色
đọc(写入/创建),pass = 灰色,deny = 红色,ok = 绿色,leak = 琥珀色。行上也要放置文本标签。ghi/tạo - RULE-08(必须):每一步的强调色仅用于左侧列表和字幕 chip(以便在列表中区分步骤)。右侧节点使用角色颜色。这是两套各有用途的颜色系统;不要在同一元素上混用。
- RULE-09(必须):**画面下方的字幕不得重复左侧栏内容。**左侧 = 紧凑导航(仅标签 + 标题)。右侧字幕 = 当前帧的详细说明和 flow。完整重复会让人认为两处内容都冗余。
- RULE-10(必须):左列较窄;动画获得更多空间。。
grid-template-columns: minmax(190px,.5fr) 1.5fr - RULE-11(必须):提供两种模式:“Tự bước”(⏭ 播放一帧的文字稿后停止)和“Tự chạy”(缓慢自动前进)。默认 = 暂停/手动。遵循 (跳过动画,显示完整画面)。
prefers-reduced-motion - RULE-12(必须):**字幕使用通俗语言,绝不使用晦涩术语或粗野黑话。**每帧字幕()都应使用完整句子,让项目之外的人也能理解。首次使用时应展开所有术语:
d→ “runtime 在每次操作前执行的动作”;hook→ 规则的实际措辞(“禁止写入 raw/ 的规则”);R1/R2→ “code 2 = BLOCK / code 0 = PASS”;exit 2 / exit 0→ “一项要求结果必须为 X 的检查”;assertion→ “在 commit/PR 时针对 changed files 运行的检查”。说明读取了什么、写入了什么,以及原因。像“PreToolUse → LÕI → R1 → exit 2”这样的简短符号字幕晦涩难懂,观看者会直接跳过——应写出完整句子,让简短的layer=repo行负责承载速记表达。(flow越长,每字符的打字速度越慢,约 18ms,以免拖沓。)d - 能力:读取 skill;编写一个 HTML 文件以及 draft/index/log;运行本地 HTML 解析检查,并通过 auto-host server 打开页面。
/docs-site-macos
Failure boundaries
失败边界
- Page without viewport meta → responsive grid breaks on mobile: failed, do not ship.
- HTML parse check raises → failed, fix before hosting.
- A frame unreadable when paused (no seq badges, empty frame 0, caption duplicating the left bar) → failed against RULE-02/03/09, fix and re-click through.
- 页面缺少 viewport meta → 移动端的响应式网格失效:失败,不得发布。
- HTML parse check 报错 → 失败,托管前必须修复。
- 暂停时某帧无法阅读(缺少 seq badge、显示空的第 0 帧、字幕重复左侧栏)→ 违反 RULE-02/03/09,失败;修复后重新逐步点击检查。
HOW
实施(HOW)
Main workflow
主要工作流
| Step | Type | Inputs | Action | Outputs/exit | Failure/next |
|---|---|---|---|---|---|
| W01 | effect | docs-site-macos conventions | Generate base page | glass base at | — |
| W02 | effect | base page | Replace body with hero + controls + lifecycle + legend | structure | — |
| W03 | judgment | real file list | Author tree rows with | tree | — |
| W04 | judgment | lifecycle | Author | data | — |
| W05 | effect | Reference engine | Drop in engine JS + CSS deltas; default paused/static | working page | — |
| W06 | deterministic | page | Validate: HTML parse + click ⏭ through every step while paused | every frame readable | not readable → fix, repeat W06 |
Chi tiết từng bước (nguồn chân lý cho W01–W06):
- Generate the base page with conventions (glass CSS, fonts, scrollbar, background plane, output to
/docs-site-macos, auto-host).llmwiki/html/DDMMYY-<slug>.html - Replace the body with the structure above.
hero + controls + .lifecycle(left steps / right tree-pane) + legend - Author the folder tree: one per file, each starting with
.trow id="f-*" data-born="…"; actor chips in<span class="seqslot"></span>likewise..controllers - Author : order them as a real lifecycle, include an explicit empty "before" step first; tag each node's
STEPS[](src/dst); addrole/verdict/leakwhere relevant.marks - Drop in the engine JS + CSS deltas. Default to paused/static; ⏭ steps, ▶ auto-plays slowly.
- Validate: ; open via the auto-host server; click ⏭ through every step and check each frame reads clearly when paused.
python3 -c "import html.parser; html.parser.HTMLParser().feed(open(F).read())"
| 步骤 | 类型 | 输入 | 操作 | 输出/退出条件 | 失败/下一步 |
|---|---|---|---|---|---|
| W01 | effect(执行) | docs-site-macos 约定 | 生成基础页面 | 位于 | — |
| W02 | effect(执行) | 基础页面 | 将 body 替换为 hero + controls + lifecycle + legend | 页面结构 | — |
| W03 | judgment(判断) | 真实文件列表 | 编写带 | 文件夹树 | — |
| W04 | judgment(判断) | lifecycle | 编写 | 数据 | — |
| W05 | effect(执行) | 参考引擎 | 加入引擎 JS 和 CSS 增量;默认为暂停/静态状态 | 可用页面 | — |
| W06 | deterministic(确定性) | 页面 | 验证:执行 HTML parse,并在暂停状态下点击 ⏭ 遍历每个步骤 | 每帧均可阅读 | 无法阅读 → 修复并重复 W06 |
以下逐步细节是 W01–W06 的可靠依据:
- 按照 约定生成基础页面(玻璃 CSS、字体、滚动条、背景平面、输出至
/docs-site-macos、自动托管)。llmwiki/html/DDMMYY-<slug>.html - 将 body 替换为上述 结构。
hero + controls + .lifecycle(left steps / right tree-pane) + legend - 编写文件夹树:每个文件对应一行 ,且每行以
.trow id="f-*" data-born="…"开头;<span class="seqslot"></span>中的 actor chips 同样处理。.controllers - 编写 :按真实 lifecycle 排序,第一项必须是明确的空白步骤;标记每个节点的
STEPS[](src/dst);在适当位置添加role/verdict/leak。marks - 加入引擎 JS 和 CSS 增量。默认为暂停/静态状态;⏭ 单步前进,▶ 缓慢自动播放。
- 验证:;通过 auto-host server 打开页面;在暂停状态下点击 ⏭ 遍历每个步骤,并检查每一帧是否都能清晰阅读。
python3 -c "import html.parser; html.parser.HTMLParser().feed(open(F).read())"
Branches
分支
| ID | Kind | Guard | Hành vi | Skip / failure | Rejoin |
|---|---|---|---|---|---|
| B01 | conditional_required | | skip animation, show full frames (RULE-11) | — | W06 |
| B02 | user_optional | viewer presses ▶ "Tự chạy" | auto-advance slowly; ⏭ plays one frame then stops | default = paused/manual | W06 |
| ID | 类型 | 条件 | 行为 | 跳过/失败 | 汇合点 |
|---|---|---|---|---|---|
| B01 | conditional_required(必需条件) | | 跳过动画,显示完整画面(RULE-11) | — | W06 |
| B02 | user_optional(用户可选) | 观看者按下 ▶“Tự chạy” | 缓慢自动前进;⏭ 播放一帧后停止 | 默认 = 暂停/手动 | W06 |
Validation và stopping
验证与停止条件
Deterministic: HTML parse check. Needs eyes: click ⏭ through every step and confirm each frame reads clearly when paused. Stop when every frame passes; then write the output report.
确定性检查:HTML parse check。仍需人工检查:在暂停状态下点击 ⏭ 遍历每个步骤,确认每一帧都能清晰阅读。当所有画面均通过检查后停止,然后编写输出报告。
Examples
示例
- Positive: "làm trang hoạt họa life cycle cài harness" → STEPS starts with empty "before install", step 1 cursor visits ,
c-install → f-policy → f-clitypes in teal "ghi/tạo"; paused frame shows ①②③ badges and full caption.f-policy - Boundary/failure: source and dest rows both tinted the step accent → viewer cannot tell copy direction → violates RULE-07/08; switch right-pane nodes to ROLE colors (src blue "đọc", dst teal "ghi/tạo") with text tags.
- 正向示例:“làm trang hoạt họa life cycle cài harness”→ 以空白的“before install”开始;步骤 1 中光标依次访问
STEPS;c-install → f-policy → f-cli以青绿色f-policy逐字出现;暂停画面显示 ①②③ 徽章和完整字幕。ghi/tạo - **边界/失败示例:**source 和 dest 行都使用步骤强调色着色 → 观看者无法判断复制方向 → 违反 RULE-07/08;应将右侧窗格节点改为角色颜色(src 为蓝色 ,dst 为青绿色
đọc),并添加文本标签。ghi/tạo
Reference — Page structure
参考——页面结构
hero (title + 1-line how-to-read)
controls: ⏮ ⏭ Bước tiếp ▶ Tự chạy <hint> <phase chip> <n / N>
.lifecycle (grid: narrow left | wide right)
├─ .steps (LEFT) — compact cards: <span class=sp>label</span><h3>title</h3> (NO paragraph)
└─ .tree-pane (RIGHT, sticky glass)
├─ chrome dots + title
├─ .controllers — actor chips (installer / agent / git / CI), each with a .seqslot
├─ .tree — rows with id=f-*, data-born="<step|−1 pre-exist|99 never>", leading .seqslot
├─ .frame-cap — fcNum / fcSp / fcH / fcD(streams) / fcFlow (the per-frame caption)
├─ .cursor — gutter arrow (fill=currentColor)
└─ .verdict + .leak — floating tags on the RIGHT side near the active row
legend: đọc(blue) · ghi(teal) · cho qua(green) · chặn(red) · lọt(amber)hero (title + 1-line how-to-read)
controls: ⏮ ⏭ Bước tiếp ▶ Tự chạy <hint> <phase chip> <n / N>
.lifecycle (grid: narrow left | wide right)
├─ .steps (LEFT) — compact cards: <span class=sp>label</span><h3>title</h3> (NO paragraph)
└─ .tree-pane (RIGHT, sticky glass)
├─ chrome dots + title
├─ .controllers — actor chips (installer / agent / git / CI), each with a .seqslot
├─ .tree — rows with id=f-*, data-born="<step|−1 pre-exist|99 never>", leading .seqslot
├─ .frame-cap — fcNum / fcSp / fcH / fcD(streams) / fcFlow (the per-frame caption)
├─ .cursor — gutter arrow (fill=currentColor)
└─ .verdict + .leak — floating tags on the RIGHT side near the active row
legend: đọc(blue) · ghi(teal) · cho qua(green) · chặn(red) · lọt(amber)Reference — STEP data model
参考——STEP 数据模型
js
const STEPS = [
{ ph:'install'|'run', // phase (left chip text)
sp:'CÀI · B0', // short label
h:'Đặt lõi vào repo', // title (left + caption)
d:'... mô tả đầy đủ ...', // detailed narration → ONLY in right caption, streams
flow:'installer → policy.yaml', // 1-line data-flow summary
chain:['c-install','f-policy','f-cli'], // node ids the cursor visits IN ORDER
role:{'f-policy':'dst','f-cli':'dst'}, // per-node role: 'src'|'dst' (pass/actor inferred)
marks:{'f-x':'warn','f-y':'deny'}, // optional: override role on specific nodes
leak:'f-wiki', // optional: node that "leaked" (amber tag)
verdict:{kind:'deny'|'ok'|'neutral', text:'exit 2 · CHẶN'} }, // optional: end badge
];data-born-199born === curborn < curjs
const STEPS = [
{ ph:'install'|'run', // phase (left chip text)
sp:'CÀI · B0', // short label
h:'Đặt lõi vào repo', // title (left + caption)
d:'... mô tả đầy đủ ...', // detailed narration → ONLY in right caption, streams
flow:'installer → policy.yaml', // 1-line data-flow summary
chain:['c-install','f-policy','f-cli'], // node ids the cursor visits IN ORDER
role:{'f-policy':'dst','f-cli':'dst'}, // per-node role: 'src'|'dst' (pass/actor inferred)
marks:{'f-x':'warn','f-y':'deny'}, // optional: override role on specific nodes
leak:'f-wiki', // optional: node that "leaked" (amber tag)
verdict:{kind:'deny'|'ok'|'neutral', text:'exit 2 · CHẶN'} }, // optional: end badge
];每个文件行上的 表示创建该文件的步骤索引( = 预先存在的 vendor 文件, = 从未创建,例如写入被阻止的尝试)。 的文件会在当前步骤逐字输入; 的文件已经存在;其余文件保持隐藏。
data-born-199born === curborn < curReference — Core JS (the engine — reproduce faithfully)
参考——核心 JS(引擎——须忠实复现)
js
const PAL=[{c:'#0a84ff',bg:'rgba(10,132,255,.12)'},{c:'#30b0c7',bg:'rgba(48,176,199,.13)'},
{c:'#5856d6',bg:'rgba(88,86,214,.12)'},{c:'#34c759',bg:'rgba(52,199,89,.14)'},
{c:'#ff9500',bg:'rgba(255,149,0,.15)'},{c:'#ff2d55',bg:'rgba(255,45,85,.12)'}]; // màu mỗi step
const ROLEINFO={src:{c:'#0a84ff',t:'đọc',cls:'r-src'}, dst:{c:'#30b0c7',t:'ghi/tạo',cls:'r-dst'},
pass:{c:'#9aa3b2',t:'',cls:'r-pass'}, actor:{c:'#9aa3b2',t:'',cls:'r-pass'},
neutral:{c:'#0a84ff',t:'',cls:'r-pass'}, deny:{c:'#e0264b',t:'chặn',cls:'deny'},
ok:{c:'#34c759',t:'cho qua',cls:'ok'}, warn:{c:'#f0902a',t:'lọt',cls:'warn'},
attempt:{c:'#e0264b',t:'',cls:'deny'}};
let cur=0, auto=false, timers=[];
const clear=()=>{timers.forEach(clearTimeout);timers=[]};
// con trỏ ở GUTTER trái (x = rowLeft − 22), y = giữa dòng
const at=id=>{const el=document.getElementById(id),pr=pane.getBoundingClientRect(),r=el.getBoundingClientRect();
return {gx:Math.max(2,r.left-pr.left-22), y:r.top-pr.top+r.height/2, el};};
// hiện nếu pre-existing(-1) hoặc đã tạo ở bước TRƯỚC (b<i); born===i sẽ "gõ" ra trong bước này
function applyVis(i){document.querySelectorAll('.trow[data-born]').forEach(e=>{
const b=+e.dataset.born; e.classList.toggle('notyet', !((b===-1)||(b!==99&&b<i)));});}
function prep(){ const s=STEPS[cur];
/* left active card, prog, phase, caption (fcNum/fcSp/fcH/fcD=full/fcFlow) */
const a=PAL[cur%PAL.length], rs=document.documentElement.style;
rs.setProperty('--ac',a.c); rs.setProperty('--acbg',a.bg); // accent PER-STEP (trái + chip)
document.querySelectorAll('.trow,.chip').forEach(e=>e.classList.remove('hit','deny','ok','warn','attempt','born-now','r-src','r-dst','r-pass'));
document.querySelectorAll('.rtag').forEach(t=>t.remove());
document.querySelectorAll('.seqslot').forEach(s2=>{s2.textContent='';s2.className='seqslot';});
applyVis(cur); return s; }
function paint(idx,s){ const id=s.chain[idx], last=idx===s.chain.length-1, vk=s.verdict?.kind||'';
const el=document.getElementById(id); el.classList.remove('notyet'); const p=at(id);
let role = id==='f-raw' ? 'attempt'
: (s.marks&&s.marks[id]) || (last&&vk) || (s.role&&s.role[id]) || (id.indexOf('c-')===0?'actor':'pass');
const ri=ROLEINFO[role]||ROLEINFO.pass;
el.classList.add('hit'); if(ri.cls)el.classList.add(ri.cls); if(id==='f-raw')el.classList.add('attempt');
const slot=el.querySelector('.seqslot'); if(slot){slot.textContent=idx+1; slot.className='seqslot on '+(ri.cls||'');}
if(ri.t && id.indexOf('c-')!==0){const tag=document.createElement('span');tag.className='rtag '+ri.cls;tag.textContent=ri.t;el.appendChild(tag);}
cursor.style.left=p.gx+'px'; cursor.style.top=(p.y-9)+'px'; cursor.style.color=ri.c; // cursor đổi màu theo vai trò
/* leak tag + verdict tag positioned on the RIGHT side near p.y */ }
function revealBorn(i){document.querySelectorAll('.trow[data-born]').forEach(e=>{if(+e.dataset.born===i)e.classList.remove('notyet');});}
function typeRow(e,dur){e.classList.remove('notyet'); if(dur<=0)return; e.style.setProperty('--td',dur+'ms');
e.classList.add('typing'); timers.push(setTimeout(()=>e.classList.remove('typing'),dur+40));}
function typeText(el,txt,per){el.textContent='';el.classList.add('streaming');let i=0;
const tick=()=>{el.textContent=txt.slice(0,i); i++<txt.length?timers.push(setTimeout(tick,per)):el.classList.remove('streaming');};tick();}
function full(){const s=prep(); revealBorn(cur); s.chain.forEach((id,idx)=>paint(idx,s));} // TĨNH = frame đầy đủ
function animate(){const s=prep();
if(reduce){revealBorn(cur); s.chain.forEach((id,idx)=>paint(idx,s)); return;}
const per=30, capDur=Math.max(1600, s.d.length*per); // transcript = đồng hồ; CHẬM
typeText(document.getElementById('fcD'), s.d, per);
const born=[...document.querySelectorAll('.trow[data-born]')].filter(e=>+e.dataset.born===cur);
let bt=400; const slot=born.length?(capDur*0.55)/born.length:0;
born.forEach(e=>{timers.push(setTimeout(()=>typeRow(e,Math.min(slot*0.8,700)),bt)); bt+=slot;});
const n=Math.max(1,s.chain.length);
s.chain.forEach((id,idx)=>timers.push(setTimeout(()=>paint(idx,s), 300+Math.round(idx*(capDur-300)/n))));
if(auto) timers.push(setTimeout(()=>step(cur+1), capDur+2200)); // CHỈ tự sang khi auto
}
function step(i){clear(); cur=(i+STEPS.length)%STEPS.length; animate();} // Tự bước: gõ 1 frame rồi dừng
// prev/next: auto=false; step(±1). play: auto=!auto; auto?step(cur):full().
// LOAD: requestAnimationFrame(()=>setTimeout(()=>{cur=0;full();},200)); // mặc định TĨNH frame đầy đủjs
const PAL=[{c:'#0a84ff',bg:'rgba(10,132,255,.12)'},{c:'#30b0c7',bg:'rgba(48,176,199,.13)'},
{c:'#5856d6',bg:'rgba(88,86,214,.12)'},{c:'#34c759',bg:'rgba(52,199,89,.14)'},
{c:'#ff9500',bg:'rgba(255,149,0,.15)'},{c:'#ff2d55',bg:'rgba(255,45,85,.12)'}]; // màu mỗi step
const ROLEINFO={src:{c:'#0a84ff',t:'đọc',cls:'r-src'}, dst:{c:'#30b0c7',t:'ghi/tạo',cls:'r-dst'},
pass:{c:'#9aa3b2',t:'',cls:'r-pass'}, actor:{c:'#9aa3b2',t:'',cls:'r-pass'},
neutral:{c:'#0a84ff',t:'',cls:'r-pass'}, deny:{c:'#e0264b',t:'chặn',cls:'deny'},
ok:{c:'#34c759',t:'cho qua',cls:'ok'}, warn:{c:'#f0902a',t:'lọt',cls:'warn'},
attempt:{c:'#e0264b',t:'',cls:'deny'}};
let cur=0, auto=false, timers=[];
const clear=()=>{timers.forEach(clearTimeout); timers=[]};
// con trỏ ở GUTTER trái (x = rowLeft − 22), y = giữa dòng
const at=id=>{const el=document.getElementById(id),pr=pane.getBoundingClientRect(),r=el.getBoundingClientRect();
return {gx:Math.max(2,r.left-pr.left-22), y:r.top-pr.top+r.height/2, el};};
// hiện nếu pre-existing(-1) hoặc đã tạo ở bước TRƯỚC (b<i); born===i sẽ "gõ" ra trong bước này
function applyVis(i){document.querySelectorAll('.trow[data-born]').forEach(e=>{
const b=+e.dataset.born; e.classList.toggle('notyet', !((b===-1)||(b!==99&&b<i)));});}
function prep(){ const s=STEPS[cur];
/* left active card, prog, phase, caption (fcNum/fcSp/fcH/fcD=full/fcFlow) */
const a=PAL[cur%PAL.length], rs=document.documentElement.style;
rs.setProperty('--ac',a.c); rs.setProperty('--acbg',a.bg); // accent PER-STEP (trái + chip)
document.querySelectorAll('.trow,.chip').forEach(e=>e.classList.remove('hit','deny','ok','warn','attempt','born-now','r-src','r-dst','r-pass'));
document.querySelectorAll('.rtag').forEach(t=>t.remove());
document.querySelectorAll('.seqslot').forEach(s2=>{s2.textContent='';s2.className='seqslot';});
applyVis(cur); return s; }
function paint(idx,s){ const id=s.chain[idx], last=idx===s.chain.length-1, vk=s.verdict?.kind||'';
const el=document.getElementById(id); el.classList.remove('notyet'); const p=at(id);
let role = id==='f-raw' ? 'attempt'
: (s.marks&&s.marks[id]) || (last&&vk) || (s.role&&s.role[id]) || (id.indexOf('c-')===0?'actor':'pass');
const ri=ROLEINFO[role]||ROLEINFO.pass;
el.classList.add('hit'); if(ri.cls)el.classList.add(ri.cls); if(id==='f-raw')el.classList.add('attempt');
const slot=el.querySelector('.seqslot'); if(slot){slot.textContent=idx+1; slot.className='seqslot on '+(ri.cls||'');}
if(ri.t && id.indexOf('c-')!==0){const tag=document.createElement('span');tag.className='rtag '+ri.cls;tag.textContent=ri.t;el.appendChild(tag);}
cursor.style.left=p.gx+'px'; cursor.style.top=(p.y-9)+'px'; cursor.style.color=ri.c; // cursor đổi màu theo vai trò
/* leak tag + verdict tag positioned on the RIGHT side near p.y */ }
function revealBorn(i){document.querySelectorAll('.trow[data-born]').forEach(e=>{if(+e.dataset.born===i)e.classList.remove('notyet');});}
function typeRow(e,dur){e.classList.remove('notyet'); if(dur<=0)return; e.style.setProperty('--td',dur+'ms');
e.classList.add('typing'); timers.push(setTimeout(()=>e.classList.remove('typing'),dur+40));}
function typeText(el,txt,per){el.textContent='';el.classList.add('streaming');let i=0;
const tick=()=>{el.textContent=txt.slice(0,i); i++<txt.length?timers.push(setTimeout(tick,per)):el.classList.remove('streaming');};tick();}
function full(){const s=prep(); revealBorn(cur); s.chain.forEach((id,idx)=>paint(idx,s));} // TĨNH = frame đầy đủ
function animate(){const s=prep();
if(reduce){revealBorn(cur); s.chain.forEach((id,idx)=>paint(idx,s)); return;}
const per=30, capDur=Math.max(1600, s.d.length*per); // transcript = đồng hồ; CHẬM
typeText(document.getElementById('fcD'), s.d, per);
const born=[...document.querySelectorAll('.trow[data-born]')].filter(e=>+e.dataset.born===cur);
let bt=400; const slot=born.length?(capDur*0.55)/born.length:0;
born.forEach(e=>{timers.push(setTimeout(()=>typeRow(e,Math.min(slot*0.8,700)),bt)); bt+=slot;});
const n=Math.max(1,s.chain.length);
s.chain.forEach((id,idx)=>timers.push(setTimeout(()=>paint(idx,s), 300+Math.round(idx*(capDur-300)/n))));
if(auto) timers.push(setTimeout(()=>step(cur+1), capDur+2200)); // CHỈ tự sang khi auto
}
function step(i){clear(); cur=(i+STEPS.length)%STEPS.length; animate();} // Tự bước: gõ 1 frame rồi dừng
// prev/next: auto=false; step(±1). play: auto=!auto; auto?step(cur):full().
// LOAD: requestAnimationFrame(()=>setTimeout(()=>{cur=0;full();},200)); // mặc định TĨNH frame đầy đủReference — Essential CSS deltas (beyond docs-site-macos)
参考——必要 CSS 增量(docs-site-macos 之外)
css
.lifecycle{display:grid;grid-template-columns:minmax(190px,.5fr) 1.5fr;gap:22px;align-items:start}
.steps{max-height:74vh;overflow-y:auto} .step{opacity:.62} .step.active{opacity:1;border-left:3px solid var(--ac)}
.tree-pane{position:sticky;top:18px} .trow{display:flex;align-items:center;white-space:pre;border-radius:8px;padding:5px 8px}
.seqslot{display:inline-flex;align-items:center;justify-content:center;width:17px;height:17px;margin-right:8px;border-radius:50%;font-size:10px;font-weight:800;background:transparent;color:transparent;border:1px solid rgba(30,90,170,.1)}
.seqslot.r-src{background:#0a84ff;color:#fff;border-color:transparent}
.seqslot.r-dst{background:#30b0c7;color:#fff;border-color:transparent}
.seqslot.r-pass{background:#9aa3b2;color:#fff;border-color:transparent}
.trow.hit.r-src{background:rgba(10,132,255,.13);box-shadow:inset 0 0 0 1px #0a84ff}
.trow.hit.r-dst{background:rgba(48,176,199,.17);box-shadow:inset 0 0 0 1px #30b0c7}
.trow.hit.r-pass{background:rgba(140,150,165,.12);box-shadow:inset 0 0 0 1px rgba(120,130,145,.5)}
.rtag{margin-left:9px;font-size:10px;font-weight:700;padding:1px 8px;border-radius:11px}
.rtag.r-src{background:rgba(10,132,255,.14);color:#0a84ff} .rtag.r-dst{background:rgba(48,176,199,.2);color:#1d7d8c}
.trow.notyet{display:none} /* CHƯA tạo → ẩn hẳn (không mờ) */
.trow.typing{overflow:hidden;animation:typeline var(--td,500ms) steps(30) both}
@keyframes typeline{from{clip-path:inset(0 100% 0 0)}to{clip-path:inset(0 0 0 0)}}
.cursor{position:absolute;z-index:7;will-change:left,top;color:var(--ac);
transition:left .5s cubic-bezier(.45,.05,.2,1),top .5s cubic-bezier(.45,.05,.2,1),color .3s ease} /* MƯỢT: left+top CÙNG duration+easing, đừng lệch */
.cursor svg path{fill:currentColor} /* arrow color = currentColor (set per role) */
.fc-sp{background:var(--acbg);color:var(--ac)} /* caption chip = per-step accent */css
.lifecycle{display:grid;grid-template-columns:minmax(190px,.5fr) 1.5fr;gap:22px;align-items:start}
.steps{max-height:74vh;overflow-y:auto} .step{opacity:.62} .step.active{opacity:1;border-left:3px solid var(--ac)}
.tree-pane{position:sticky;top:18px} .trow{display:flex;align-items:center;white-space:pre;border-radius:8px;padding:5px 8px}
.seqslot{display:inline-flex;align-items:center;justify-content:center;width:17px;height:17px;margin-right:8px;border-radius:50%;font-size:10px;font-weight:800;background:transparent;color:transparent;border:1px solid rgba(30,90,170,.1)}
.seqslot.r-src{background:#0a84ff;color:#fff;border-color:transparent}
.seqslot.r-dst{background:#30b0c7;color:#fff;border-color:transparent}
.seqslot.r-pass{background:#9aa3b2;color:#fff;border-color:transparent}
.trow.hit.r-src{background:rgba(10,132,255,.13);box-shadow:inset 0 0 0 1px #0a84ff}
.trow.hit.r-dst{background:rgba(48,176,199,.17);box-shadow:inset 0 0 0 1px #30b0c7}
.trow.hit.r-pass{background:rgba(140,150,165,.12);box-shadow:inset 0 0 0 1px rgba(120,130,145,.5)}
.rtag{margin-left:9px;font-size:10px;font-weight:700;padding:1px 8px;border-radius:11px}
.rtag.r-src{background:rgba(10,132,255,.14);color:#0a84ff} .rtag.r-dst{background:rgba(48,176,199,.2);color:#1d7d8c}
.trow.notyet{display:none} /* CHƯA tạo → ẩn hẳn (không mờ) */
.trow.typing{overflow:hidden;animation:typeline var(--td,500ms) steps(30) both}
@keyframes typeline{from{clip-path:inset(0 100% 0 0)}to{clip-path:inset(0 0 0 0)}}
.cursor{position:absolute;z-index:7;will-change:left,top;color:var(--ac);
transition:left .5s cubic-bezier(.45,.05,.2,1),top .5s cubic-bezier(.45,.05,.2,1),color .3s ease} /* MƯỢT: left+top CÙNG duration+easing, đừng lệch */
.cursor svg path{fill:currentColor} /* arrow color = currentColor (set per role) */
.fc-sp{background:var(--acbg);color:var(--ac)} /* caption chip = per-step accent */Delivery — Output Report
交付——输出报告
Write a draft to , append to + .
Dùng YAML frontmatter (chuẩn OKF v0.1 — KHÔNG dùng bold , sẽ fail OKF):
proposellmwiki/wiki/sources/draft/DDMMYY-<ten>.mdwiki/index.mdwiki/log.md**Type:**markdown
---
type: draft
title: DDMMYY-<ten>
status: proposed
tags: [cursor-animated-sites, output-report]
timestamp: YYYY-MM-DD
---在 编写一个 草稿,并追加到 + 。
使用 YAML frontmatter(OKF v0.1 标准——不要使用粗体 ,否则会因 OKF 校验失败):
llmwiki/wiki/sources/draft/DDMMYY-<ten>.mdproposewiki/index.mdwiki/log.md**Type:**markdown
---
type: draft
title: DDMMYY-<ten>
status: proposed
tags: [cursor-animated-sites, output-report]
timestamp: YYYY-MM-DD
---DDMMYY-<ten>
DDMMYY-<ten>
What
What
<một câu — trang này dựng/quyết định cái gì>
<một câu — trang này dựng/quyết định cái gì>
Files
Files
| File | Action |
|---|---|
| created |
| File | Action |
|---|---|
| created |
Origin
Origin
- Draft:
wiki/sources/draft/DDMMYY-<ten>.md - Commit: (verify-before-commit điền)
undefined- Draft:
wiki/sources/draft/DDMMYY-<ten>.md - Commit: (verify-before-commit điền)
undefinedOrigin
来源
- Distilled by from the session that built
/orca-eval.llmwiki/html/250626-harness-lifecycle.html - Base theme: (
/docs-site-macos).~/.claude/skills/docs-site-macos/SKILL.md
- 由 提炼自构建
/orca-eval的会话。llmwiki/html/250626-harness-lifecycle.html - 基础主题:(
/docs-site-macos)。~/.claude/skills/docs-site-macos/SKILL.md