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.
- package/.claude-plugin/plugin.json +1 -1
- package/package.json +1 -1
- package/skills/luckiest-ab-testing/SKILL.md +1 -1
- package/skills/luckiest-ad-creative/SKILL.md +1 -1
- package/skills/luckiest-ads/SKILL.md +1 -1
- package/skills/luckiest-advisors/SKILL.md +1 -1
- package/skills/luckiest-aeo-grader/SKILL.md +1 -1
- package/skills/luckiest-ai-seo/SKILL.md +1 -1
- package/skills/luckiest-analytics/SKILL.md +1 -1
- package/skills/luckiest-aso/SKILL.md +1 -1
- package/skills/luckiest-churn-prevention/SKILL.md +1 -1
- package/skills/luckiest-co-marketing/SKILL.md +1 -1
- package/skills/luckiest-coder/SKILL.md +1 -1
- package/skills/luckiest-coder-brainstorming/SKILL.md +1 -1
- package/skills/luckiest-coder-consistency/SKILL.md +1 -1
- package/skills/luckiest-coder-constitution/SKILL.md +1 -1
- package/skills/luckiest-coder-debugging/SKILL.md +1 -1
- package/skills/luckiest-coder-dispatching-parallel-agents/SKILL.md +1 -1
- package/skills/luckiest-coder-executing-plans/SKILL.md +1 -1
- package/skills/luckiest-coder-finishing-a-branch/SKILL.md +1 -1
- package/skills/luckiest-coder-git-worktrees/SKILL.md +1 -1
- package/skills/luckiest-coder-guard/SKILL.md +1 -1
- package/skills/luckiest-coder-qa/SKILL.md +1 -1
- package/skills/luckiest-coder-receiving-code-review/SKILL.md +1 -1
- package/skills/luckiest-coder-requesting-code-review/SKILL.md +1 -1
- package/skills/luckiest-coder-shipping/SKILL.md +1 -1
- package/skills/luckiest-coder-subagent-driven-development/SKILL.md +1 -1
- package/skills/luckiest-coder-tdd/SKILL.md +1 -1
- package/skills/luckiest-coder-verification/SKILL.md +1 -1
- package/skills/luckiest-coder-writing-plans/SKILL.md +1 -1
- package/skills/luckiest-coder-writing-skills/SKILL.md +1 -1
- package/skills/luckiest-cold-email/SKILL.md +1 -1
- package/skills/luckiest-community-marketing/SKILL.md +1 -1
- package/skills/luckiest-competitor-profiling/SKILL.md +1 -1
- package/skills/luckiest-competitors/SKILL.md +1 -1
- package/skills/luckiest-content-strategy/SKILL.md +1 -1
- package/skills/luckiest-copy-editing/SKILL.md +1 -1
- package/skills/luckiest-copywriting/SKILL.md +1 -1
- package/skills/luckiest-cro/SKILL.md +1 -1
- package/skills/luckiest-customer-research/SKILL.md +1 -1
- package/skills/luckiest-directory-submissions/SKILL.md +1 -1
- package/skills/luckiest-emails/SKILL.md +1 -1
- package/skills/luckiest-extract-design-system/SKILL.md +1 -1
- package/skills/luckiest-free-tools/SKILL.md +1 -1
- package/skills/luckiest-image/SKILL.md +1 -1
- package/skills/luckiest-launch/SKILL.md +1 -1
- package/skills/luckiest-lead-magnets/SKILL.md +1 -1
- package/skills/luckiest-marketing-ideas/SKILL.md +1 -1
- package/skills/luckiest-marketing-plan/SKILL.md +1 -1
- package/skills/luckiest-marketing-psychology/SKILL.md +1 -1
- package/skills/luckiest-model-router/SKILL.md +1 -1
- package/skills/luckiest-offers/SKILL.md +1 -1
- package/skills/luckiest-onboarding/SKILL.md +1 -1
- package/skills/luckiest-paywalls/SKILL.md +1 -1
- package/skills/luckiest-popups/SKILL.md +1 -1
- package/skills/luckiest-pricing/SKILL.md +1 -1
- package/skills/luckiest-product-marketing/SKILL.md +1 -1
- package/skills/luckiest-programmatic-seo/SKILL.md +1 -1
- package/skills/luckiest-prompt-rewrite/SKILL.md +1 -1
- package/skills/luckiest-prospecting/SKILL.md +1 -1
- package/skills/luckiest-public-relations/SKILL.md +1 -1
- package/skills/luckiest-referrals/SKILL.md +1 -1
- package/skills/luckiest-revops/SKILL.md +1 -1
- package/skills/luckiest-sales-enablement/SKILL.md +1 -1
- package/skills/luckiest-schema/SKILL.md +1 -1
- package/skills/luckiest-seo-audit/SKILL.md +1 -1
- package/skills/luckiest-session-handoff/SKILL.md +1 -1
- package/skills/luckiest-signup/SKILL.md +1 -1
- package/skills/luckiest-site-architecture/SKILL.md +1 -1
- package/skills/luckiest-sms/SKILL.md +1 -1
- package/skills/luckiest-social/SKILL.md +1 -1
- package/skills/luckiest-thinker/SKILL.md +1 -1
- package/skills/luckiest-trends/SKILL.md +1 -1
- package/skills/luckiest-video/SKILL.md +1 -1
- package/skills/luckiest-website-cloner/ATTRIBUTION.md +29 -0
- package/skills/luckiest-website-cloner/CHANGELOG.md +8 -0
- package/skills/luckiest-website-cloner/LICENSE +21 -0
- package/skills/luckiest-website-cloner/SKILL.md +289 -0
- package/skills/luckiest-website-cloner/references/builtin-browser-recipes.md +74 -0
- package/skills/luckiest-website-cloner/references/compositing.md +65 -0
- package/skills/luckiest-website-cloner/references/fidelity-fast-path.md +92 -0
- package/skills/luckiest-website-cloner/references/playwright-cli-recipes.md +68 -0
- package/skills/luckiest-website-cloner/references/teardown.md +142 -0
- package/skills/luckiest-website-cloner/references/visual-qa.md +102 -0
- package/skills/luckiest-website-cloner/scripts/build-bundle.cjs +12 -0
- package/skills/luckiest-website-cloner/scripts/motion-probe.js +423 -0
- package/skills/luckiest-website-cloner/scripts/surface-map.js +392 -0
- package/skills/luckiest-website-cloner/scripts/tokens-probe.js +178 -0
- package/skills/luckiest-website-cloner-dom/ATTRIBUTION.md +4 -0
- package/skills/luckiest-website-cloner-dom/CHANGELOG.md +8 -0
- package/skills/luckiest-website-cloner-dom/LICENSE +21 -0
- package/skills/luckiest-website-cloner-dom/SKILL.md +170 -0
- package/skills/luckiest-website-cloner-dom/references/asset-resolution.md +93 -0
- package/skills/luckiest-website-cloner-dom/references/interaction-fingerprints.md +85 -0
- package/skills/luckiest-website-cloner-remix/ATTRIBUTION.md +4 -0
- package/skills/luckiest-website-cloner-remix/CHANGELOG.md +8 -0
- package/skills/luckiest-website-cloner-remix/LICENSE +21 -0
- package/skills/luckiest-website-cloner-remix/SKILL.md +202 -0
- package/skills/luckiest-website-cloner-remix/references/directions.md +82 -0
- package/skills/luckiest-website-cloner-remix/references/reskin.md +84 -0
- package/skills/luckiest-website-cloner-remix/references/tweak-panel.md +72 -0
- package/skills/luckiest-website-cloner-remix/scripts/apply-overrides.cjs +105 -0
- package/skills/luckiest-website-cloner-remix/scripts/gallery.cjs +71 -0
- package/skills/luckiest-website-cloner-remix/scripts/tokenize-css.cjs +127 -0
- package/skills/luckiest-website-cloner-remix/scripts/tweak-panel.js +169 -0
- package/skills/luckiest-website-cloner-shaders/ATTRIBUTION.md +11 -0
- package/skills/luckiest-website-cloner-shaders/CHANGELOG.md +8 -0
- package/skills/luckiest-website-cloner-shaders/LICENSE +21 -0
- package/skills/luckiest-website-cloner-shaders/SKILL.md +129 -0
- package/skills/luckiest-website-cloner-shaders/references/capture-backends.md +89 -0
- package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/SKILL.md +123 -0
- package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/references/capture-backends.md +201 -0
- package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/references/evidence-policy.md +93 -0
- package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/references/operating-contract.md +82 -0
- package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/references/qa-failure-policy.md +100 -0
- package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/references/recon-kernel.md +206 -0
- package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/references/replay-policy.md +145 -0
- package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/references/shaders-com.md +212 -0
- package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/references/source-analysis.md +112 -0
- package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/references/surface-discovery.md +113 -0
- package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/references/target-lock.md +205 -0
- package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/references/three-shader-reconstruction.md +155 -0
- package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/references/tool-capability-matrix.md +57 -0
- package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/references/unicorn-studio.md +387 -0
- package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/scripts/fetch-rendered-dom.mjs +178 -0
- package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/scripts/scan-bundle.sh +80 -0
- package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/templates/extraction-report.md +41 -0
- package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/templates/known-gaps.md +14 -0
- package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/templates/qa-report.md +74 -0
- package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/templates/replay-manifest.json +147 -0
- package/skills/luckiest-website-cloner-shaders/vendor/web-shader-extractor/templates/run-state.json +75 -0
- 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`.
|