luckiest-co 1.0.13 → 1.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/package.json +1 -1
  3. package/skills/luckiest-ab-testing/SKILL.md +1 -1
  4. package/skills/luckiest-ad-creative/SKILL.md +1 -1
  5. package/skills/luckiest-ads/SKILL.md +1 -1
  6. package/skills/luckiest-advisors/SKILL.md +1 -1
  7. package/skills/luckiest-aeo-grader/SKILL.md +1 -1
  8. package/skills/luckiest-ai-seo/SKILL.md +1 -1
  9. package/skills/luckiest-analytics/SKILL.md +1 -1
  10. package/skills/luckiest-aso/SKILL.md +1 -1
  11. package/skills/luckiest-churn-prevention/SKILL.md +1 -1
  12. package/skills/luckiest-co-marketing/SKILL.md +1 -1
  13. package/skills/luckiest-coder/SKILL.md +1 -1
  14. package/skills/luckiest-coder-brainstorming/SKILL.md +1 -1
  15. package/skills/luckiest-coder-consistency/SKILL.md +1 -1
  16. package/skills/luckiest-coder-constitution/SKILL.md +1 -1
  17. package/skills/luckiest-coder-debugging/SKILL.md +1 -1
  18. package/skills/luckiest-coder-dispatching-parallel-agents/SKILL.md +1 -1
  19. package/skills/luckiest-coder-executing-plans/SKILL.md +1 -1
  20. package/skills/luckiest-coder-finishing-a-branch/SKILL.md +1 -1
  21. package/skills/luckiest-coder-git-worktrees/SKILL.md +1 -1
  22. package/skills/luckiest-coder-guard/SKILL.md +1 -1
  23. package/skills/luckiest-coder-qa/SKILL.md +1 -1
  24. package/skills/luckiest-coder-receiving-code-review/SKILL.md +1 -1
  25. package/skills/luckiest-coder-requesting-code-review/SKILL.md +1 -1
  26. package/skills/luckiest-coder-shipping/SKILL.md +1 -1
  27. package/skills/luckiest-coder-subagent-driven-development/SKILL.md +1 -1
  28. package/skills/luckiest-coder-tdd/SKILL.md +1 -1
  29. package/skills/luckiest-coder-verification/SKILL.md +1 -1
  30. package/skills/luckiest-coder-writing-plans/SKILL.md +1 -1
  31. package/skills/luckiest-coder-writing-skills/SKILL.md +1 -1
  32. package/skills/luckiest-cold-email/SKILL.md +1 -1
  33. package/skills/luckiest-community-marketing/SKILL.md +1 -1
  34. package/skills/luckiest-competitor-profiling/SKILL.md +1 -1
  35. package/skills/luckiest-competitors/SKILL.md +1 -1
  36. package/skills/luckiest-content-strategy/SKILL.md +1 -1
  37. package/skills/luckiest-copy-editing/SKILL.md +1 -1
  38. package/skills/luckiest-copywriting/SKILL.md +1 -1
  39. package/skills/luckiest-cro/SKILL.md +1 -1
  40. package/skills/luckiest-customer-research/SKILL.md +1 -1
  41. package/skills/luckiest-directory-submissions/SKILL.md +1 -1
  42. package/skills/luckiest-emails/SKILL.md +1 -1
  43. package/skills/luckiest-extract-design-system/SKILL.md +1 -1
  44. package/skills/luckiest-free-tools/SKILL.md +1 -1
  45. package/skills/luckiest-image/SKILL.md +1 -1
  46. package/skills/luckiest-launch/SKILL.md +1 -1
  47. package/skills/luckiest-lead-magnets/SKILL.md +1 -1
  48. package/skills/luckiest-marketing-ideas/SKILL.md +1 -1
  49. package/skills/luckiest-marketing-plan/SKILL.md +1 -1
  50. package/skills/luckiest-marketing-psychology/SKILL.md +1 -1
  51. package/skills/luckiest-model-router/SKILL.md +1 -1
  52. package/skills/luckiest-offers/SKILL.md +1 -1
  53. package/skills/luckiest-onboarding/SKILL.md +1 -1
  54. package/skills/luckiest-paywalls/SKILL.md +1 -1
  55. package/skills/luckiest-popups/SKILL.md +1 -1
  56. package/skills/luckiest-pricing/SKILL.md +1 -1
  57. package/skills/luckiest-product-marketing/SKILL.md +1 -1
  58. package/skills/luckiest-programmatic-seo/SKILL.md +1 -1
  59. package/skills/luckiest-prompt-rewrite/SKILL.md +1 -1
  60. package/skills/luckiest-prospecting/SKILL.md +1 -1
  61. package/skills/luckiest-public-relations/SKILL.md +1 -1
  62. package/skills/luckiest-referrals/SKILL.md +1 -1
  63. package/skills/luckiest-revops/SKILL.md +1 -1
  64. package/skills/luckiest-sales-enablement/SKILL.md +1 -1
  65. package/skills/luckiest-schema/SKILL.md +1 -1
  66. package/skills/luckiest-seo-audit/SKILL.md +1 -1
  67. package/skills/luckiest-session-handoff/SKILL.md +1 -1
  68. package/skills/luckiest-signup/SKILL.md +1 -1
  69. package/skills/luckiest-site-architecture/SKILL.md +1 -1
  70. package/skills/luckiest-sms/SKILL.md +1 -1
  71. package/skills/luckiest-social/SKILL.md +1 -1
  72. package/skills/luckiest-thinker/SKILL.md +1 -1
  73. package/skills/luckiest-trends/SKILL.md +1 -1
  74. package/skills/luckiest-video/SKILL.md +1 -1
  75. package/skills/luckiest-website-cloner/ATTRIBUTION.md +29 -0
  76. package/skills/luckiest-website-cloner/CHANGELOG.md +8 -0
  77. package/skills/luckiest-website-cloner/LICENSE +21 -0
  78. package/skills/luckiest-website-cloner/SKILL.md +289 -0
  79. package/skills/luckiest-website-cloner/references/builtin-browser-recipes.md +74 -0
  80. package/skills/luckiest-website-cloner/references/compositing.md +65 -0
  81. package/skills/luckiest-website-cloner/references/fidelity-fast-path.md +92 -0
  82. package/skills/luckiest-website-cloner/references/playwright-cli-recipes.md +68 -0
  83. package/skills/luckiest-website-cloner/references/teardown.md +142 -0
  84. package/skills/luckiest-website-cloner/references/visual-qa.md +102 -0
  85. package/skills/luckiest-website-cloner/scripts/build-bundle.cjs +12 -0
  86. package/skills/luckiest-website-cloner/scripts/motion-probe.js +423 -0
  87. package/skills/luckiest-website-cloner/scripts/surface-map.js +392 -0
  88. package/skills/luckiest-website-cloner/scripts/tokens-probe.js +178 -0
  89. package/skills/luckiest-website-cloner-dom/ATTRIBUTION.md +4 -0
  90. package/skills/luckiest-website-cloner-dom/CHANGELOG.md +8 -0
  91. package/skills/luckiest-website-cloner-dom/LICENSE +21 -0
  92. package/skills/luckiest-website-cloner-dom/SKILL.md +170 -0
  93. package/skills/luckiest-website-cloner-dom/references/asset-resolution.md +93 -0
  94. package/skills/luckiest-website-cloner-dom/references/interaction-fingerprints.md +85 -0
  95. package/skills/luckiest-website-cloner-remix/ATTRIBUTION.md +4 -0
  96. package/skills/luckiest-website-cloner-remix/CHANGELOG.md +8 -0
  97. package/skills/luckiest-website-cloner-remix/LICENSE +21 -0
  98. package/skills/luckiest-website-cloner-remix/SKILL.md +202 -0
  99. package/skills/luckiest-website-cloner-remix/references/directions.md +82 -0
  100. package/skills/luckiest-website-cloner-remix/references/reskin.md +84 -0
  101. package/skills/luckiest-website-cloner-remix/references/tweak-panel.md +72 -0
  102. package/skills/luckiest-website-cloner-remix/scripts/apply-overrides.cjs +105 -0
  103. package/skills/luckiest-website-cloner-remix/scripts/gallery.cjs +71 -0
  104. package/skills/luckiest-website-cloner-remix/scripts/tokenize-css.cjs +127 -0
  105. package/skills/luckiest-website-cloner-remix/scripts/tweak-panel.js +169 -0
  106. package/skills/luckiest-website-cloner-shaders/ATTRIBUTION.md +11 -0
  107. package/skills/luckiest-website-cloner-shaders/CHANGELOG.md +8 -0
  108. package/skills/luckiest-website-cloner-shaders/LICENSE +21 -0
  109. package/skills/luckiest-website-cloner-shaders/SKILL.md +129 -0
  110. package/skills/luckiest-website-cloner-shaders/references/capture-backends.md +89 -0
  111. package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/SKILL.md +123 -0
  112. package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/references/capture-backends.md +201 -0
  113. package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/references/evidence-policy.md +93 -0
  114. package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/references/operating-contract.md +82 -0
  115. package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/references/qa-failure-policy.md +100 -0
  116. package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/references/recon-kernel.md +206 -0
  117. package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/references/replay-policy.md +145 -0
  118. package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/references/shaders-com.md +212 -0
  119. package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/references/source-analysis.md +112 -0
  120. package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/references/surface-discovery.md +113 -0
  121. package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/references/target-lock.md +205 -0
  122. package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/references/three-shader-reconstruction.md +155 -0
  123. package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/references/tool-capability-matrix.md +57 -0
  124. package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/references/unicorn-studio.md +387 -0
  125. package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/scripts/fetch-rendered-dom.mjs +178 -0
  126. package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/scripts/scan-bundle.sh +80 -0
  127. package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/templates/extraction-report.md +41 -0
  128. package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/templates/known-gaps.md +14 -0
  129. package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/templates/qa-report.md +74 -0
  130. package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/templates/replay-manifest.json +147 -0
  131. package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/templates/run-state.json +75 -0
  132. package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/templates/scout-card.json +106 -0
@@ -0,0 +1,169 @@
1
+ /**
2
+ * tweak-panel.js — live knobs for a remixed site. Dev-only; strip from prod.
3
+ *
4
+ * Usage (in main.ts, after remix-loader):
5
+ * import { mountTweakPanel } from './remix/tweak-panel.js';
6
+ * import panel from '../remix/panel.json';
7
+ * if (import.meta.env.DEV) mountTweakPanel(panel);
8
+ *
9
+ * panel.json:
10
+ * { "title": "...", "slug": "<direction>", // slug: only mount when this direction is active (optional)
11
+ * "presets": { "name": { "<knob id>": value, ... } }, // one-click states layered on the direction
12
+ * "knobs": [
13
+ * { "id": "--rx-color-1", "label": "Accent", "group": "Color", "type": "color", "default": "#1f3bff" },
14
+ * { "id": "--p-h1-scale", "label": "Display scale", "group": "Type", "type": "number", "default": 1, "min": .7, "max": 1.6, "step": .02 },
15
+ * { "id": "--p-radius", "label": "Radius", "group": "Space", "type": "length", "default": "0px", "min": 0, "max": 24, "step": 1, "unit": "px" },
16
+ * { "id": "motion.reveal.duration", "label": "Reveal", "group": "Motion", "type": "number", "default": .7, "min": .1, "max": 2, "step": .05 },
17
+ * { "id": "shaders.hero.colorFront", "label": "Paper tint", "group": "GPU", "type": "color", "default": "#9FADBC" },
18
+ * { "id": "--font-sans", "label": "Body face", "group": "Type", "type": "select", "options": [...], "labels": [...], "default": "..." } ] }
19
+ *
20
+ * Knob ids starting with "--" are CSS custom properties (set live on :root).
21
+ * Dotted ids are paths into window.__remix (motion.* / shaders.*); the panel
22
+ * calls __remix.apply({motion:{...}}) and dispatches 'rx:change' so behaviors
23
+ * and shader mounts re-read. State lives in location.hash as #rx=<b64 json>
24
+ * → any URL is a permalink. ` toggles, / focuses search. Copy JSON exports an
25
+ * overrides file you can feed back to apply-overrides.cjs as a new direction.
26
+ */
27
+ export function mountTweakPanel(config) {
28
+ const rx = window.__remix || (window.__remix = { apply() {} });
29
+ if (config.slug && rx.slug && rx.slug !== config.slug) return null;
30
+ const knobs = config.knobs || [];
31
+ const presets = config.presets || {};
32
+ const state = {};
33
+
34
+ /* ---- state ---- */
35
+ const b64 = (s) => btoa(unescape(encodeURIComponent(s))).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
36
+ const unb64 = (s) => decodeURIComponent(escape(atob(s.replace(/-/g, '+').replace(/_/g, '/'))));
37
+ const read = () => { try { const m = location.hash.match(/rx=([A-Za-z0-9_-]+)/); return m ? JSON.parse(unb64(m[1])) : {}; } catch { return {}; } };
38
+ const write = () => { history.replaceState(null, '', location.pathname + location.search + (Object.keys(state).length ? '#rx=' + b64(JSON.stringify(state)) : '')); };
39
+ const setPath = (obj, dotted, v) => { const p = dotted.split('.'); let o = obj; for (let i = 0; i < p.length - 1; i++) o = o[p[i]] = o[p[i]] || {}; o[p[p.length - 1]] = v; return obj; };
40
+ const applyOne = (k, v) => {
41
+ if (k.id.startsWith('--')) document.documentElement.style.setProperty(k.id, typeof v === 'number' && k.unit ? v + k.unit : String(v));
42
+ else rx.apply(setPath({}, k.id, v));
43
+ };
44
+ const set = (k, v, persist = true) => { if (v === k.default) delete state[k.id]; else state[k.id] = v; applyOne(k, v); if (persist) write(); };
45
+
46
+ /* ---- UI ---- */
47
+ const css = `
48
+ #rx-panel{--w:320px;position:fixed;top:12px;right:12px;z-index:2147483000;width:var(--w);max-height:calc(100vh - 24px);display:flex;flex-direction:column;font:12px/1.4 ui-monospace,SFMono-Regular,Menlo,monospace;color:#e8e8e8;background:rgba(14,14,16,.95);backdrop-filter:blur(12px);border:1px solid rgba(255,255,255,.12);border-radius:10px;box-shadow:0 24px 60px -20px rgba(0,0,0,.6)}
49
+ #rx-panel[hidden]{display:none}
50
+ #rx-panel header{display:flex;align-items:center;gap:8px;padding:10px 12px;border-bottom:1px solid rgba(255,255,255,.1)}
51
+ #rx-panel header b{font-weight:600;letter-spacing:.02em} #rx-panel header span{opacity:.5;font-size:10px;margin-left:auto;white-space:nowrap}
52
+ #rx-panel .tools{display:flex;gap:6px;padding:8px 12px;border-bottom:1px solid rgba(255,255,255,.08);flex-wrap:wrap}
53
+ #rx-panel .tools input[type=search]{flex:1;min-width:90px;background:rgba(255,255,255,.06);color:inherit;border:1px solid rgba(255,255,255,.12);border-radius:5px;padding:4px 7px;font:inherit}
54
+ #rx-panel .tools select{background:rgba(255,255,255,.06);color:inherit;border:1px solid rgba(255,255,255,.12);border-radius:5px;padding:4px 6px;font:inherit;max-width:120px}
55
+ #rx-panel .body{overflow:auto;flex:1}
56
+ #rx-panel details{border-bottom:1px solid rgba(255,255,255,.06)}
57
+ #rx-panel summary{cursor:pointer;padding:8px 12px;opacity:.7;text-transform:uppercase;letter-spacing:.08em;font-size:10px;user-select:none;display:flex;justify-content:space-between}
58
+ #rx-panel summary i{font-style:normal;opacity:.6}
59
+ #rx-panel label{display:grid;grid-template-columns:1fr 112px;align-items:center;gap:8px;padding:5px 12px} #rx-panel label.hide{display:none}
60
+ #rx-panel label small{opacity:.5;display:block;font-size:9.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
61
+ #rx-panel label.dirty > div:first-child{color:#9fe1ff}
62
+ #rx-panel input[type=range]{width:100%;accent-color:#9fe1ff}
63
+ #rx-panel input[type=color]{width:100%;height:24px;border:0;background:none;padding:0;cursor:pointer}
64
+ #rx-panel input[type=text],#rx-panel input[type=number],#rx-panel label select{width:100%;background:rgba(255,255,255,.06);color:inherit;border:1px solid rgba(255,255,255,.12);border-radius:4px;padding:3px 6px;font:inherit}
65
+ #rx-panel .val{opacity:.6;font-size:10px;text-align:right;font-variant-numeric:tabular-nums}
66
+ #rx-panel .range-row{display:grid;grid-template-columns:1fr 48px;gap:6px;align-items:center}
67
+ #rx-panel footer{display:flex;gap:6px;padding:10px 12px;border-top:1px solid rgba(255,255,255,.1);flex-wrap:wrap}
68
+ #rx-panel footer button,#rx-panel .tools button{flex:1;background:rgba(255,255,255,.08);color:inherit;border:1px solid rgba(255,255,255,.12);border-radius:6px;padding:6px 8px;font:inherit;cursor:pointer;white-space:nowrap}
69
+ #rx-panel footer button:hover,#rx-panel .tools button:hover{background:rgba(255,255,255,.14)}
70
+ #rx-panel .grip{position:absolute;left:-6px;top:0;bottom:0;width:12px;cursor:ew-resize}`;
71
+ const style = document.createElement('style'); style.textContent = css; document.head.appendChild(style);
72
+ // Knob ids, labels, group names and preset keys come from the overrides JSON,
73
+ // which is derived from the CLONED site's own token names. None of it is
74
+ // trusted, so every one of them is set as text, never as markup.
75
+ const tag = (name, text, cls) => { const n = document.createElement(name); if (text != null) n.textContent = String(text); if (cls) n.className = cls; return n; };
76
+ const el = document.createElement('aside'); el.id = 'rx-panel';
77
+ el.appendChild(tag('div', null, 'grip'));
78
+ const head = document.createElement('header');
79
+ head.append(tag('b', config.title || 'Tweaks'), tag('span', `${rx.slug || 'base'} · ${knobs.length} knobs · \` toggle`));
80
+ el.appendChild(head);
81
+
82
+ // tools: search, presets, collapse, randomize
83
+ const tools = document.createElement('div'); tools.className = 'tools';
84
+ const search = document.createElement('input'); search.type = 'search'; search.placeholder = 'filter knobs ( / )';
85
+ const presetSel = document.createElement('select');
86
+ presetSel.appendChild(new Option('presets…', ''));
87
+ for (const name of Object.keys(presets)) presetSel.appendChild(new Option(name, name));
88
+ const collapse = document.createElement('button'); collapse.textContent = 'collapse';
89
+ const rnd = document.createElement('button'); rnd.textContent = 'shuffle'; rnd.title = 'randomize every knob within its range (colors stay)';
90
+ tools.append(search, presetSel, collapse, rnd); el.appendChild(tools);
91
+
92
+ const body = document.createElement('div'); body.className = 'body'; el.appendChild(body);
93
+ const groups = [...new Set(knobs.map((k) => k.group || 'Knobs'))];
94
+ const inputs = new Map();
95
+ const num = (v) => (typeof v === 'number' ? v : parseFloat(v));
96
+ const unitOf = (k) => k.unit ?? (k.type === 'length' ? String(k.default).replace(/[\d.\-]/g, '') || 'px' : '');
97
+ const show = (e, v) => { const { k, input, val, lab } = e; if (input.type === 'color') input.value = toHex(v); else if (input.type === 'range') input.value = num(v); else input.value = String(v); if (val) val.textContent = v; lab.classList.toggle('dirty', v !== k.default); };
98
+ for (const g of groups) {
99
+ const d = document.createElement('details'); d.open = true;
100
+ const items = knobs.filter((x) => (x.group || 'Knobs') === g);
101
+ const sum = document.createElement('summary');
102
+ sum.append(document.createTextNode(String(g)), tag('i', items.length));
103
+ d.appendChild(sum);
104
+ for (const k of items) {
105
+ const lab = document.createElement('label'); lab.dataset.q = (k.label + ' ' + k.id + ' ' + g).toLowerCase();
106
+ const name = tag('small', k.id); name.title = String(k.id);
107
+ const head = document.createElement('div');
108
+ head.append(document.createTextNode(String(k.label || k.id)), name);
109
+ lab.appendChild(head);
110
+ const cell = document.createElement('div'); let input, val;
111
+ if (k.type === 'color') { input = document.createElement('input'); input.type = 'color'; input.oninput = () => set(k, input.value); }
112
+ else if (k.type === 'length' || k.type === 'number') {
113
+ cell.className = 'range-row';
114
+ input = document.createElement('input'); input.type = 'range'; input.min = k.min ?? 0; input.max = k.max ?? 100; input.step = k.step ?? 1;
115
+ val = document.createElement('div'); val.className = 'val';
116
+ const unit = unitOf(k);
117
+ input.oninput = () => { const v = k.type === 'length' ? `${input.value}${unit}` : +input.value; val.textContent = v; set(k, v); lab.classList.toggle('dirty', v !== k.default); };
118
+ val.ondblclick = () => { const n = prompt(k.label, String(state[k.id] ?? k.default)); if (n != null) { const v = k.type === 'length' ? (/[a-z%]$/i.test(n) ? n : n + unit) : +n; set(k, v); show(inputs.get(k.id), v); } };
119
+ cell.append(input, val);
120
+ }
121
+ else if (k.type === 'select') { input = document.createElement('select'); (k.options || []).forEach((o, i) => { const op = document.createElement('option'); op.value = o; op.textContent = (k.labels || [])[i] || o; input.appendChild(op); }); input.onchange = () => set(k, input.value); }
122
+ else { input = document.createElement('input'); input.type = 'text'; input.onchange = () => set(k, input.value); }
123
+ if (!cell.className) cell.appendChild(input);
124
+ lab.appendChild(cell); d.appendChild(lab);
125
+ const e = { k, input, val, lab }; inputs.set(k.id, e); show(e, k.default);
126
+ lab.oncontextmenu = (ev) => { ev.preventDefault(); set(k, k.default); show(e, k.default); };
127
+ }
128
+ body.appendChild(d);
129
+ }
130
+
131
+ const foot = document.createElement('footer');
132
+ const btn = (t, fn, title) => { const b = document.createElement('button'); b.textContent = t; b.title = title || ''; b.onclick = fn; foot.appendChild(b); return b; };
133
+ const exportJson = () => { const o = { name: (config.slug || config.title || 'tweak') + '-' + Date.now().toString(36), thesis: 'exported from tweak panel', tokens: {}, motion: {}, shaders: {} };
134
+ for (const [id, v] of Object.entries(state)) { if (id.startsWith('--')) o.tokens[id] = v; else setPath(o, id, v); } return JSON.stringify(o, null, 2); };
135
+ btn('Copy JSON', () => { navigator.clipboard?.writeText(exportJson()); flash('copied JSON'); }, 'overrides file for apply-overrides.cjs');
136
+ btn('Copy link', () => { navigator.clipboard?.writeText(location.href); flash('link copied'); }, 'permalink with this state');
137
+ btn('Reset', () => { for (const id of Object.keys(state)) delete state[id]; for (const e of inputs.values()) { applyOne(e.k, e.k.default); show(e, e.k.default); } write(); flash('reset'); });
138
+ el.appendChild(foot); document.body.appendChild(el);
139
+ const flash = (t) => { const h = el.querySelector('header span'); const old = h.textContent; h.textContent = t; setTimeout(() => (h.textContent = old), 900); };
140
+
141
+ // tools behavior
142
+ search.oninput = () => { const q = search.value.trim().toLowerCase(); el.querySelectorAll('label').forEach((l) => l.classList.toggle('hide', !!q && !l.dataset.q.includes(q))); };
143
+ collapse.onclick = () => { const open = [...el.querySelectorAll('details')].some((d) => d.open); el.querySelectorAll('details').forEach((d) => (d.open = !open)); collapse.textContent = open ? 'expand' : 'collapse'; };
144
+ presetSel.onchange = () => { const p = presets[presetSel.value]; if (!p) return; for (const e of inputs.values()) { const v = p[e.k.id] ?? e.k.default; set(e.k, v, false); show(e, v); } write(); flash('preset: ' + presetSel.value); presetSel.value = ''; };
145
+ rnd.onclick = () => { for (const e of inputs.values()) { const k = e.k; let v; if (k.type === 'number' || k.type === 'length') { const lo = k.min ?? 0, hi = k.max ?? 100, st = k.step ?? 1; const r = lo + Math.round(Math.random() * ((hi - lo) / st)) * st; v = k.type === 'length' ? `${+r.toFixed(3)}${unitOf(k)}` : +r.toFixed(3); } else if (k.type === 'select') v = k.options[Math.floor(Math.random() * k.options.length)]; else continue; set(e.k, v, false); show(e, v); } write(); flash('shuffled'); };
146
+ // resize grip
147
+ const grip = el.querySelector('.grip'); let drag = null;
148
+ grip.onmousedown = (e) => { drag = { x: e.clientX, w: el.offsetWidth }; e.preventDefault(); };
149
+ window.addEventListener('mousemove', (e) => { if (drag) el.style.setProperty('--w', Math.max(260, Math.min(640, drag.w + (drag.x - e.clientX))) + 'px'); });
150
+ window.addEventListener('mouseup', () => (drag = null));
151
+
152
+ /* ---- restore from URL ---- */
153
+ Object.assign(state, read());
154
+ for (const [id, v] of Object.entries(state)) { const e = inputs.get(id); if (!e) continue; applyOne(e.k, v); show(e, v); }
155
+
156
+ window.addEventListener('keydown', (e) => {
157
+ const typing = /input|textarea|select/i.test(document.activeElement?.tagName || '');
158
+ if (e.key === '`' && !typing) el.hidden = !el.hidden;
159
+ if (e.key === '/' && !typing) { e.preventDefault(); el.hidden = false; search.focus(); }
160
+ });
161
+ return { state, el, set: (id, v) => { const e = inputs.get(id); if (e) { set(e.k, v); show(e, v); } } };
162
+ }
163
+
164
+ function toHex(c) {
165
+ if (/^#[0-9a-f]{6}$/i.test(c)) return c;
166
+ if (/^#[0-9a-f]{3}$/i.test(c)) return '#' + [...c.slice(1)].map((x) => x + x).join('');
167
+ const m = String(c).match(/(\d+)[,\s]+(\d+)[,\s]+(\d+)/); if (!m) return '#000000';
168
+ return '#' + [m[1], m[2], m[3]].map((v) => (+v).toString(16).padStart(2, '0')).join('');
169
+ }
@@ -0,0 +1,11 @@
1
+ # Attribution
2
+
3
+ See `../luckiest-website-cloner/ATTRIBUTION.md`. Luckiest edition of the
4
+ open-source site-clone skill collection, MIT licensed.
5
+
6
+ `vendor/web-shader-extractor/` is vendored unmodified from the
7
+ **web-shader-extractor** skill in the
8
+ [lixiaolin94/skills](https://github.com/lixiaolin94/skills) repository by
9
+ **lixiaolin94**, with a 2D-Canvas extraction contribution by
10
+ [Huazi](https://github.com/HeyHuazi). Licensed **MIT**. Update it by re-pulling
11
+ upstream rather than hand-editing it.
@@ -0,0 +1,8 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0
4
+
5
+ First Luckiest edition of `luckiest-website-cloner-shaders`. Renamed from the upstream site-clone
6
+ collection, guardrails added to every entry point, recipes added for running the
7
+ probes from an in-app browser pane, frontmatter normalized to the Luckiest
8
+ package format. See ATTRIBUTION.md.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Chase Hannegan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,129 @@
1
+ ---
2
+ name: luckiest-website-cloner-shaders
3
+ description: >-
4
+ Extract, reproduce, and locally replay a single WebGL / WebGPU / Canvas /
5
+ shader / animated-3D visual effect from a web page — the GPU-rendered surface
6
+ that DOM/CSS cloning is blind to. Use whenever a page has a WebGL/WebGPU/canvas
7
+ shader background, animated 3D hero, generative gradient, particle field, or
8
+ Unicorn Studio / Spline / Three.js effect that must be captured and rebuilt as
9
+ a runnable local module. This is the GPU track of a site clone (driven by
10
+ luckiest-website-cloner) but also stands alone. Trigger on "extract this shader", "clone the
11
+ WebGL background", "port this canvas effect", "rebuild this animated hero",
12
+ "reproduce this Three.js scene locally". NOT for ordinary DOM/CSS cloning
13
+ (use luckiest-website-cloner-dom).
14
+ argument-hint: "<url> | <locked surface: selector + rect + driver + output-dir>"
15
+ user-invocable: false
16
+ license: MIT. See ATTRIBUTION.md
17
+ allowed-tools: Bash, Read, Write, Edit, Glob, Grep
18
+ metadata:
19
+ version: "1.0.0"
20
+ listing_id: luckiest-website-cloner-shaders
21
+ author: luckiest
22
+ ---
23
+
24
+ # Shader Extract
25
+
26
+ Capture one GPU-rendered surface and rebuild it as a verified, runnable local
27
+ effect module. The governing principle — inherited from the vendored engine this
28
+ skill wraps — is **evidence before implementation**: capture what the page's GPU
29
+ pipeline actually does (shaders, uniforms, pass order, textures, timing) and
30
+ match it, rather than eyeballing the visual and hand-tuning a lookalike. A
31
+ lookalike drifts; a capture-matched baseline is faithful and honest about its
32
+ gaps.
33
+
34
+ ## This skill = intake adapter + a vendored evidence-gated engine
35
+
36
+ The heavy machinery lives in **`vendor/web-shader-extractor/`** — an
37
+ evidence-gated state machine (surface lock → source/runtime trace → capture →
38
+ verified baseline → projectize) by lixiaolin94 (MIT; see `ATTRIBUTION.md`). Do
39
+ not reimplement it. This wrapper does two things the vendored engine assumes were
40
+ done elsewhere:
41
+
42
+ 1. **Intake** — accept a *pre-locked* surface from the luckiest-website-cloner coordinator so
43
+ you skip straight to capture instead of re-scouting the whole page.
44
+ 2. **Capture backends** — make the concrete, research-verified capture tools
45
+ explicit (`references/capture-backends.md`): **Spector.js** for WebGL1/2 and
46
+ **WebGPU Inspector** for WebGPU. These are what actually recover a frame; the
47
+ vendored policy files describe the *discipline*, these describe the *tools*.
48
+
49
+ ## Router: how you were invoked
50
+
51
+ **Driven by luckiest-website-cloner (common):** you receive a locked surface — selector,
52
+ bounding box, guessed driver (three.js / unicorn-studio / spline / regl / raw
53
+ WebGL), and an output dir like `output/<host>/effects/<surface-id>/`. The surface
54
+ is already attributed, so skip scouting. Go straight to:
55
+
56
+ 1. Read `vendor/web-shader-extractor/SKILL.md` and its `references/replay-policy.md`
57
+ — that is the operating manual for capture → baseline → projectize.
58
+ 2. Pick the capture backend by surface type (`references/capture-backends.md`):
59
+ WEBGL1/2 → Spector.js; WEBGPU → WebGPU Inspector.
60
+ 3. Run the vendored state flow from `CAPTURE_MINIMUM_TRUTH` onward, writing
61
+ evidence and the baseline into the given output dir.
62
+ 4. Return a **mount-contract module** (see below) plus the honesty label.
63
+
64
+ **Standalone (user hands you a URL):** you must lock the surface first. Run the
65
+ full vendored flow from `INTAKE` (read `vendor/web-shader-extractor/SKILL.md`).
66
+ The `luckiest-website-cloner` script `scripts/surface-map.js` is a fast way to enumerate and
67
+ classify canvases if you want a head start, but the vendored `TARGET_LOCK` gate
68
+ is authoritative.
69
+
70
+ ## Non-negotiables (carried from the vendored engine)
71
+
72
+ - **Honest labels.** Every implementation-critical fact is `SOURCE`, `PARTIAL`,
73
+ or `GUESS`; unlabeled = `GUESS`. The final module carries a fidelity verdict.
74
+ Never quietly upgrade a `BEHAVIOR_REBUILD` (lookalike) to sound like a source
75
+ replay.
76
+ - **No compensation tuning.** Don't nudge brightness, speed, offsets, noise
77
+ scale, or color to mask missing pipeline evidence. A visible gap gets recorded
78
+ in `known-gaps.md`, not fudged away.
79
+ - **Baseline before projectize.** Get a faithful, verified capture-baseline
80
+ running first; only then refactor it into an editable module. Don't overwrite a
81
+ verified baseline for cleanup.
82
+ - **Cross-origin honesty.** If the canvas is cross-origin/tainted and pixel or
83
+ shader readback is blocked, say so and fall back to a captured poster frame —
84
+ don't invent a shader you couldn't read.
85
+
86
+ ## Output contract (so luckiest-website-cloner can mount it)
87
+
88
+ Beyond the vendored `output/` layout (capture-baseline, editable-project,
89
+ qa-report, known-gaps), expose the effect through the mount lifecycle the
90
+ coordinator composites against:
91
+
92
+ ```js
93
+ export function mount(canvasEl, opts) { /* start renderer + rAF loop */ return handle }
94
+ export function unmount(handle) { /* cancel rAF, loseContext, free GPU */ }
95
+ export function resize(handle, w, h, dpr) { /* resize drawing buffer + viewport */ }
96
+ ```
97
+
98
+ Also emit a **poster frame** (a captured still) as a fallback for reduced-motion
99
+ and for the case where reconstruction only reached poster fidelity. Report the
100
+ fidelity label so the coordinator carries it into the final clone report
101
+ unchanged.
102
+
103
+ ## Where to read next
104
+
105
+ - `references/capture-backends.md` — Spector.js (WebGL) and WebGPU Inspector
106
+ (WebGPU): what each captures, how to drive it, what's reliable vs guesswork.
107
+ - `vendor/web-shader-extractor/SKILL.md` — the full state machine + reference
108
+ router (surface discovery, target lock, evidence policy, replay policy, QA,
109
+ Three.js/TSL reconstruction, Unicorn Studio / shaders.com adapters).
110
+ - `ATTRIBUTION.md` — upstream authorship and MIT license.
111
+
112
+ ## Guardrails
113
+
114
+ Clone for migration, for recovering your own lost source, or for learning how a
115
+ build works. Do not use it to pass off someone else's brand or design as your
116
+ own, for phishing or impersonation, or against a site whose terms forbid
117
+ reproduction. Logos, brand assets, and copy belong to their owners.
118
+
119
+ Stop and ask the user before continuing if any of these are true:
120
+
121
+ - The target looks like it exists to be impersonated: a bank or wallet login, a
122
+ checkout, an account or password page.
123
+ - The page is behind a login, a paywall, or a bot wall. Never supply
124
+ credentials, cookies, session tokens, or a stored browser profile to get past
125
+ one, and never work around the block.
126
+ - The page holds personal data about real people.
127
+
128
+ Capture only what renders publicly. Do not read or copy credentials, cookies,
129
+ local storage, or session storage from the target.
@@ -0,0 +1,89 @@
1
+ # Capture backends
2
+
3
+ The vendored engine tells you the *discipline* (lock the surface, capture the
4
+ truth, verify before projectizing). This file names the *tools* that actually
5
+ recover a GPU frame, and what each gives you vs. what remains guesswork. Pick by
6
+ surface type from the surface map.
7
+
8
+ ## WebGL1 / WebGL2 → Spector.js
9
+
10
+ Spector.js (BabylonJS, first-party, actively maintained; works with any
11
+ WebGL1/WebGL2 engine — Three.js, Babylon, regl, raw GL) captures a **complete
12
+ frame as a full ordered command list**, each command annotated with its visual
13
+ state and GL context info. That gives you, per frame:
14
+
15
+ - the executed GL commands in **draw/pass order** (reconstruct the render graph),
16
+ - **shader programs** (GLSL source), attributes, VAOs,
17
+ - **uniforms** and uniform buffers bound at each draw,
18
+ - textures, framebuffers, and render state.
19
+
20
+ How to drive it:
21
+
22
+ - Inject the Spector.js script (CDN or bundled) into the page via the browser
23
+ tool. Programmatic capture: `new SPECTOR.Spector()` then `captureCanvas(canvas)`
24
+ or `captureNextFrame(canvas)`; the result is the command tree you serialize to
25
+ evidence. `startCapture` / `stopCapture` bracket a specific interaction.
26
+ - Capture a representative frame — for a time-driven effect, one steady-state
27
+ frame; for an interactive one, capture at a known pointer/scroll state and
28
+ record that state alongside.
29
+
30
+ **Reliable:** shader source, per-draw uniforms, command/pass order, textures,
31
+ state. This is real evidence, label `SOURCE`.
32
+ **Still guesswork:** how uniforms are *driven over time* (the JS that animates
33
+ them frame to frame) — Spector shows one frame's values, not the update function.
34
+ Recover the drive loop from source/source-maps when possible; otherwise the
35
+ timing/coupling is `PARTIAL` or `GUESS`. Spector captures and inspects; it does
36
+ **not** auto-replay — you reconstruct the runnable module from its evidence.
37
+
38
+ ## WebGPU → WebGPU Inspector
39
+
40
+ WebGPU Inspector (brendan-duncan; browser extension, RenderDoc-style, engine-
41
+ independent within WebGPU) captures a frame's **full command stream** — render-
42
+ pass output images, textures, buffer data, render state, and the uniform/storage
43
+ buffers bound to each draw/dispatch. It also gives a **live view of every GPU
44
+ object** with live shader (WGSL) editing and texture inspection, and — the part
45
+ that matters most for porting — it can **serialize a capture into a self-contained
46
+ HTML or binary file that replays offline** without a local server.
47
+
48
+ How to drive it:
49
+
50
+ - Install the extension (Chrome Web Store / Firefox Add-ons). Open its panel on
51
+ the target, Capture a frame, inspect passes/buffers/shaders, then Record →
52
+ export the self-contained replay file into your output dir as the baseline
53
+ evidence.
54
+ - Use the WGSL shaders + bound buffer layouts as the source of truth for the
55
+ reconstructed module.
56
+
57
+ **Reliable:** WGSL shaders, pass structure, bound buffers, and a replayable
58
+ capture file. Label `SOURCE`.
59
+ **Still guesswork:** same as WebGL — the per-frame update logic driving the
60
+ buffers is not in a single capture; recover it from source or mark `PARTIAL`.
61
+
62
+ ## Canvas2D → source + operation trace
63
+
64
+ No GPU pipeline. Recover the 2D drawing from the JS source (the vendored engine's
65
+ source-analysis path). If the source is minified/unavailable, trace the sequence
66
+ of Canvas2D operations and rebuild from observed behavior — explicitly a
67
+ `BEHAVIOR_REBUILD` (approximate), never claimed as source.
68
+
69
+ ## Platform drivers (short-circuits)
70
+
71
+ If the surface map's `driver` says a known platform, prefer its structured
72
+ definition over raw frame capture — it's higher fidelity and less work:
73
+
74
+ - **Unicorn Studio** — has a project export/definition; use the vendored
75
+ `references/unicorn-studio.md` adapter.
76
+ - **Spline** — scene has an exportable URL/definition; embed or re-export rather
77
+ than pixel-capture.
78
+ - **shaders.com / TSL** — structured shader definitions; vendored
79
+ `references/shaders-com.md` + `references/three-shader-reconstruction.md`.
80
+
81
+ Fall back to Spector.js / WebGPU Inspector only when no structured definition is
82
+ reachable.
83
+
84
+ ## Hard blocker: cross-origin / tainted canvas
85
+
86
+ If the canvas is cross-origin without CORS, pixel readback and some capture paths
87
+ are blocked by the browser. Don't fabricate a shader you couldn't read — capture
88
+ a **poster frame** (screenshot) as the fallback deliverable and record the
89
+ limitation in `known-gaps.md`. Honest poster > invented lookalike.
@@ -0,0 +1,123 @@
1
+ ---
2
+ name: web-shader-extractor
3
+ description: >
4
+ Use when a user gives or references a webpage URL and wants to extract,
5
+ reproduce, port, or locally replay a WebGL, WebGPU, Canvas, shader-like,
6
+ animated background, interactive 3D, or web visual effect. Locks the target
7
+ rendering surface group, records shader/resource/render graph/timing/input
8
+ evidence, builds an evidence-matched local baseline, then projectizes it.
9
+ Do not use for ordinary DOM/CSS page cloning.
10
+ ---
11
+
12
+ # Web Shader Extractor
13
+
14
+ Index for WebGL / WebGPU / Canvas rendering investigation and local replay.
15
+ Start from the target visual. Lock the surface group. Trace source or runtime facts. Build a runnable baseline. Then projectize.
16
+
17
+ ## Router Contract
18
+
19
+ This file is the index. Do not treat it as the full operating manual. Before task action, read:
20
+
21
+ - `references/operating-contract.md`
22
+ - `references/recon-kernel.md`
23
+
24
+ Then load only the focused references needed by the current state.
25
+ Keep large evidence, captures, and generated outputs out of the conversation.
26
+ Store them in the user's output directory.
27
+
28
+ ## Use This For
29
+
30
+ - Extracting a webpage WebGL, WebGPU, Canvas2D, OffscreenCanvas, shader, or animated canvas effect.
31
+ - Replaying an animated background, product shader, interactive WebGL scene, or Canvas visual locally.
32
+ - Building an evidence-matched baseline first, then an editable project.
33
+ - Investigating target-bound shader/render graph/timing/resource/input facts.
34
+
35
+ Do not use this for ordinary DOM/CSS cloning, static screenshots, generic website copying, unrelated JavaScript deobfuscation, or product UI redesign.
36
+ Use it only when the task has a shader/canvas target.
37
+
38
+ ## Core Rules
39
+
40
+ - Target-bound before framework-bound: a global Three.js, platform, or shader signature is only a hypothesis until tied to the target surface group.
41
+ - Evidence before implementation: source, runtime objects, frame captures, source maps, and public structured definitions outrank visual fitting.
42
+ - Baseline before projectization: never overwrite a verified baseline for cleanup, simplification, or native conversion.
43
+ - Honest labels: implementation-critical facts are `SOURCE`, `PARTIAL`, or `GUESS`; unlabeled values are treated as `GUESS`.
44
+ - No compensation tuning: do not adjust brightness, time, color, offsets, or noise to mask missing pipeline evidence.
45
+ - Gate artifacts are transition guards: if the required artifact is missing, incomplete, or has placeholders in gate-critical fields, the state has not advanced.
46
+ - Ask only for product scope changes or external access/permission blockers.
47
+ - Use plain records: state the fact, evidence path, current unknown, and next action. Avoid metaphor, broad claims, and unsupported conclusions.
48
+
49
+ ## State Router
50
+
51
+ Use the Recon Kernel state flow:
52
+
53
+ ```text
54
+ INTAKE -> CAPABILITY_SNAPSHOT -> QUICK_SCOUT -> SURFACE_ATTRIBUTION
55
+ -> TARGET_LOCK_GATE
56
+ - provisional/failed -> REFINE_SCOUT
57
+ - attributed -> targeted owner/backend/source probe -> TARGET_LOCK_GATE
58
+ - locked -> SCOPE_CHECK
59
+ -> TRACE_ROUTE_SELECT -> SOURCE_TRACE -> CAPTURE_MINIMUM_TRUTH
60
+ -> REPLAY_READY_GATE
61
+ - not ready -> SOURCE_TRACE / CAPTURE_MINIMUM_TRUTH
62
+ - ready -> RAW_REPLAY
63
+ -> BASELINE_RUN -> BASELINE_VERIFY
64
+ -> BASELINE_VERIFIED -> PROJECTIZE -> PROJECT_VERIFY -> PACKAGE
65
+ ```
66
+
67
+ `TARGET_LOCKED` must precede deep source/bundle work.
68
+ Before lock, only narrow source probes tied to `nextProbe` are allowed.
69
+ `REPLAY_READY` must precede implementation.
70
+ `BASELINE_VERIFIED` must precede projectization.
71
+
72
+ ## Reference Router
73
+
74
+ Load only what the current state needs:
75
+
76
+ | Need | Read |
77
+ |---|---|
78
+ | Global contract, fact labels, completion states | `references/operating-contract.md` |
79
+ | Kernel, initial protocol, state flow, autonomy, budgets | `references/recon-kernel.md` |
80
+ | Surface discovery and visual attribution | `references/surface-discovery.md` |
81
+ | Lock criteria, target-bound evidence, scope, Three.js binding | `references/target-lock.md` |
82
+ | Evidence labels, ledgers, unknown classes, sensitive data | `references/evidence-policy.md` |
83
+ | Tool capability selection | `references/tool-capability-matrix.md` |
84
+ | WebGL, WebGPU, and Canvas2D capture facts | `references/capture-backends.md` |
85
+ | Source maps, bundle slices, config, encoded definitions | `references/source-analysis.md` |
86
+ | Replay readiness, routes, baseline, stack choice, projectization | `references/replay-policy.md` |
87
+ | QA, failure routing, severity, mismatch signatures | `references/qa-failure-policy.md` |
88
+ | Three.js shader injection or TSL reconstruction | `references/three-shader-reconstruction.md` |
89
+ | Unicorn Studio target | `references/unicorn-studio.md` |
90
+ | shaders.com / TSL target | `references/shaders-com.md` |
91
+
92
+ ## Tool And Artifact Policy
93
+
94
+ Tools are replaceable capabilities, not prerequisites. First record the available capability profile:
95
+
96
+ ```text
97
+ navigate, runtime-eval, preload-script, network-metadata, network-body,
98
+ source-map, canvas-screenshot, interaction, frame-capture-webgl,
99
+ frame-capture-webgpu, local-run, multi-frame-compare
100
+ ```
101
+
102
+ Use `scripts/fetch-rendered-dom.mjs` only as an optional inventory helper when Playwright is already available.
103
+ Use `scripts/scan-bundle.sh` only on target-bound bundle slices or a precise `nextProbe`.
104
+ Script output is hypothesis evidence. It never satisfies Surface Attribution, Target Lock, Replay Ready, or QA gates by itself.
105
+
106
+ Use bundled templates as schemas, not free-form notes:
107
+
108
+ - `templates/scout-card.json`
109
+ - `templates/replay-manifest.json`
110
+ - `templates/run-state.json`
111
+ - `templates/qa-report.md`
112
+ - `templates/known-gaps.md`
113
+ - `templates/extraction-report.md`
114
+
115
+ ## Platform Adapters
116
+
117
+ Load platform references only after target-bound evidence points there:
118
+
119
+ - Unicorn Studio: `references/unicorn-studio.md`
120
+ - shaders.com / TSL: `references/shaders-com.md`
121
+ - Three.js shader injection or TSL: `references/three-shader-reconstruction.md`
122
+
123
+ If no adapter fits, follow generic WebGL, WebGPU, or Canvas2D capture in `references/capture-backends.md`.