Loading...
Loading...
Build an interactive "cursor-animated walkthrough" page on top of the /docs-site-macos glass theme — a narrow LEFT step-list + wide RIGHT animated folder-tree where an arrow cursor sits in the gutter at the start of each line and moves controller→file per step, files TYPE IN like a transcript exactly when they are created (absent before), nodes are colored BY ROLE (source/read vs dest/write vs pass vs verdict) with text tags, each step has its own accent, there is a manual "step" mode and an auto-play mode, and a caption under the frame narrates the current frame. Use for explaining install→runtime lifecycles, sequences, data-flow, or any "how it works, step by step" walkthrough where the viewer must SEE which file each action touches. Hooks /docs-site-macos for the base glass design system.
npx skill4agent add rheinmir/setup cursor-animated-sites/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
/docs-site-macos/docs-site-macosSTEPS[] (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| 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 |
x = rowLeft − ~22px▶lefttop.5s cubic-bezier(.45,.05,.2,1)will-change:left,topdisplay:nonegrid-template-columns: minmax(190px,.5fr) 1.5frprefers-reduced-motiondflowd/docs-site-macos| 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 |
/docs-site-macosllmwiki/html/DDMMYY-<slug>.htmlhero + controls + .lifecycle(left steps / right tree-pane) + legend.trow id="f-*" data-born="…"<span class="seqslot"></span>.controllersSTEPS[]roleverdictleakmarkspython3 -c "import html.parser; html.parser.HTMLParser().feed(open(F).read())"| 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 |
c-install → f-policy → f-clif-policyhero (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)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 < curconst 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 đủ.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 */proposellmwiki/wiki/sources/draft/DDMMYY-<ten>.mdwiki/index.mdwiki/log.md**Type:**---
type: draft
title: DDMMYY-<ten>
status: proposed
tags: [cursor-animated-sites, output-report]
timestamp: YYYY-MM-DD
---
# DDMMYY-<ten>
## What
<một câu — trang này dựng/quyết định cái gì>
## Files
| File | Action |
|------|--------|
| `llmwiki/html/DDMMYY-<ten>.html` | created |
## Origin
- **Draft:** `wiki/sources/draft/DDMMYY-<ten>.md`
- **Commit:** _(verify-before-commit điền)_/orca-evalllmwiki/html/250626-harness-lifecycle.html/docs-site-macos~/.claude/skills/docs-site-macos/SKILL.md