cursor-animated-sites

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Skill: 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
/docs-site-macos
— reuse that skill's glass design system (background plane, glass tiers, scrollbar, fonts, ripple, output path
llmwiki/html/DDMMYY-<slug>.html
, auto-host). This skill ADDS the interactive walkthrough.
Inherit docs-site-macos's Accessibility & Document Head section too —
<meta viewport>
+
<title>
/
description
, inline favicon,
:focus-visible
ring on the ⏮/⏭/▶ controls, and the global
prefers-reduced-motion
guard (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.
构建一个单文件、自包含 HTML 演示,逐步让光标在文件夹树中移动。它是建立在
/docs-site-macos
之上的一个叠加层——复用该 skill 的玻璃设计系统(背景平面、玻璃层级、滚动条、字体、涟漪、输出路径
llmwiki/html/DDMMYY-<slug>.html
、自动托管)。此 skill 仅在现有页面上新增交互式演示。
同时继承 docs-site-macos 的 无障碍与文档头部(Accessibility & Document Head) 部分——
<meta viewport>
+
<title>
/
description
、内联 favicon、⏮/⏭/▶ 控件上的
:focus-visible
焦点环,以及全局
prefers-reduced-motion
防护(规则 11 已会跳过演示动画;该防护也会让光标和打字机效果静止)。不要在缺少 viewport meta 的情况下发布页面,否则移动端的响应式网格会失效。

WHAT

内容(WHAT)

Purpose và context

目的与上下文

  • Purpose: build a single-file, self-contained HTML walkthrough (layer on
    /docs-site-macos
    ) 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.
  • 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
    /docs-site-macos
    ; this skill only ADDS the interactive walkthrough.
  • **目的:**构建一个单文件、自包含 HTML 演示(叠加在
    /docs-site-macos
    之上),使装订线中的光标逐步从 controller 移动到 file;文件在创建时逐字输入;节点按角色着色;提供手动单步和自动播放模式;每帧配有说明字幕。
  • 触发条件(何时使用):
    • 讲解 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”。
  • 非目标:不重新定义玻璃设计系统(背景平面、玻璃层级、滚动条、字体、涟漪、输出路径、自动托管)——复用
    /docs-site-macos
    ;此 skill 仅
    新增
    交互式演示。

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 frame
.
STEPS[]
(ph · sp · h · d · flow · chain · role · marks · leak · verdict)+ 树节点行(data-born)→ 准备(每步的强调色、按 born 状态控制可见性)→ 动画(字幕文字稿作为主时钟,新节点逐字输入,光标按顺序访问 chain,角色颜色 + 序号徽章)→ 静止 = 完整的最终画面。

Input và output contract

输入与输出约定

FieldRequired?Ý nghĩa
Inlifecycle/sequence to explaincóreal order of steps + which files each step reads/writes
Infolder tree (files + actors)cóeach file has a birth step
Out
llmwiki/html/DDMMYY-<slug>.html
cósingle file, docs-site-macos base, auto-hosted
Outdraft output report + index + logcóOKF YAML frontmatter
字段是否必填?含义
输入要讲解的 lifecycle/sequence是真实步骤顺序,以及每一步会读取或写入哪些文件
输入文件夹树(文件 + actors)是每个文件都有一个创建步骤
输出
llmwiki/html/DDMMYY-<slug>.html
是单文件,基于 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
    x = rowLeft − ~22px
    , moving mostly vertically. A mouse-pointer glyph placed on the row covers the text and reads as clutter. → use
    ▶
    -style arrow in the gutter. Smooth motion:
    left
    and
    top
    MUST share the same duration + easing (e.g.
    .5s cubic-bezier(.45,.05,.2,1)
    ) — mismatched timings (e.g. left .32s, top .5s) make diagonal moves jerk because x lands before y. Add
    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
    display:none
    (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.
  • 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
    prefers-reduced-motion
    (skip animation, show full frames).
  • RULE-12 (MUST): Captions = plain language, never jargon/caveman. Each frame's caption (
    d
    ) 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
    flow
    line carry the shorthand. (Longer
    d
    ⇒ lower the per-char type speed, ~18ms, so it doesn't drag.)
  • Capabilities: read the
    /docs-site-macos
    skill; write one HTML file + draft/index/log; run a local HTML parse check and open the page via the auto-host server.
这些是实战中总结出的规则(已提炼——不要重复学习)。它们源自实际使用中的修正;违反这些规则会让页面变得令人困惑:
  • RULE-01(必须):**光标必须位于左侧装订线区域,绝不能覆盖内容。**它是一个位于
    x = rowLeft − ~22px
    的小型右向箭头,主要沿垂直方向移动。放在行上的鼠标指针字形会遮挡文字,看起来杂乱。→ 使用装订线中的
    ▶
    风格箭头。平滑运动:
    left
    和
    top
    必须使用相同的时长与 easing(例如
    .5s cubic-bezier(.45,.05,.2,1)
    );时长不一致(例如 left 为 .32s、top 为 .5s)会导致斜向移动卡顿,因为 x 会先于 y 到位。添加
    will-change:left,top
    。
  • RULE-02(必须):**为每个访问过的节点编号(内联 seq badge)。**暂停时,观看者仍必须能够读出顺序 ①②③。仅有移动光标在画面冻结后无法阅读。
  • RULE-03(必须):**静止时的默认状态 = 当前步骤的完整最终画面,而非空白的第一帧。**加载时显示完整画面(所有节点均已命中,字幕完整)。绝不显示没有任何内容的“第 0 帧”。
  • RULE-04(必须):**文件在被创建前不存在。**在文件的 born 步骤之前,它应为
    display:none
    (从树中完全缺席,而不是淡化或显示为幽灵)。它只会在创建它的那一步出现(逐字输入)。树会随时间逐步填充。保留一个明确的空白“before install”步骤,让空状态真正可见。
  • RULE-05(必须):**呈现效果应像文字稿,而不是复制粘贴式弹出。**新文件行通过 clip typewriter 显现;字幕逐字符流出。文字稿是主时钟——画面按文字稿的速度推进,而不是使用固定计时器。
  • RULE-06(必须):**放慢速度。**阅读速度比运动效果更重要。约 30ms/字符,并在每帧末尾留出较长停留时间。节奏太快会让用户放弃观看。
  • RULE-07(必须):在步骤内部按角色着色,而不是所有元素使用同一种颜色。最大的困惑来源是 copy-FROM(源)和 copy-TO(目标)使用相同色调,导致无法判断方向。Source = 蓝色
    đọc
    (读取),dest = 青绿色
    ghi/tạo
    (写入/创建),pass = 灰色,deny = 红色,ok = 绿色,leak = 琥珀色。行上也要放置
    文本标签
    。
  • 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
    )都应使用完整句子,让项目之外的人也能理解。首次使用时应展开所有术语:
    hook
    → “runtime 在每次操作前执行的动作”;
    R1/R2
    → 规则的实际措辞(“禁止写入 raw/ 的规则”);
    exit 2 / exit 0
    → “code 2 = BLOCK / code 0 = PASS”;
    assertion
    → “一项要求结果必须为 X 的检查”;
    layer=repo
    → “在 commit/PR 时针对 changed files 运行的检查”。说明读取了什么、写入了什么,以及原因。像“PreToolUse → LÕI → R1 → exit 2”这样的简短符号字幕晦涩难懂,观看者会直接跳过——应写出完整句子,让简短的
    flow
    行负责承载速记表达。(
    d
    越长,每字符的打字速度越慢,约 18ms,以免拖沓。)
  • 能力:读取
    /docs-site-macos
    skill;编写一个 HTML 文件以及 draft/index/log;运行本地 HTML 解析检查,并通过 auto-host server 打开页面。

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

主要工作流

StepTypeInputsActionOutputs/exitFailure/next
W01effectdocs-site-macos conventionsGenerate base pageglass base at
llmwiki/html/DDMMYY-<slug>.html
—
W02effectbase pageReplace body with hero + controls + lifecycle + legendstructure—
W03judgmentreal file listAuthor tree rows with
data-born
+ seqslot, actor chips
tree—
W04judgmentlifecycleAuthor
STEPS[]
with empty "before" step first, roles, verdict/leak/marks
data—
W05effectReference engineDrop in engine JS + CSS deltas; default paused/staticworking page—
W06deterministicpageValidate: HTML parse + click ⏭ through every step while pausedevery frame readablenot readable → fix, repeat W06
Chi tiết từng bước (nguồn chân lý cho W01–W06):
  1. Generate the base page with
    /docs-site-macos
    conventions (glass CSS, fonts, scrollbar, background plane, output to
    llmwiki/html/DDMMYY-<slug>.html
    , auto-host).
  2. Replace the body with the
    hero + controls + .lifecycle(left steps / right tree-pane) + legend
    structure above.
  3. Author the folder tree: one
    .trow id="f-*" data-born="…"
    per file, each starting with
    <span class="seqslot"></span>
    ; actor chips in
    .controllers
    likewise.
  4. Author
    STEPS[]
    : order them as a real lifecycle, include an explicit empty "before" step first; tag each node's
    role
    (src/dst); add
    verdict
    /
    leak
    /
    marks
    where relevant.
  5. Drop in the engine JS + CSS deltas. Default to paused/static; ⏭ steps, ▶ auto-plays slowly.
  6. Validate:
    python3 -c "import html.parser; html.parser.HTMLParser().feed(open(F).read())"
    ; open via the auto-host server; click ⏭ through every step and check each frame reads clearly when paused.
步骤类型输入操作输出/退出条件失败/下一步
W01effect(执行)docs-site-macos 约定生成基础页面位于
llmwiki/html/DDMMYY-<slug>.html
的玻璃基础页面
—
W02effect(执行)基础页面将 body 替换为 hero + controls + lifecycle + legend页面结构—
W03judgment(判断)真实文件列表编写带
data-born
+ seqslot 的树节点行以及 actor chips
文件夹树—
W04judgment(判断)lifecycle编写
STEPS[]
,首项为空白步骤,并设置角色、verdict/leak/marks
数据—
W05effect(执行)参考引擎加入引擎 JS 和 CSS 增量;默认为暂停/静态状态可用页面—
W06deterministic(确定性)页面验证:执行 HTML parse,并在暂停状态下点击 ⏭ 遍历每个步骤每帧均可阅读无法阅读 → 修复并重复 W06
以下逐步细节是 W01–W06 的可靠依据:
  1. 按照
    /docs-site-macos
    约定生成基础页面(玻璃 CSS、字体、滚动条、背景平面、输出至
    llmwiki/html/DDMMYY-<slug>.html
    、自动托管)。
  2. 将 body 替换为上述
    hero + controls + .lifecycle(left steps / right tree-pane) + legend
    结构。
  3. 编写文件夹树:每个文件对应一行
    .trow id="f-*" data-born="…"
    ,且每行以
    <span class="seqslot"></span>
    开头;
    .controllers
    中的 actor chips 同样处理。
  4. 编写
    STEPS[]
    :按真实 lifecycle 排序,第一项必须是明确的空白步骤;标记每个节点的
    role
    (src/dst);在适当位置添加
    verdict
    /
    leak
    /
    marks
    。
  5. 加入引擎 JS 和 CSS 增量。默认为暂停/静态状态;⏭ 单步前进,▶ 缓慢自动播放。
  6. 验证:
    python3 -c "import html.parser; html.parser.HTMLParser().feed(open(F).read())"
    ;通过 auto-host server 打开页面;在暂停状态下点击 ⏭ 遍历每个步骤,并检查每一帧是否都能清晰阅读。

Branches

分支

IDKindGuardHành viSkip / failureRejoin
B01conditional_required
prefers-reduced-motion: reduce
skip animation, show full frames (RULE-11)—W06
B02user_optionalviewer presses ▶ "Tự chạy"auto-advance slowly; ⏭ plays one frame then stopsdefault = paused/manualW06
ID类型条件行为跳过/失败汇合点
B01conditional_required(必需条件)
prefers-reduced-motion: reduce
跳过动画,显示完整画面(RULE-11)—W06
B02user_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-cli
    ,
    f-policy
    types in teal "ghi/tạo"; paused frame shows ①②③ badges and full caption.
  • 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”→
    STEPS
    以空白的“before install”开始;步骤 1 中光标依次访问
    c-install → f-policy → f-cli
    ;
    f-policy
    以青绿色
    ghi/tạo
    逐字出现;暂停画面显示 ①②③ 徽章和完整字幕。
  • **边界/失败示例:**source 和 dest 行都使用步骤强调色着色 → 观看者无法判断复制方向 → 违反 RULE-07/08;应将右侧窗格节点改为角色颜色(src 为蓝色
    đọc
    ,dst 为青绿色
    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
on each file row: the step index at which it is created (
-1
= pre-existing vendor file,
99
= never created e.g. a blocked write attempt). Files with
born === cur
type in this step;
born < cur
already present; otherwise hidden.
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
表示创建该文件的步骤索引(
-1
= 预先存在的 vendor 文件,
99
= 从未创建,例如写入被阻止的尝试)。
born === cur
的文件会在当前步骤逐字输入;
born < cur
的文件已经存在;其余文件保持隐藏。

Reference — 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
propose
draft to
llmwiki/wiki/sources/draft/DDMMYY-<ten>.md
, append to
wiki/index.md
+
wiki/log.md
. Dùng YAML frontmatter (chuẩn OKF v0.1 — KHÔNG dùng bold
**Type:**
, sẽ fail OKF):
markdown
---
type: draft
title: DDMMYY-<ten>
status: proposed
tags: [cursor-animated-sites, output-report]
timestamp: YYYY-MM-DD
---
在
llmwiki/wiki/sources/draft/DDMMYY-<ten>.md
编写一个
propose
草稿,并追加到
wiki/index.md
+
wiki/log.md
。 使用 YAML frontmatter(OKF v0.1 标准——不要使用粗体
**Type:**
,否则会因 OKF 校验失败):
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

FileAction
llmwiki/html/DDMMYY-<ten>.html
created
FileAction
llmwiki/html/DDMMYY-<ten>.html
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)
undefined

Origin

来源

  • Distilled by
    /orca-eval
    from the session that built
    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
    )。