shaders 2.5.114 → 2.5.115

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.
@@ -1,4 +1,4 @@
1
- import { ShaderInstance, PreviewOptions } from './types';
1
+ import { PreviewInstance, PreviewOptions } from './types';
2
2
 
3
3
  /**
4
4
  * Create a watermarked shader preview from a preview token or preset ID.
@@ -8,12 +8,16 @@ import { ShaderInstance, PreviewOptions } from './types';
8
8
  * @example
9
9
  * ```ts
10
10
  * const preview = await createPreview(canvas, {
11
- * presetId: 'abc123'
11
+ * presetId: 'abc123',
12
+ * configuration: { primaryColor: '#ff0000', intensity: 0.5 }
12
13
  * })
13
14
  *
15
+ * // Update configuration at runtime (no refetch)
16
+ * preview.setConfiguration({ primaryColor: '#00ff00', intensity: 0.8 })
17
+ *
14
18
  * // Cleanup
15
19
  * preview.destroy()
16
20
  * ```
17
21
  */
18
- export declare function createPreview(canvas: HTMLCanvasElement, options: PreviewOptions): Promise<ShaderInstance>;
22
+ export declare function createPreview(canvas: HTMLCanvasElement, options: PreviewOptions): Promise<PreviewInstance>;
19
23
  //# sourceMappingURL=createPreview.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createPreview.d.ts","sourceRoot":"","sources":["../src/createPreview.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAO7D;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,cAAc,CAAC,CAuCzB"}
1
+ {"version":3,"file":"createPreview.d.ts","sourceRoot":"","sources":["../src/createPreview.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAW,MAAM,SAAS,CAAA;AA8EvE;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,eAAe,CAAC,CA2F1B"}
@@ -3,24 +3,130 @@ import { decodePreviewDefinition } from "./decode.js";
3
3
  var DEFAULT_API_BASE = "https://shaders.com";
4
4
  var WATERMARK_TEXT = "Unlock your Shaders Pro license";
5
5
  var WATERMARK_LINK = "https://shaders.com/dashboard?pricing=true";
6
+ var RESERVED_IDENTIFIERS = new Set([
7
+ "break",
8
+ "case",
9
+ "catch",
10
+ "class",
11
+ "const",
12
+ "continue",
13
+ "default",
14
+ "delete",
15
+ "do",
16
+ "else",
17
+ "export",
18
+ "extends",
19
+ "finally",
20
+ "for",
21
+ "function",
22
+ "if",
23
+ "import",
24
+ "in",
25
+ "instanceof",
26
+ "new",
27
+ "return",
28
+ "super",
29
+ "switch",
30
+ "this",
31
+ "throw",
32
+ "try",
33
+ "typeof",
34
+ "var",
35
+ "void",
36
+ "while",
37
+ "with",
38
+ "yield"
39
+ ]);
40
+ function slugifyIdentifier(label, fallback) {
41
+ const cleaned = label.replace(/[^A-Za-z0-9]+/g, " ").trim();
42
+ if (!cleaned) return fallback;
43
+ const camel = cleaned.split(/\s+/).map((part, i) => i === 0 ? part.charAt(0).toLowerCase() + part.slice(1) : part.charAt(0).toUpperCase() + part.slice(1)).join("");
44
+ const safe = /^[A-Za-z_$]/.test(camel) ? camel : `_${camel}`;
45
+ return RESERVED_IDENTIFIERS.has(safe) ? `_${safe}` : safe;
46
+ }
47
+ function buildKeyPropIdentifierMap(keyProps) {
48
+ const used = new Set(["style"]);
49
+ const map = /* @__PURE__ */ new Map();
50
+ if (!keyProps?.length) return map;
51
+ keyProps.forEach((kp, i) => {
52
+ if (!kp.targets?.length) return;
53
+ const base = slugifyIdentifier(kp.label, `keyProp${i}`);
54
+ let ident = base;
55
+ let suffix = 1;
56
+ while (used.has(ident)) {
57
+ suffix++;
58
+ ident = `${base}${suffix}`;
59
+ }
60
+ used.add(ident);
61
+ map.set(ident, kp);
62
+ });
63
+ return map;
64
+ }
65
+ function findInTree(id, list) {
66
+ for (const c of list) {
67
+ if (c.id === id) return c;
68
+ const children = c.children;
69
+ if (children?.length) {
70
+ const hit = findInTree(id, children);
71
+ if (hit) return hit;
72
+ }
73
+ }
74
+ return null;
75
+ }
76
+ function applyConfigurationInPlace(components, configuration, identMap) {
77
+ if (!configuration) return;
78
+ for (const [ident, value] of Object.entries(configuration)) {
79
+ const kp = identMap.get(ident);
80
+ if (!kp) continue;
81
+ for (const t of kp.targets ?? []) {
82
+ const comp = findInTree(t.component_id, components);
83
+ if (comp?.props && t.prop in comp.props) comp.props[t.prop] = value;
84
+ }
85
+ }
86
+ }
6
87
  async function createPreview(canvas, options) {
7
88
  if (!options.shader && !options.presetId || options.shader && options.presetId) throw new Error("Exactly one of shader (preview token) or presetId must be provided");
8
89
  const apiBase = options.apiBaseUrl || DEFAULT_API_BASE;
9
- const url = options.shader ? `${apiBase}/api/preview/shader/${encodeURIComponent(options.shader)}` : `${apiBase}/api/preview/preset/${encodeURIComponent(options.presetId)}`;
90
+ const versionParam = options.presetId && options.version ? `?version=${encodeURIComponent(options.version)}` : "";
91
+ const url = options.shader ? `${apiBase}/api/preview/shader/${encodeURIComponent(options.shader)}` : `${apiBase}/api/preview/preset/${encodeURIComponent(options.presetId)}${versionParam}`;
10
92
  const response = await fetch(url);
11
93
  if (!response.ok) throw new Error(`Failed to fetch preview: ${response.status} ${response.statusText}`);
12
- const instance = await createShader(canvas, decodePreviewDefinition(await response.text()), {
94
+ const payload = await response.json();
95
+ const item = payload.preset ?? payload.shader;
96
+ if (!item?.definition || typeof item.definition !== "string") throw new Error("Preview response missing encoded definition");
97
+ const definition = decodePreviewDefinition(item.definition);
98
+ const keyProps = Array.isArray(item.key_props) ? item.key_props : null;
99
+ const identMap = buildKeyPropIdentifierMap(keyProps);
100
+ const baselineMap = /* @__PURE__ */ new Map();
101
+ for (const kp of identMap.values()) for (const t of kp.targets ?? []) {
102
+ const comp = findInTree(t.component_id, definition.components);
103
+ if (comp?.props && t.prop in comp.props) baselineMap.set(`${t.component_id}:${t.prop}`, comp.props[t.prop]);
104
+ }
105
+ applyConfigurationInPlace(definition.components, options.configuration, identMap);
106
+ const instance = await createShader(canvas, definition, {
13
107
  isPreview: true,
14
108
  enablePerformanceTracking: true
15
109
  });
16
110
  const { overlay, savedPosition, parentEl } = createWatermarkOverlay(canvas);
17
111
  const originalDestroy = instance.destroy.bind(instance);
18
- instance.destroy = () => {
112
+ const previewInstance = instance;
113
+ previewInstance.destroy = () => {
19
114
  if (parentEl && savedPosition !== void 0) parentEl.style.position = savedPosition;
20
115
  overlay.remove();
21
116
  originalDestroy();
22
117
  };
23
- return instance;
118
+ previewInstance.setConfiguration = (configuration) => {
119
+ if (!keyProps?.length) return;
120
+ for (const [ident, kp] of identMap) {
121
+ const hasNewValue = Object.prototype.hasOwnProperty.call(configuration, ident) && configuration[ident] !== void 0;
122
+ for (const t of kp.targets ?? []) {
123
+ const value = hasNewValue ? configuration[ident] : baselineMap.get(`${t.component_id}:${t.prop}`);
124
+ if (value === void 0) continue;
125
+ instance.update(t.component_id, { [t.prop]: value });
126
+ }
127
+ }
128
+ };
129
+ return previewInstance;
24
130
  }
25
131
  function createWatermarkOverlay(canvas) {
26
132
  const parent = canvas.parentElement;
@@ -48,7 +48,7 @@ async function createShader(canvas, preset, options) {
48
48
  if (isExternalUser()) {
49
49
  const checkRendering = () => {
50
50
  if (renderer.getPerformanceStats().fps > 0) {
51
- telemetryCollector = startTelemetry(renderer, "2.5.114", options?.disableTelemetry || false, false);
51
+ telemetryCollector = startTelemetry(renderer, "2.5.115", options?.disableTelemetry || false, false);
52
52
  if (telemetryCollector) telemetryCollector.start();
53
53
  telemetryStartTimeout = null;
54
54
  } else telemetryStartTimeout = setTimeout(checkRendering, 500);
@@ -40,10 +40,42 @@ export interface ShaderOptions {
40
40
  adapter: GPUAdapter;
41
41
  };
42
42
  }
43
+ export interface KeyPropTarget {
44
+ component_id: string;
45
+ prop: string;
46
+ }
47
+ export interface KeyProp {
48
+ label: string;
49
+ type: 'color' | 'range' | 'logo' | 'image';
50
+ category?: string;
51
+ targets: KeyPropTarget[];
52
+ }
43
53
  export interface PreviewOptions {
44
54
  shader?: string;
45
55
  presetId?: string;
46
56
  apiBaseUrl?: string;
57
+ /**
58
+ * Map of camelCase key_prop identifier → user value, layered on top of the
59
+ * preset's authored defaults. Identifiers are derived from `key_prop.label`
60
+ * via the same slugify rules the Pro Framer exporter uses, so identifiers
61
+ * generated by codegen and identifiers expected here always match.
62
+ *
63
+ * Only applies on the `presetId` path — `shader` token previews don't carry
64
+ * key_props and silently ignore this option.
65
+ */
66
+ configuration?: Record<string, unknown>;
67
+ /**
68
+ * Lock the preview to a specific snapshot of the preset, addressed by
69
+ * content hash. Customized snippets pin a version so subsequent upstream
70
+ * edits don't silently break the configuration. Server falls back to
71
+ * latest with the `X-Shaders-Version-Fallback` header when the requested
72
+ * snapshot is missing. Only meaningful on the `presetId` path.
73
+ */
74
+ version?: string;
75
+ }
76
+ export interface PreviewInstance extends ShaderInstance {
77
+ /** Replace the active configuration. Re-applies values to the live shader without refetching. */
78
+ setConfiguration(configuration: Record<string, unknown>): void;
47
79
  }
48
80
  export interface ShaderInstance {
49
81
  update(componentId: string, props: Record<string, any>): void;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAEjE,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,WAAW,GAAG,MAAM,CAAA;IACjC,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,yBAAyB,CAAC,EAAE,OAAO,CAAA;IACnC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;;kBAKc;IACd,GAAG,CAAC,EAAE;QACJ,MAAM,EAAE,SAAS,CAAA;QACjB,OAAO,EAAE,UAAU,CAAA;KACpB,CAAA;CACF;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAA;IAC7D;;;;OAIG;IACH,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7C,mFAAmF;IACnF,KAAK,IAAI,IAAI,CAAA;IACb,kDAAkD;IAClD,MAAM,IAAI,IAAI,CAAA;IACd,OAAO,IAAI,IAAI,CAAA;CAChB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAEjE,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,WAAW,GAAG,MAAM,CAAA;IACjC,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,yBAAyB,CAAC,EAAE,OAAO,CAAA;IACnC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;;kBAKc;IACd,GAAG,CAAC,EAAE;QACJ,MAAM,EAAE,SAAS,CAAA;QACjB,OAAO,EAAE,UAAU,CAAA;KACpB,CAAA;CACF;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAA;IACpB,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,CAAA;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,aAAa,EAAE,CAAA;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;;;;;OAQG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACvC;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,eAAgB,SAAQ,cAAc;IACrD,iGAAiG;IACjG,gBAAgB,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;CAC/D;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAA;IAC7D;;;;OAIG;IACH,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7C,mFAAmF;IACnF,KAAK,IAAI,IAAI,CAAA;IACb,kDAAkD;IAClD,MAAM,IAAI,IAAI,CAAA;IACd,OAAO,IAAI,IAAI,CAAA;CAChB"}
@@ -19,6 +19,94 @@ function decodePreviewDefinition(encoded, key) {
19
19
  throw new Error("Failed to decode shader definition: invalid data or incorrect key");
20
20
  }
21
21
  }
22
+ var RESERVED_IDENTIFIERS = new Set([
23
+ "break",
24
+ "case",
25
+ "catch",
26
+ "class",
27
+ "const",
28
+ "continue",
29
+ "default",
30
+ "delete",
31
+ "do",
32
+ "else",
33
+ "export",
34
+ "extends",
35
+ "finally",
36
+ "for",
37
+ "function",
38
+ "if",
39
+ "import",
40
+ "in",
41
+ "instanceof",
42
+ "new",
43
+ "return",
44
+ "super",
45
+ "switch",
46
+ "this",
47
+ "throw",
48
+ "try",
49
+ "typeof",
50
+ "var",
51
+ "void",
52
+ "while",
53
+ "with",
54
+ "yield"
55
+ ]);
56
+ function slugifyIdentifier(label, fallback) {
57
+ const cleaned = label.replace(/[^A-Za-z0-9]+/g, " ").trim();
58
+ if (!cleaned) return fallback;
59
+ const camel = cleaned.split(/\s+/).map((part, i) => i === 0 ? part.charAt(0).toLowerCase() + part.slice(1) : part.charAt(0).toUpperCase() + part.slice(1)).join("");
60
+ const safe = /^[A-Za-z_$]/.test(camel) ? camel : `_${camel}`;
61
+ return RESERVED_IDENTIFIERS.has(safe) ? `_${safe}` : safe;
62
+ }
63
+ function buildKeyPropIdentifierMap(keyProps) {
64
+ const used = new Set(["style"]);
65
+ const map = /* @__PURE__ */ new Map();
66
+ if (!keyProps?.length) return map;
67
+ keyProps.forEach((kp, i) => {
68
+ if (!kp.targets?.length) return;
69
+ const base = slugifyIdentifier(kp.label, `keyProp${i}`);
70
+ let ident = base;
71
+ let suffix = 1;
72
+ while (used.has(ident)) {
73
+ suffix++;
74
+ ident = `${base}${suffix}`;
75
+ }
76
+ used.add(ident);
77
+ map.set(ident, kp);
78
+ });
79
+ return map;
80
+ }
81
+ function findInTree(id, list) {
82
+ for (const c of list) {
83
+ if (c.id === id) return c;
84
+ if (c.children?.length) {
85
+ const hit = findInTree(id, c.children);
86
+ if (hit) return hit;
87
+ }
88
+ }
89
+ return null;
90
+ }
91
+ function applyConfiguration(definition, configuration, keyProps) {
92
+ if (!configuration || !keyProps?.length) return definition;
93
+ const entries = Object.entries(configuration);
94
+ if (entries.length === 0) return definition;
95
+ const identMap = buildKeyPropIdentifierMap(keyProps);
96
+ const cloned = JSON.parse(JSON.stringify(definition.components));
97
+ for (const [ident, value] of entries) {
98
+ const kp = identMap.get(ident);
99
+ if (!kp) continue;
100
+ for (const t of kp.targets ?? []) {
101
+ const comp = findInTree(t.component_id, cloned);
102
+ if (comp?.props && t.prop in comp.props) comp.props[t.prop] = value;
103
+ }
104
+ }
105
+ return {
106
+ ...definition,
107
+ components: cloned
108
+ };
109
+ }
22
110
  var componentMap = {
23
111
  AngularBlur: lazy(() => import("./AngularBlur.js")),
24
112
  Ascii: lazy(() => import("./Ascii.js")),
@@ -158,23 +246,31 @@ function RenderComponent({ component }) {
158
246
  children: children?.map((child, index) => /* @__PURE__ */ jsx(RenderComponent, { component: child }, child.id || index))
159
247
  });
160
248
  }
161
- const Preview = ({ shader, presetId, apiBaseUrl = "https://shaders.com", obfuscationKey = DEFAULT_KEY, watermarkText = "Unlock your Shaders Pro license", watermarkLink = "https://shaders.com/dashboard?pricing=true", style, className,...rest }) => {
249
+ const Preview = ({ shader, presetId, apiBaseUrl = "https://shaders.com", obfuscationKey = DEFAULT_KEY, watermarkText = "Unlock your Shaders Pro license", watermarkLink = "https://shaders.com/dashboard?pricing=true", style, className, configuration, version,...rest }) => {
162
250
  const [fetchedDefinition, setFetchedDefinition] = useState(null);
251
+ const [fetchedKeyProps, setFetchedKeyProps] = useState(null);
163
252
  const fetchAndDecode = (url) => {
164
253
  setFetchedDefinition(null);
254
+ setFetchedKeyProps(null);
165
255
  fetch(url).then((res) => {
166
256
  if (!res.ok) throw new Error(`Failed to fetch: ${res.status}`);
167
257
  return res.json();
168
258
  }).then((data) => {
169
259
  const item = data.preset || data.shader;
170
- if (item?.definition && typeof item.definition === "string") setFetchedDefinition(decodePreviewDefinition(item.definition, obfuscationKey));
260
+ if (item?.definition && typeof item.definition === "string") {
261
+ setFetchedDefinition(decodePreviewDefinition(item.definition, obfuscationKey));
262
+ setFetchedKeyProps(Array.isArray(item.key_props) ? item.key_props : null);
263
+ }
171
264
  }).catch((err) => {
172
265
  console.error("[Shaders Preview] Failed to fetch preview:", err);
173
266
  });
174
267
  };
175
268
  useEffect(() => {
176
269
  if (shader) fetchAndDecode(`${apiBaseUrl}/api/preview/shader/${shader}`);
177
- else if (!presetId) setFetchedDefinition(null);
270
+ else if (!presetId) {
271
+ setFetchedDefinition(null);
272
+ setFetchedKeyProps(null);
273
+ }
178
274
  }, [
179
275
  shader,
180
276
  presetId,
@@ -182,18 +278,26 @@ const Preview = ({ shader, presetId, apiBaseUrl = "https://shaders.com", obfusca
182
278
  obfuscationKey
183
279
  ]);
184
280
  useEffect(() => {
185
- if (presetId) fetchAndDecode(`${apiBaseUrl}/api/preview/preset/${presetId}`);
186
- else if (!shader) setFetchedDefinition(null);
281
+ if (presetId) fetchAndDecode(`${apiBaseUrl}/api/preview/preset/${presetId}${version ? `?version=${encodeURIComponent(version)}` : ""}`);
282
+ else if (!shader) {
283
+ setFetchedDefinition(null);
284
+ setFetchedKeyProps(null);
285
+ }
187
286
  }, [
188
287
  presetId,
189
288
  shader,
190
289
  apiBaseUrl,
191
- obfuscationKey
290
+ obfuscationKey,
291
+ version
192
292
  ]);
193
293
  const definition = useMemo(() => {
194
- if (fetchedDefinition) return fetchedDefinition;
195
- return null;
196
- }, [fetchedDefinition]);
294
+ if (!fetchedDefinition) return null;
295
+ return applyConfiguration(fetchedDefinition, configuration, fetchedKeyProps);
296
+ }, [
297
+ fetchedDefinition,
298
+ fetchedKeyProps,
299
+ configuration
300
+ ]);
197
301
  const hasWarnedRef = useRef(false);
198
302
  useEffect(() => {
199
303
  if (!hasWarnedRef.current && definition) {
@@ -89,7 +89,7 @@ const Shader = ({ children, disableTelemetry = false, colorSpace = "p3-linear",
89
89
  return;
90
90
  }
91
91
  if (rendererRef.current.getPerformanceStats().fps > 0) {
92
- telemetryCollectorRef.current = startTelemetry(rendererRef.current, "2.5.114", disableTelemetry, isPreview);
92
+ telemetryCollectorRef.current = startTelemetry(rendererRef.current, "2.5.115", disableTelemetry, isPreview);
93
93
  if (telemetryCollectorRef.current) telemetryCollectorRef.current.start();
94
94
  telemetryStartTimeoutRef.current = null;
95
95
  } else telemetryStartTimeoutRef.current = window.setTimeout(checkRendering, 500);