Plain HTML/CSS/JS component (no framework) — vertical list of markers, each marker has date + title + source, reveal as you scroll.
WHAT
Purpose and context
- Purpose: add to the target page a vertical timeline with ONE time axis (date markers + title + source), scroll-reveal, responsive mobile→desktop at 768px, real data.
- Trigger (when to use):
- Page needs to list TIME-BASED MARKERS: changelog, project history, roadmap, writing archive, event timeline.
- User says "make a timeline", "dòng thời gian", "lịch sử dạng timeline".
- Non-goals: NOT for relationship/flow diagrams (that is
/diagram) or numeric data charts (that isdataviz) — this is only ONE linear time axis.
Mental model
dữ liệu mốc thật (API/markdown/CMS) → <li class="timeline__item"> (time + a + small) → IntersectionObserver gắn timeline__item--in → CSS transition hiện dần. The sample asset is a starting point to ADAPT, not a copy.
Input and output contract
| Field | Required? | Meaning | |
|---|---|---|---|
| In | target page | yes | where to attach the timeline |
| In | real marker data | yes | date (ISO) + title + link + source; without it you cannot wire it up (only demo faker available) |
| In | design.md / dark-mode-maker token |
no | if present, switch class/token per the project design system |
| Out | adapted HTML/CSS/JS | yes | no more faker import, BEM classes match CSS and JS |
| Out | verification evidence | yes | screenshots + test scroll through playwright-verify |
Rules and capabilities
- RULE-01 (MUST):
assets/timeline.jsline 1 importsfakerfromesm.shonly to GENERATE FAKE DATA for the demo (generateArticles()) — when wiring into a real project, DELETE that import +generateArticles(), replacethis.articleswith REAL data (API/markdown/CMS) before build(). Leaving the faker import in production is an unnecessary dependency + exposes fake data. - RULE-02 (MUST): Classes named per BEM (
timeline__item-time...) — renaming a class means renaming it in both CSS and JSquerySelector, do not change only one side. - RULE-03 (MUST): Threshold
threshold: 1ofIntersectionObservermeans the marker must be ENTIRELY in the viewport to appear — a marker taller than the viewport (long content) will never reach threshold 1, lower it to0.5if the marker has long content. - RULE-04 (MUST): Verify with
playwright-verify(capture + scroll test) after wiring real data, do not self-praise "it works" just because there are no console errors. - Capabilities: read the skill's sample asset; write the target page's front-end files; run a headless browser to capture/scroll check.
Failure boundaries
- No real milestone data yet → clarify data source; do not deliver a version that still has faker.
- The actual task is a relationship/flow diagram or a numeric chart → blocked, switch to
/diagramordataviz. - Verify with playwright shows milestones do not appear on scroll → failed, fix (e.g. lower threshold) then verify again.
HOW
Main workflow
| Step | Type | Inputs | Action | Outputs/exit | Failure/next |
|---|---|---|---|---|---|
| W01 | deterministic | skill assets | Read assets/timeline.html + assets/timeline.css + assets/timeline.js |
understand the structure | — |
| W02 | judgment | asset, design.md |
ADAPT into the target page: change class/token according to the project's design system (BEM synchronizing CSS + JS) | component in the page | no design.md → keep the sample tokens |
| W03 | effect | real data | Remove the faker import + generateArticles(), replace this.articles with REAL data before build() |
JS no longer has faker | missing data → clarify |
| W04 | judgment | project | Choose dark-mode: keep prefers-color-scheme or replace with token dark-mode-maker (B01) |
a single dark mechanism | — |
| W05 | deterministic | page | Verify with playwright-verify: capture + scroll test |
image + milestones fully visible | milestones do not appear → B02 |
Details for each step (source of truth for W01–W05):
Assets
assets/timeline.html + assets/timeline.css + assets/timeline.js — read then ADAPT into the target page (change class/token according to the project's design system if design.mdalready exists), do not copy mechanically as-is.
Mechanism
- Each milestone is
<li class="timeline__item">containing<time>(date,datetimestandard ISO attr) +<a>title +<small>source. IntersectionObserveradds classtimeline__item--inwhen the milestone scrolls into the viewport → CSS transition makes it "fade in" (opacity + translateX), do NOT animate directly with JS.- Responsive: mobile — milestone dot + connecting line on the left, date within the line.
≥768px— date splits into its own column on the left (position: absolute). - Dark theme via
@media (prefers-color-scheme: dark)— change 3 variables--bg/--fg/--primary; if the project already hasdark-mode-maker(active toggle, not just OS-based) then replace this block with the token variable ofdark-mode-maker, don't let two dark-mode mechanisms conflict with each other.
Branches
| ID | Kind | Guard | Behavior | Skip / failure | Rejoin |
|---|---|---|---|---|---|
| B01 | conditional_required | the project already has dark-mode-maker |
replace the block prefers-color-scheme with the token variable of dark-mode-maker |
none → keep the template block | W05 |
| B02 | recovery | the milestone has long content, taller than the viewport, never appears | lower threshold: 1 to 0.5 (RULE-03) |
still doesn't appear → failed, notify the user | W05 |
Validation and stopping
Done when: grep no longer finds faker/generateArticles in the target page's JS, the CSS class and JS match, and playwright-verify captures every milestone that appears after scrolling. No console errors is not enough to conclude (RULE-04).
Examples
- Positive: "make a changelog timeline from CHANGELOG.md" → adapt 3 assets, data parsed from markdown instead of
this.articles, remove faker → playwright scrolls and sees every milestone with classtimeline__item--in, desktop ≥768px the date is in the left column. - Boundary/failure: a roadmap milestone described longer than the screen height → with
threshold: 1milestones stuck at opacity 0 forever → B02 lowers0.5, verify again and see it appear.
Origin
- Compressed from
llmwiki/patterns/timeline/(reference snippet not yet attached to any skill, never git-tracked) into a real skill per the user's request on 2026-09-17 — in the same batch asblur.