Performance Safe Optimizations Implementation Plan
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: Improve runtime performance of the MkDocs site without changing visual effects, user-facing behavior, or deployment architecture.
Architecture: Apply four low-risk, isolated runtime optimizations in existing JS modules: listener lifecycle cleanup, short TTL API caching, JSON promise caching, and on-demand animation loop scheduling. Each task is independently verifiable and reversible.
Tech Stack: MkDocs Material, vanilla JavaScript, document$.subscribe lifecycle, browser DevTools (Network/Performance/Memory)
Preconditions
- Use current branch with working instant navigation behavior.
- Run local preview before and after each task.
Run:
mkdocs serve
Open: http://127.0.0.1:8000
Task 1: Add safe page-lifecycle listener cleanup in extra.js
Files:
- Modify: docs/javascripts/extra.js
- Verify: pages with floating TOC and draggable controls
Step 1: Create failing reproduction (manual test case)
Reproduction script: 1. Open a page with TOC floating panel. 2. Navigate between 8-10 markdown pages. 3. In DevTools, check behavior for duplicate triggers (drag/click handlers firing multiple times or delayed interactions).
Expected current issue before fix: potential handler accumulation over many navigations.
Step 2: Implement minimal lifecycle guard
Add one page-level AbortController (global variable). At each tcyInitPage() start:
- abort previous controller (if any)
- create new controller
- bind page-level document/window listeners with { signal: controller.signal }
Do not change listener business logic or UI structure.
Step 3: Verify no behavior changes
- TOC button opens/closes
- Drag behavior still works
- Outside-click close still works
- Resize reposition still works
Step 4: Verify listener cleanup effect
- Navigate 10+ times.
- Confirm interactions remain single-fire and responsive.
Step 5: Commit
git add docs/javascripts/extra.js
git commit -m "perf: clean up page-level listeners across instant navigation"
Task 2: Add 60s TTL status cache in tcy-status-monitor.js
Files:
- Modify: docs/javascripts/tcy-status-monitor.js
- Verify: status page/component containing #tcy-status-monitor
Step 1: Create failing reproduction (manual test case)
Reproduction script:
1. Open status page.
2. Switch to another page and back 2-3 times within 60 seconds.
3. In Network panel, observe repeated calls to api.mcsrvstat.us for all nodes.
Expected before fix: repeated full request burst each re-entry.
Step 2: Implement minimal TTL cache
Use window-scoped cache object:
- key: address
- value: { online, ts }
- TTL: 60,000 ms
Fetch path:
- if cache valid, return cached online state
- else fetch and refresh cache
- on fetch error, keep existing fallback behavior (false)
Do not alter card HTML or status labels.
Step 3: Verify behavior parity
- Same number of cards
- Same online/offline labels and colors
- Copy IP still works
Step 4: Verify network reduction
- Repeat navigation loop inside TTL window.
- Expected: significantly fewer API requests.
Step 5: Commit
git add docs/javascripts/tcy-status-monitor.js
git commit -m "perf: cache status checks with short TTL"
Task 3: Cache hitokoto JSON Promise in random-sentence.js
Files:
- Modify: docs/javascripts/random-sentence.js
- Verify: pages rendering #hitokoto-text
Step 1: Create failing reproduction (manual test case)
Reproduction script:
1. Open page with hitokoto.
2. Navigate away and back repeatedly.
3. Observe repeated hitokoto_bundle.json fetches in Network.
Expected before fix: repeated fetch/parse for same static bundle.
Step 2: Implement minimal Promise cache
Use window global slot for a single shared Promise:
- first run: create fetch(...).then(res=>res.json())
- subsequent runs: reuse same Promise
- keep random sentence selection per render
- keep existing catch fallback text
Step 3: Verify behavior parity
- Still shows sentence text each page entry
- Source text still updates when available
- Error fallback remains unchanged
Step 4: Verify network reduction
- Re-navigate in same tab session.
- Expected: JSON fetch only once (or served from memory cache path).
Step 5: Commit
git add docs/javascripts/random-sentence.js
git commit -m "perf: reuse hitokoto data promise across page transitions"
Task 4: Make cursor animation loop on-demand in cursor.js
Files:
- Modify: docs/javascripts/cursor.js
- Verify: any page with cursor effect enabled
Step 1: Create failing reproduction (manual test case)
Reproduction script: 1. Open site and do not move mouse. 2. Profile idle CPU in Performance panel. 3. Confirm animation loop still running continuously.
Expected before fix: persistent rAF loop even with zero particles.
Step 2: Implement minimal on-demand loop
- Track
rafIdandrunningflag. - Start loop only when particles are created.
- Stop loop when particle array becomes empty.
- Optional: pause while
document.hidden, resume on interaction.
Do not modify particle visuals, motion formulas, colors, or burst count.
Step 3: Verify behavior parity
- Mouse trail unchanged
- Click burst unchanged
- No visual regression in particle appearance
Step 4: Verify performance improvement
- Idle state: reduced scripting activity.
- Interaction state: effect appears immediately and smoothly.
Step 5: Commit
git add docs/javascripts/cursor.js
git commit -m "perf: run cursor animation loop only when needed"
Final Verification Checklist
Run after Task 4:
mkdocs serveand browse core pages (index,guide,update,tools) for regressions.- Confirm no console errors introduced.
- Confirm instant navigation still works for markdown-to-markdown transitions.
- Confirm music player remains stable across page transitions.
- Confirm TOC interactions unchanged.
- Compare Network panel before/after for status API + hitokoto bundle calls.
Rollback Strategy
If a regression appears, rollback only the affected file/task commit:
- Task 1 regression → rollback extra.js commit
- Task 2 regression → rollback tcy-status-monitor.js commit
- Task 3 regression → rollback random-sentence.js commit
- Task 4 regression → rollback cursor.js commit
This preserves unrelated optimizations and minimizes blast radius.