waygraph 0.15.29 → 0.15.31

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 (37) hide show
  1. package/dist/auto-explore-run.js +9 -6
  2. package/dist/pilot-overlay/fixtures.d.ts +81 -0
  3. package/dist/pilot-overlay/fixtures.js +334 -0
  4. package/dist/pilot-overlay/panel.d.ts +34 -0
  5. package/dist/pilot-overlay/panel.js +155 -0
  6. package/dist/pilot-overlay/shell.d.ts +48 -0
  7. package/dist/pilot-overlay/shell.js +276 -0
  8. package/dist/pilot-overlay.d.ts +3 -158
  9. package/dist/pilot-overlay.js +4 -778
  10. package/dist/runner/cursor.js +3 -3
  11. package/dist/runner/inpage/banner.js +2 -2
  12. package/dist/runner/inpage/core.js +23 -23
  13. package/dist/runner/inpage/device.js +11 -11
  14. package/dist/runner/inpage/panel-chrome.js +3 -3
  15. package/dist/runner/inpage/stamp.js +2 -2
  16. package/dist/runner/inpage/swipe-zoom.js +10 -10
  17. package/dist/runner/inpage/todos.js +6 -6
  18. package/dist/runner/overlay-css.js +21 -18
  19. package/dist/runner/overlay-install.js +5 -2
  20. package/dist/runner/rings.js +1 -1
  21. package/dist/runner/slides.js +11 -11
  22. package/dist/runner/step-panels.js +18 -18
  23. package/dist/runner/teardown.js +8 -8
  24. package/dist/runner/todo-dock.js +1 -1
  25. package/dist/step-overlay.js +20 -18
  26. package/dist/ui/shadow.d.ts +15 -0
  27. package/dist/ui/shadow.js +42 -0
  28. package/examples/saucedemo/.waygraph-auto/1bd7b7bf.log +0 -0
  29. package/examples/saucedemo/.waygraph-auto/2a577961.log +0 -0
  30. package/examples/saucedemo/.waygraph-auto/401177a3.log +0 -0
  31. package/examples/saucedemo/.waygraph-auto/68fa0682.log +0 -0
  32. package/examples/saucedemo/.waygraph-auto/982138cf.log +0 -0
  33. package/examples/saucedemo/.waygraph-auto/a8645294.log +0 -0
  34. package/examples/saucedemo/.waygraph-auto/bb0e0e46.log +0 -0
  35. package/examples/saucedemo/.waygraph-auto/e230f24e.log +0 -0
  36. package/examples/saucedemo/.waygraph-auto/fc917c18.log +0 -0
  37. package/package.json +1 -1
@@ -48,7 +48,7 @@ export async function playSwipeTrail(page, opts) {
48
48
  : "left";
49
49
  const ms = Math.max(280, Math.min(1400, Number(payload.ms) || 720));
50
50
  const label = payload.label || "swipe";
51
- let layer = document.getElementById("wg-swipe-layer");
51
+ let layer = __wgById("wg-swipe-layer");
52
52
  if (layer) layer.remove();
53
53
  layer = document.createElement("div");
54
54
  layer.id = "wg-swipe-layer";
@@ -67,7 +67,7 @@ export async function playSwipeTrail(page, opts) {
67
67
  "border:1px solid rgba(56,189,248,.55);font:700 12px/1.2 system-ui,sans-serif;";
68
68
  layer.appendChild(lab);
69
69
  layer.appendChild(finger);
70
- document.documentElement.appendChild(layer);
70
+ __wgAdd(layer);
71
71
  const vw = window.innerWidth || 390;
72
72
  const vh = window.innerHeight || 844;
73
73
  const pad = Math.min(vw, vh) * 0.18;
@@ -121,7 +121,7 @@ export async function playSwipeTrail(page, opts) {
121
121
  });
122
122
  if (i === steps) {
123
123
  setTimeout(() => {
124
- const el = document.getElementById("wg-swipe-layer");
124
+ const el = __wgById("wg-swipe-layer");
125
125
  if (el) el.remove();
126
126
  }, 400);
127
127
  }
@@ -12,7 +12,7 @@ export function installBanner({ title, favicon, bannerPos, todoPos, envAutoplay,
12
12
  }
13
13
  };
14
14
  if (title) {
15
- let banner = document.getElementById("wg-banner");
15
+ let banner = __wgById("wg-banner");
16
16
  if (!banner) {
17
17
  banner = document.createElement("div");
18
18
  banner.id = "wg-banner";
@@ -39,7 +39,7 @@ export function installBanner({ title, favicon, bannerPos, todoPos, envAutoplay,
39
39
  text.textContent = title;
40
40
  banner.appendChild(tag);
41
41
  banner.appendChild(text);
42
- document.documentElement.appendChild(banner);
42
+ __wgAdd(banner);
43
43
  } else {
44
44
  // Fixture / episode title changes every step - update in place
45
45
  // (banner is created once; do not leave the first step's text stuck).
@@ -19,17 +19,17 @@ export function installCore({ title, favicon, bannerPos, todoPos, envAutoplay, t
19
19
  } catch {
20
20
  /* private mode / blocked storage - falls back to manual gating */
21
21
  }
22
- if (!document.getElementById("wg-ring")) {
22
+ if (!__wgById("wg-ring")) {
23
23
  const ring = document.createElement("div");
24
24
  ring.id = "wg-ring";
25
- document.documentElement.appendChild(ring);
25
+ __wgAdd(ring);
26
26
  }
27
- if (!document.getElementById("wg-ring-label")) {
27
+ if (!__wgById("wg-ring-label")) {
28
28
  const ringLabel = document.createElement("div");
29
29
  ringLabel.id = "wg-ring-label";
30
- document.documentElement.appendChild(ringLabel);
30
+ __wgAdd(ringLabel);
31
31
  }
32
- if (!document.getElementById("wg-cursor")) {
32
+ if (!__wgById("wg-cursor")) {
33
33
  const cursor = document.createElement("div");
34
34
  cursor.id = "wg-cursor";
35
35
  // Dark fill + white stroke, same as help-center-clip-engine's own
@@ -39,15 +39,15 @@ export function installCore({ title, favicon, bannerPos, todoPos, envAutoplay, t
39
39
  "<svg viewBox='0 0 32 32' width='24' height='24'>" +
40
40
  "<path fill='#0C0C1A' stroke='#fff' stroke-width='1.4' stroke-linejoin='round' " +
41
41
  "d='M6 3.5l1.4 22.5 5.8-5.4 4.2 9.4 3.6-1.6-4.2-9.2H26z'/></svg>";
42
- document.documentElement.appendChild(cursor);
42
+ __wgAdd(cursor);
43
43
  }
44
- if (!document.getElementById("wg-click-pulse")) {
44
+ if (!__wgById("wg-click-pulse")) {
45
45
  const pulse = document.createElement("div");
46
46
  pulse.id = "wg-click-pulse";
47
- document.documentElement.appendChild(pulse);
47
+ __wgAdd(pulse);
48
48
  }
49
49
  window.__wgMoveCursorTo = (x, y, ms, instant) => {
50
- const cursor = document.getElementById("wg-cursor");
50
+ const cursor = __wgById("wg-cursor");
51
51
  if (!cursor) return;
52
52
  cursor.style.setProperty("--wg-cursor-ms", (ms || 600) + "ms");
53
53
  if (instant) {
@@ -62,12 +62,12 @@ export function installCore({ title, favicon, bannerPos, todoPos, envAutoplay, t
62
62
  cursor.style.opacity = "1";
63
63
  };
64
64
  window.__wgHideCursor = () => {
65
- const cursor = document.getElementById("wg-cursor");
65
+ const cursor = __wgById("wg-cursor");
66
66
  if (cursor) cursor.style.opacity = "0";
67
67
  };
68
68
  window.__wgPositionRing = (box, label, tone, style) => {
69
- const ring = document.getElementById("wg-ring");
70
- const ringLabel = document.getElementById("wg-ring-label");
69
+ const ring = __wgById("wg-ring");
70
+ const ringLabel = __wgById("wg-ring-label");
71
71
  if (!ring || !ringLabel || !box) return;
72
72
  const raw = (tone || "planned") + "";
73
73
  const t =
@@ -119,12 +119,12 @@ export function installCore({ title, favicon, bannerPos, todoPos, envAutoplay, t
119
119
  window.__wgTodosSetBehind = (on) => {
120
120
  const ui = window.__wgTodoDockUi || {};
121
121
  if (ui.behindRing === false) {
122
- document.querySelectorAll(".wg-todo-dock, #wg-todo-dock").forEach((el) => {
122
+ __wgQA(".wg-todo-dock, #wg-todo-dock").forEach((el) => {
123
123
  el.classList.remove("wg-todo-behind");
124
124
  });
125
125
  return;
126
126
  }
127
- document.querySelectorAll(".wg-todo-dock, #wg-todo-dock").forEach((el) => {
127
+ __wgQA(".wg-todo-dock, #wg-todo-dock").forEach((el) => {
128
128
  el.classList.toggle("wg-todo-behind", !!on);
129
129
  });
130
130
  };
@@ -145,7 +145,7 @@ export function installCore({ title, favicon, bannerPos, todoPos, envAutoplay, t
145
145
  const r = el.getBoundingClientRect();
146
146
  return !(r.right < rx1 || r.left > rx2 || r.bottom < ry1 || r.top > ry2);
147
147
  };
148
- const docks = [...document.querySelectorAll(".wg-todo-dock, #wg-todo-dock")].filter(
148
+ const docks = [...__wgQA(".wg-todo-dock, #wg-todo-dock")].filter(
149
149
  (el, i, arr) => arr.indexOf(el) === i,
150
150
  );
151
151
  for (const dock of docks) {
@@ -194,7 +194,7 @@ export function installCore({ title, favicon, bannerPos, todoPos, envAutoplay, t
194
194
  tick();
195
195
  };
196
196
  window.__wgClickPulse = (x, y, tone) => {
197
- const pulse = document.getElementById("wg-click-pulse");
197
+ const pulse = __wgById("wg-click-pulse");
198
198
  if (!pulse) return;
199
199
  const raw = (tone || "planned") + "";
200
200
  pulse.dataset.tone =
@@ -214,14 +214,14 @@ export function installCore({ title, favicon, bannerPos, todoPos, envAutoplay, t
214
214
  // action finishes, not just its first sub-step.
215
215
  if (window.__wgNarrateOwnsRing) return;
216
216
  if (window.__wgStopRingFollow) window.__wgStopRingFollow();
217
- const ring = document.getElementById("wg-ring");
218
- const ringLabel = document.getElementById("wg-ring-label");
217
+ const ring = __wgById("wg-ring");
218
+ const ringLabel = __wgById("wg-ring-label");
219
219
  if (ring) ring.style.opacity = "0";
220
220
  if (ringLabel) ringLabel.style.opacity = "0";
221
221
  if (window.__wgClearFocus) window.__wgClearFocus();
222
222
  if (window.__wgTodosSetBehind) window.__wgTodosSetBehind(false);
223
223
  window.__wgTodoCollisionLocked = false;
224
- document.querySelectorAll(".wg-todo-dock[data-tucked], #wg-todo-dock[data-tucked]").forEach((el) => {
224
+ __wgQA(".wg-todo-dock[data-tucked], #wg-todo-dock[data-tucked]").forEach((el) => {
225
225
  delete el.dataset.tucked;
226
226
  });
227
227
  // Honor zoomOut:false - keep camera until next zoom / desktop clear.
@@ -236,11 +236,11 @@ export function installCore({ title, favicon, bannerPos, todoPos, envAutoplay, t
236
236
  }
237
237
  };
238
238
  window.__wgClearFocus = () => {
239
- const veil = document.getElementById("wg-focus-veil");
239
+ const veil = __wgById("wg-focus-veil");
240
240
  if (!veil) return;
241
241
  veil.classList.remove("wg-in");
242
242
  setTimeout(() => {
243
- const v = document.getElementById("wg-focus-veil");
243
+ const v = __wgById("wg-focus-veil");
244
244
  if (v && !v.classList.contains("wg-in")) v.remove();
245
245
  }, 320);
246
246
  };
@@ -249,12 +249,12 @@ export function installCore({ title, favicon, bannerPos, todoPos, envAutoplay, t
249
249
  if (window.__wgClearFocus) window.__wgClearFocus();
250
250
  return;
251
251
  }
252
- let veil = document.getElementById("wg-focus-veil");
252
+ let veil = __wgById("wg-focus-veil");
253
253
  if (!veil) {
254
254
  veil = document.createElement("div");
255
255
  veil.id = "wg-focus-veil";
256
256
  veil.setAttribute("data-wg-ui", "1");
257
- document.documentElement.appendChild(veil);
257
+ __wgAdd(veil);
258
258
  }
259
259
  const pad = 10;
260
260
  veil.style.left = Math.max(0, box.x - pad) + "px";
@@ -10,7 +10,7 @@ export function installDevice({ title, favicon, bannerPos, todoPos, envAutoplay,
10
10
  ? payload.sync
11
11
  : "keep";
12
12
  const device = payload && payload.device ? payload.device : null;
13
- const cursor = document.getElementById("wg-cursor");
13
+ const cursor = __wgById("wg-cursor");
14
14
  const MOUSE_SVG =
15
15
  "<svg viewBox='0 0 32 32' width='24' height='24'>" +
16
16
  "<path fill='#0C0C1A' stroke='#fff' stroke-width='1.4' stroke-linejoin='round' " +
@@ -45,12 +45,12 @@ export function installDevice({ title, favicon, bannerPos, todoPos, envAutoplay,
45
45
  }
46
46
  };
47
47
  const ensureChip = (preset, touch, remain, orientation) => {
48
- let badge = document.getElementById("wg-device-badge");
48
+ let badge = __wgById("wg-device-badge");
49
49
  if (preset === "desktop" && !touch) {
50
50
  if (badge) {
51
51
  badge.classList.remove("wg-in");
52
52
  setTimeout(() => {
53
- const b = document.getElementById("wg-device-badge");
53
+ const b = __wgById("wg-device-badge");
54
54
  if (b) b.remove();
55
55
  }, 320);
56
56
  }
@@ -60,7 +60,7 @@ export function installDevice({ title, favicon, bannerPos, todoPos, envAutoplay,
60
60
  badge = document.createElement("div");
61
61
  badge.id = "wg-device-badge";
62
62
  badge.setAttribute("data-wg-ui", "1");
63
- document.documentElement.appendChild(badge);
63
+ __wgAdd(badge);
64
64
  }
65
65
  badge.dataset.preset = preset;
66
66
  badge.dataset.touch = touch ? "1" : "0";
@@ -85,7 +85,7 @@ export function installDevice({ title, favicon, bannerPos, todoPos, envAutoplay,
85
85
  badge.classList.add("wg-in");
86
86
  };
87
87
  const showToast = (preset, touch, title, sub, orientation) => {
88
- let toast = document.getElementById("wg-device-toast");
88
+ let toast = __wgById("wg-device-toast");
89
89
  if (toast && toast._wgTimer) {
90
90
  clearTimeout(toast._wgTimer);
91
91
  toast._wgTimer = null;
@@ -94,10 +94,10 @@ export function installDevice({ title, favicon, bannerPos, todoPos, envAutoplay,
94
94
  toast = document.createElement("div");
95
95
  toast.id = "wg-device-toast";
96
96
  toast.setAttribute("data-wg-ui", "1");
97
- document.documentElement.appendChild(toast);
97
+ __wgAdd(toast);
98
98
  }
99
99
  // Hide chip while toast is up (same corner).
100
- const badge = document.getElementById("wg-device-badge");
100
+ const badge = __wgById("wg-device-badge");
101
101
  if (badge) badge.classList.remove("wg-in");
102
102
  toast.dataset.preset = preset;
103
103
  toast.innerHTML =
@@ -115,7 +115,7 @@ export function installDevice({ title, favicon, bannerPos, todoPos, envAutoplay,
115
115
  toast.classList.add("wg-out");
116
116
  toast.classList.remove("wg-in");
117
117
  setTimeout(() => {
118
- const t = document.getElementById("wg-device-toast");
118
+ const t = __wgById("wg-device-toast");
119
119
  if (t) t.remove();
120
120
  if (preset !== "desktop" || touch) {
121
121
  ensureChip(preset, touch, true, orientation);
@@ -142,13 +142,13 @@ export function installDevice({ title, favicon, bannerPos, todoPos, envAutoplay,
142
142
  "landscape",
143
143
  );
144
144
  setTimeout(() => {
145
- const badge = document.getElementById("wg-device-badge");
145
+ const badge = __wgById("wg-device-badge");
146
146
  if (badge) badge.remove();
147
147
  }, 2600);
148
148
  } else {
149
- const badge = document.getElementById("wg-device-badge");
149
+ const badge = __wgById("wg-device-badge");
150
150
  if (badge) badge.remove();
151
- const toast = document.getElementById("wg-device-toast");
151
+ const toast = __wgById("wg-device-toast");
152
152
  if (toast) toast.remove();
153
153
  }
154
154
  window.__wgDevicePreset = "desktop";
@@ -69,7 +69,7 @@ export function installPanelChrome({ title, favicon, bannerPos, todoPos, envAuto
69
69
  } catch {
70
70
  /* ignore */
71
71
  }
72
- const runBtn = document.getElementById("wg-run");
72
+ const runBtn = __wgById("wg-run");
73
73
  const show = !!hidden && !auto && !!runBtn;
74
74
  miniNext.classList.toggle("wg-mini-next-show", show);
75
75
  if (runBtn) {
@@ -125,7 +125,7 @@ export function installPanelChrome({ title, favicon, bannerPos, todoPos, envAuto
125
125
  miniNext.dataset.wgWired = "1";
126
126
  miniNext.addEventListener("click", (e) => {
127
127
  e.stopPropagation();
128
- const runBtn = document.getElementById("wg-run");
128
+ const runBtn = __wgById("wg-run");
129
129
  if (runBtn && !runBtn.disabled) {
130
130
  runBtn.click();
131
131
  return;
@@ -133,7 +133,7 @@ export function installPanelChrome({ title, favicon, bannerPos, todoPos, envAuto
133
133
  if (typeof window.__wgNext === "function") window.__wgNext({});
134
134
  });
135
135
  }
136
- const autoCb = document.getElementById("wg-autoplay-cb");
136
+ const autoCb = __wgById("wg-autoplay-cb");
137
137
  if (autoCb && !autoCb.dataset.wgMiniWired) {
138
138
  autoCb.dataset.wgMiniWired = "1";
139
139
  autoCb.addEventListener("change", () => {
@@ -20,7 +20,7 @@ export function installStamp({ title, favicon, bannerPos, todoPos, envAutoplay,
20
20
  el.setAttribute("data-wg-ready", meta.ready === false ? "0" : "1");
21
21
  };
22
22
  window.__wgOverlayBeacon = () => {
23
- return Array.from(document.querySelectorAll("[data-wg-ui=\"1\"]")).map((el) => {
23
+ return Array.from(__wgQA("[data-wg-ui=\"1\"]")).map((el) => {
24
24
  const r = el.getBoundingClientRect();
25
25
  const st = getComputedStyle(el);
26
26
  return {
@@ -41,6 +41,6 @@ export function installStamp({ title, favicon, bannerPos, todoPos, envAutoplay,
41
41
  };
42
42
  });
43
43
  };
44
- const existingBanner = document.getElementById("wg-banner");
44
+ const existingBanner = __wgById("wg-banner");
45
45
  if (existingBanner) window.__wgStampModal(existingBanner, "banner", { ready: true });
46
46
  }
@@ -15,7 +15,7 @@ export function installSwipeZoom({ title, favicon, bannerPos, todoPos, envAutopl
15
15
  o.label ||
16
16
  (dir === "left" || dir === "right" ? "swipe" : "swipe") +
17
17
  (o.hint ? " \u00b7 " + o.hint : "");
18
- let layer = document.getElementById("wg-swipe-layer");
18
+ let layer = __wgById("wg-swipe-layer");
19
19
  if (layer && layer._wgTimer) {
20
20
  clearTimeout(layer._wgTimer);
21
21
  layer._wgTimer = null;
@@ -31,7 +31,7 @@ export function installSwipeZoom({ title, favicon, bannerPos, todoPos, envAutopl
31
31
  lab.textContent = label;
32
32
  layer.appendChild(lab);
33
33
  layer.appendChild(finger);
34
- document.documentElement.appendChild(layer);
34
+ __wgAdd(layer);
35
35
  const vw = window.innerWidth || 390;
36
36
  const vh = window.innerHeight || 844;
37
37
  const pad = Math.min(vw, vh) * 0.18;
@@ -89,7 +89,7 @@ export function installSwipeZoom({ title, favicon, bannerPos, todoPos, envAutopl
89
89
  finger.style.opacity = "0";
90
90
  layer.classList.remove("wg-in");
91
91
  layer._wgTimer = setTimeout(() => {
92
- const el = document.getElementById("wg-swipe-layer");
92
+ const el = __wgById("wg-swipe-layer");
93
93
  if (el) el.remove();
94
94
  }, 380);
95
95
  }
@@ -108,7 +108,7 @@ export function installSwipeZoom({ title, favicon, bannerPos, todoPos, envAutopl
108
108
  delete el.dataset.wgZoomed;
109
109
  });
110
110
  // Undo any prior shell-camera experiment - restore device fit scale only.
111
- const shell = document.getElementById("wg-device-shell");
111
+ const shell = __wgById("wg-device-shell");
112
112
  if (shell && shell.dataset.wgCamBase != null) {
113
113
  shell.style.transform = shell.dataset.wgCamBase;
114
114
  if (shell.dataset.wgCamOrigin) {
@@ -130,12 +130,12 @@ export function installSwipeZoom({ title, favicon, bannerPos, todoPos, envAutopl
130
130
  window.__wgSetZoomBadge = (scale, sel) => {
131
131
  const n = Number(scale);
132
132
  const level = Number.isFinite(n) && n > 0 ? n : 1;
133
- let badge = document.getElementById("wg-zoom-badge");
133
+ let badge = __wgById("wg-zoom-badge");
134
134
  if (!badge) {
135
135
  badge = document.createElement("div");
136
136
  badge.id = "wg-zoom-badge";
137
137
  badge.setAttribute("data-wg-ui", "1");
138
- document.documentElement.appendChild(badge);
138
+ __wgAdd(badge);
139
139
  }
140
140
  const zoomed = level > 1.001 || level < 0.999;
141
141
  badge.dataset.zoomed = zoomed ? "1" : "0";
@@ -156,12 +156,12 @@ export function installSwipeZoom({ title, favicon, bannerPos, todoPos, envAutopl
156
156
  }
157
157
  };
158
158
  window.__wgSetTypingBadge = (on, label) => {
159
- let badge = document.getElementById("wg-typing-badge");
159
+ let badge = __wgById("wg-typing-badge");
160
160
  if (!on) {
161
161
  if (badge) {
162
162
  badge.classList.remove("wg-in");
163
163
  setTimeout(() => {
164
- const b = document.getElementById("wg-typing-badge");
164
+ const b = __wgById("wg-typing-badge");
165
165
  if (b && !b.classList.contains("wg-in")) b.remove();
166
166
  }, 220);
167
167
  }
@@ -171,7 +171,7 @@ export function installSwipeZoom({ title, favicon, bannerPos, todoPos, envAutopl
171
171
  badge = document.createElement("div");
172
172
  badge.id = "wg-typing-badge";
173
173
  badge.setAttribute("data-wg-ui", "1");
174
- document.documentElement.appendChild(badge);
174
+ __wgAdd(badge);
175
175
  }
176
176
  const text = label ? String(label).slice(0, 40) : "typing";
177
177
  badge.innerHTML =
@@ -196,7 +196,7 @@ export function installSwipeZoom({ title, favicon, bannerPos, todoPos, envAutopl
196
196
  el.style.removeProperty("position");
197
197
  delete el.dataset.wgZoomed;
198
198
  });
199
- const shell = document.getElementById("wg-device-shell");
199
+ const shell = __wgById("wg-device-shell");
200
200
  if (shell && shell.dataset.wgCamBase != null) {
201
201
  shell.style.transform = shell.dataset.wgCamBase;
202
202
  shell.style.transformOrigin = shell.dataset.wgCamOrigin || "center center";
@@ -43,10 +43,10 @@ export function installTodos({ title, favicon, bannerPos, todoPos, envAutoplay,
43
43
  "_default";
44
44
 
45
45
  // Drop any in-panel leftover (old builds put #wg-todos in .wg-body).
46
- document.querySelectorAll("#wg-panel #wg-todos").forEach((el) => el.remove());
46
+ __wgQA("#wg-panel #wg-todos").forEach((el) => el.remove());
47
47
 
48
48
  const allDocks = () =>
49
- [...document.querySelectorAll(".wg-todo-dock, #wg-todo-dock")].filter(
49
+ [...__wgQA(".wg-todo-dock, #wg-todo-dock")].filter(
50
50
  (el, i, arr) => arr.indexOf(el) === i,
51
51
  );
52
52
  const relayoutTodoDocks = () => {
@@ -60,11 +60,11 @@ export function installTodos({ title, favicon, bannerPos, todoPos, envAutoplay,
60
60
  const findDock = (key) => {
61
61
  if (key === "_default") {
62
62
  return (
63
- document.querySelector('.wg-todo-dock[data-wg-todo-key="_default"]') ||
64
- document.getElementById("wg-todo-dock")
63
+ __wgQ('.wg-todo-dock[data-wg-todo-key="_default"]') ||
64
+ __wgById("wg-todo-dock")
65
65
  );
66
66
  }
67
- const all = document.querySelectorAll(".wg-todo-dock");
67
+ const all = __wgQA(".wg-todo-dock");
68
68
  for (let i = 0; i < all.length; i++) {
69
69
  if (all[i].getAttribute("data-wg-todo-key") === String(key)) return all[i];
70
70
  }
@@ -141,7 +141,7 @@ export function installTodos({ title, favicon, bannerPos, todoPos, envAutoplay,
141
141
  /* ignore */
142
142
  }
143
143
  });
144
- document.documentElement.appendChild(dock);
144
+ __wgAdd(dock);
145
145
  } else if (wantPos) {
146
146
  dock.dataset.pos = wantPos;
147
147
  try {
@@ -115,24 +115,6 @@ export const RING_CSS =
115
115
  ".wg-todo-dock .wg-todo-dock-title{font:700 11px/1.2 system-ui,sans-serif;color:#c9a6ff;" +
116
116
  "letter-spacing:.04em;text-transform:uppercase;margin:0 0 8px;}" +
117
117
  ".wg-todo-dock .wg-todos-list,#wg-todo-dock #wg-todos,.wg-todo-dock #wg-todos{list-style:none;margin:0;padding:0;background:transparent;border:none;}" +
118
- // Video device stage: keep recordVideo size fixed; center a device-sized shell.
119
- "html.wg-video-device-stage{background:#0b1220 !important;}" +
120
- "html.wg-video-device-stage body{margin:0 !important;min-height:100vh !important;" +
121
- "display:flex !important;align-items:center !important;justify-content:center !important;" +
122
- "background:#0b1220 !important;overflow:hidden !important;}" +
123
- "#wg-device-shell{flex-shrink:0;overflow:auto;background:#fff;" +
124
- "border-radius:16px;box-shadow:0 24px 80px rgba(0,0,0,.55),0 0 0 1px rgba(255,255,255,.08);" +
125
- "transform-origin:center center;" +
126
- /* Force radius clip on all corners (Chrome + transform/scale). */
127
- "-webkit-mask-image:-webkit-radial-gradient(white,black);" +
128
- "isolation:isolate;" +
129
- "transition:border-radius .55s cubic-bezier(.22,1,.36,1),box-shadow .55s ease," +
130
- "transform .55s cubic-bezier(.22,1,.36,1),width .5s ease,height .5s ease,max-width .5s ease,max-height .5s ease;}" +
131
- "#wg-device-shell.wg-shell-enter{border-radius:0;box-shadow:none;}" +
132
- "#wg-device-shell.wg-shell-shutter-out{border-radius:0 !important;" +
133
- "box-shadow:none !important;outline:none !important;border:none !important;}" +
134
- "#wg-device-shell.wg-shell-desktop-flat{border-radius:0 !important;box-shadow:none !important;" +
135
- "outline:none !important;border:none !important;-webkit-mask-image:none;}" +
136
118
  // Always-on zoom HUD - bottom-right (top-left is crowded: todos + banners).
137
119
  "#wg-zoom-badge{position:fixed;z-index:2147483646;bottom:14px;right:14px;" +
138
120
  "display:flex;align-items:center;gap:7px;padding:6px 11px 6px 8px;" +
@@ -329,3 +311,24 @@ export const WAYGRAPH_FAVICON =
329
311
  "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'>" +
330
312
  "<circle cx='16' cy='16' r='14' fill='#7C3AED'/></svg>",
331
313
  );
314
+
315
+ // Rules that style the HOST page (device stage) - these must stay in the light DOM, outside the overlay's shadow root.
316
+ export const HOST_CSS =
317
+ // Video device stage: keep recordVideo size fixed; center a device-sized shell.
318
+ "html.wg-video-device-stage{background:#0b1220 !important;}" +
319
+ "html.wg-video-device-stage body{margin:0 !important;min-height:100vh !important;" +
320
+ "display:flex !important;align-items:center !important;justify-content:center !important;" +
321
+ "background:#0b1220 !important;overflow:hidden !important;}" +
322
+ "#wg-device-shell{flex-shrink:0;overflow:auto;background:#fff;" +
323
+ "border-radius:16px;box-shadow:0 24px 80px rgba(0,0,0,.55),0 0 0 1px rgba(255,255,255,.08);" +
324
+ "transform-origin:center center;" +
325
+ /* Force radius clip on all corners (Chrome + transform/scale). */
326
+ "-webkit-mask-image:-webkit-radial-gradient(white,black);" +
327
+ "isolation:isolate;" +
328
+ "transition:border-radius .55s cubic-bezier(.22,1,.36,1),box-shadow .55s ease," +
329
+ "transform .55s cubic-bezier(.22,1,.36,1),width .5s ease,height .5s ease,max-width .5s ease,max-height .5s ease;}" +
330
+ "#wg-device-shell.wg-shell-enter{border-radius:0;box-shadow:none;}" +
331
+ "#wg-device-shell.wg-shell-shutter-out{border-radius:0 !important;" +
332
+ "box-shadow:none !important;outline:none !important;border:none !important;}" +
333
+ "#wg-device-shell.wg-shell-desktop-flat{border-radius:0 !important;box-shadow:none !important;" +
334
+ "outline:none !important;border:none !important;-webkit-mask-image:none;}";
@@ -1,6 +1,7 @@
1
1
  // Moved verbatim from the former CHAIN_RUNNER_SCRIPT template string in cli.ts (see src/ARCHITECTURE.md).
2
2
  // Runs inside the target project's own waygraph copy - keep it dependency-light and self-contained.
3
- import { RING_CSS, WAYGRAPH_FAVICON } from "./overlay-css.js";
3
+ import { HOST_CSS, RING_CSS, WAYGRAPH_FAVICON } from "./overlay-css.js";
4
+ import { ensureShadowRoot } from "../ui/shadow.js";
4
5
  import { resolveTodoDockUi } from "../highlights.js";
5
6
  import { installCore } from "./inpage/core.js";
6
7
  import { installSwipeZoom } from "./inpage/swipe-zoom.js";
@@ -12,7 +13,9 @@ import { installDevice } from "./inpage/device.js";
12
13
  import { applyVideoDeviceStage } from "./device-stage.js";
13
14
 
14
15
  export async function installOverlay(page, title) {
15
- await page.addStyleTag({ content: RING_CSS }).catch(() => {});
16
+ await ensureShadowRoot(page);
17
+ await page.evaluate(([css, key]) => __wgCss(css, key), [RING_CSS, "wg-overlay-css"]).catch(() => {});
18
+ await page.addStyleTag({ content: HOST_CSS }).catch(() => {});
16
19
  // Default top-left; override with WAYGRAPH_TITLE_POS=left|center|right.
17
20
  // Click cycles left -> center -> right (persisted in localStorage so a
18
21
  // navigation that rebuilds the banner keeps the human's last pick).
@@ -247,7 +247,7 @@ export async function cycleHighlightRings(page, highlights, gatesFast, opts) {
247
247
  return;
248
248
  }
249
249
  // Fallback for pages that never got installOverlay sync helper.
250
- const ul = document.getElementById("wg-todos");
250
+ const ul = __wgById("wg-todos");
251
251
  if (!ul) return;
252
252
  ul.innerHTML = todos
253
253
  .map((t) => {
@@ -66,7 +66,7 @@ export async function presentSlides(page, slides, _gate, opts) {
66
66
  }
67
67
  await page.evaluate(
68
68
  (info) => {
69
- let panel = document.getElementById("wg-panel");
69
+ let panel = __wgById("wg-panel");
70
70
  const isNew = !panel;
71
71
  if (!panel) {
72
72
  panel = document.createElement("div");
@@ -139,7 +139,7 @@ export async function presentSlides(page, slides, _gate, opts) {
139
139
  ">Auto-advancing...</div>" +
140
140
  "</div>";
141
141
  if (isNew) {
142
- document.documentElement.appendChild(panel);
142
+ __wgAdd(panel);
143
143
  requestAnimationFrame(() => panel.classList.add("wg-in"));
144
144
  }
145
145
  if (window.__wgWirePanelChrome) {
@@ -172,7 +172,7 @@ export async function presentSlides(page, slides, _gate, opts) {
172
172
  } catch {
173
173
  /* ignore */
174
174
  }
175
- const cb = document.getElementById("wg-autoplay-cb");
175
+ const cb = __wgById("wg-autoplay-cb");
176
176
  if (cb) {
177
177
  cb.checked = autoNow;
178
178
  cb.addEventListener("change", () => {
@@ -181,17 +181,17 @@ export async function presentSlides(page, slides, _gate, opts) {
181
181
  } catch {
182
182
  /* ignore */
183
183
  }
184
- const manual = document.getElementById("wg-gate-manual");
185
- const auto = document.getElementById("wg-gate-auto");
184
+ const manual = __wgById("wg-gate-manual");
185
+ const auto = __wgById("wg-gate-auto");
186
186
  if (manual) manual.style.display = cb.checked ? "none" : "";
187
187
  if (auto) auto.style.display = cb.checked ? "" : "none";
188
188
  });
189
189
  }
190
- const manual = document.getElementById("wg-gate-manual");
191
- const auto = document.getElementById("wg-gate-auto");
190
+ const manual = __wgById("wg-gate-manual");
191
+ const auto = __wgById("wg-gate-auto");
192
192
  if (manual) manual.style.display = autoNow ? "none" : "";
193
193
  if (auto) auto.style.display = autoNow ? "" : "none";
194
- const runBtn = document.getElementById("wg-run");
194
+ const runBtn = __wgById("wg-run");
195
195
  if (runBtn) {
196
196
  runBtn.removeAttribute("data-wg-acked");
197
197
  runBtn.addEventListener("click", (e) => {
@@ -205,8 +205,8 @@ export async function presentSlides(page, slides, _gate, opts) {
205
205
  const unlockAt = Date.now() + info.dwellMs;
206
206
  const tick = () => {
207
207
  const left = Math.max(0, unlockAt - Date.now());
208
- const hint = document.getElementById("wg-dwell-hint");
209
- const btn = document.getElementById("wg-run");
208
+ const hint = __wgById("wg-dwell-hint");
209
+ const btn = __wgById("wg-run");
210
210
  if (left <= 0) {
211
211
  if (hint) hint.remove();
212
212
  if (btn) btn.disabled = false;
@@ -248,7 +248,7 @@ export async function presentSlides(page, slides, _gate, opts) {
248
248
  for (;;) {
249
249
  const acked = await page
250
250
  .evaluate(() => {
251
- const btn = document.getElementById("wg-run");
251
+ const btn = __wgById("wg-run");
252
252
  return !!(btn && btn.getAttribute("data-wg-acked") === "1");
253
253
  })
254
254
  .catch(() => false);