shaders 2.5.113 → 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.
@@ -157,7 +157,9 @@ var Preview_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ define
157
157
  apiBaseUrl: { default: "https://shaders.com" },
158
158
  obfuscationKey: { default: "shaders-preview-key" },
159
159
  watermarkText: { default: "Unlock your Shaders Pro license" },
160
- watermarkLink: { default: "https://shaders.com/dashboard?pricing=true" }
160
+ watermarkLink: { default: "https://shaders.com/dashboard?pricing=true" },
161
+ configuration: {},
162
+ version: {}
161
163
  },
162
164
  setup(__props) {
163
165
  const componentMap = {
@@ -288,11 +290,100 @@ var Preview_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ define
288
290
  throw new Error("Failed to decode shader definition: invalid data or incorrect key");
289
291
  }
290
292
  }
293
+ const RESERVED_IDENTIFIERS = new Set([
294
+ "break",
295
+ "case",
296
+ "catch",
297
+ "class",
298
+ "const",
299
+ "continue",
300
+ "default",
301
+ "delete",
302
+ "do",
303
+ "else",
304
+ "export",
305
+ "extends",
306
+ "finally",
307
+ "for",
308
+ "function",
309
+ "if",
310
+ "import",
311
+ "in",
312
+ "instanceof",
313
+ "new",
314
+ "return",
315
+ "super",
316
+ "switch",
317
+ "this",
318
+ "throw",
319
+ "try",
320
+ "typeof",
321
+ "var",
322
+ "void",
323
+ "while",
324
+ "with",
325
+ "yield"
326
+ ]);
327
+ function slugifyIdentifier(label, fallback) {
328
+ const cleaned = label.replace(/[^A-Za-z0-9]+/g, " ").trim();
329
+ if (!cleaned) return fallback;
330
+ 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("");
331
+ const safe = /^[A-Za-z_$]/.test(camel) ? camel : `_${camel}`;
332
+ return RESERVED_IDENTIFIERS.has(safe) ? `_${safe}` : safe;
333
+ }
334
+ function buildKeyPropIdentifierMap(keyProps) {
335
+ const used = new Set(["style"]);
336
+ const map = /* @__PURE__ */ new Map();
337
+ if (!keyProps?.length) return map;
338
+ keyProps.forEach((kp, i) => {
339
+ if (!kp.targets?.length) return;
340
+ const base = slugifyIdentifier(kp.label, `keyProp${i}`);
341
+ let ident = base;
342
+ let suffix = 1;
343
+ while (used.has(ident)) {
344
+ suffix++;
345
+ ident = `${base}${suffix}`;
346
+ }
347
+ used.add(ident);
348
+ map.set(ident, kp);
349
+ });
350
+ return map;
351
+ }
352
+ function findInTree(id, list) {
353
+ for (const c of list) {
354
+ if (c.id === id) return c;
355
+ if (c.children?.length) {
356
+ const hit = findInTree(id, c.children);
357
+ if (hit) return hit;
358
+ }
359
+ }
360
+ return null;
361
+ }
362
+ function applyConfiguration(definition, configuration, keyProps) {
363
+ if (!configuration || !keyProps?.length) return definition;
364
+ const entries = Object.entries(configuration);
365
+ if (entries.length === 0) return definition;
366
+ const identMap = buildKeyPropIdentifierMap(keyProps);
367
+ const cloned = JSON.parse(JSON.stringify(definition.components));
368
+ for (const [ident, value] of entries) {
369
+ const kp = identMap.get(ident);
370
+ if (!kp) continue;
371
+ for (const t of kp.targets ?? []) {
372
+ const comp = findInTree(t.component_id, cloned);
373
+ if (comp?.props && t.prop in comp.props) comp.props[t.prop] = value;
374
+ }
375
+ }
376
+ return {
377
+ ...definition,
378
+ components: cloned
379
+ };
380
+ }
291
381
  const props = __props;
292
382
  const fetchedDefinition = ref(null);
383
+ const fetchedKeyProps = ref(null);
293
384
  const resolvedDefinition = computed(() => {
294
- if (fetchedDefinition.value) return fetchedDefinition.value;
295
- return null;
385
+ if (!fetchedDefinition.value) return null;
386
+ return applyConfiguration(fetchedDefinition.value, props.configuration, fetchedKeyProps.value);
296
387
  });
297
388
  async function fetchAndDecode(url) {
298
389
  try {
@@ -300,7 +391,10 @@ var Preview_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ define
300
391
  if (!response.ok) throw new Error(`Failed to fetch: ${response.status}`);
301
392
  const data = await response.json();
302
393
  const item = data.preset || data.shader;
303
- if (item?.definition && typeof item.definition === "string") fetchedDefinition.value = decodePreviewDefinition(item.definition, props.obfuscationKey);
394
+ if (item?.definition && typeof item.definition === "string") {
395
+ fetchedDefinition.value = decodePreviewDefinition(item.definition, props.obfuscationKey);
396
+ fetchedKeyProps.value = Array.isArray(item.key_props) ? item.key_props : null;
397
+ }
304
398
  } catch (e) {
305
399
  console.error("[Shaders Preview] Failed to fetch preview:", e);
306
400
  }
@@ -308,14 +402,23 @@ var Preview_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ define
308
402
  watch(() => props.shader, (token) => {
309
403
  if (token) {
310
404
  fetchedDefinition.value = null;
405
+ fetchedKeyProps.value = null;
311
406
  fetchAndDecode(`${props.apiBaseUrl}/api/preview/shader/${token}`);
312
- } else if (!props.presetId) fetchedDefinition.value = null;
407
+ } else if (!props.presetId) {
408
+ fetchedDefinition.value = null;
409
+ fetchedKeyProps.value = null;
410
+ }
313
411
  }, { immediate: true });
314
- watch(() => props.presetId, (id) => {
412
+ watch(() => [props.presetId, props.version], ([id, version]) => {
315
413
  if (id) {
316
414
  fetchedDefinition.value = null;
317
- fetchAndDecode(`${props.apiBaseUrl}/api/preview/preset/${id}`);
318
- } else if (!props.shader) fetchedDefinition.value = null;
415
+ fetchedKeyProps.value = null;
416
+ const versionParam = version ? `?version=${encodeURIComponent(version)}` : "";
417
+ fetchAndDecode(`${props.apiBaseUrl}/api/preview/preset/${id}${versionParam}`);
418
+ } else if (!props.shader) {
419
+ fetchedDefinition.value = null;
420
+ fetchedKeyProps.value = null;
421
+ }
319
422
  }, { immediate: true });
320
423
  onMounted(() => {
321
424
  console.warn("[Shaders] Preview component is intended for use with a Shaders license. Visit https://shaders.com for more information.");
@@ -60,7 +60,7 @@ var Shader_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
60
60
  const startTelemetryWhenReady = () => {
61
61
  const checkRendering = () => {
62
62
  if (rendererInstance.value.getPerformanceStats().fps > 0) {
63
- telemetryCollector = startTelemetry(rendererInstance.value, "2.5.113", props.disableTelemetry, props.isPreview);
63
+ telemetryCollector = startTelemetry(rendererInstance.value, "2.5.115", props.disableTelemetry, props.isPreview);
64
64
  if (telemetryCollector) telemetryCollector.start();
65
65
  telemetryStartTimeout = null;
66
66
  } else telemetryStartTimeout = setTimeout(checkRendering, 500);
@@ -112,52 +112,80 @@ var Shader_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
112
112
  rendererResetSignal.value++;
113
113
  }
114
114
  });
115
- const captureScreenshot = async (maxWidth = 1200) => {
116
- if (!canvasRef.value) throw new Error("Canvas not available");
115
+ const renderForCapture = async () => {
117
116
  try {
118
117
  await rendererInstance.value.renderAndWait();
119
118
  } catch (error) {
120
- console.warn("Failed to force render before screenshot:", error);
119
+ console.warn("[Shaders] Failed to force render before capture:", error);
120
+ throw error;
121
121
  }
122
- return new Promise((resolve, reject) => {
123
- const sourceCanvas = canvasRef.value;
124
- const sourceWidth = sourceCanvas.width;
125
- const sourceHeight = sourceCanvas.height;
126
- let targetWidth = sourceWidth;
127
- let targetHeight = sourceHeight;
128
- if (sourceWidth > maxWidth) {
129
- targetWidth = maxWidth;
130
- targetHeight = Math.round(sourceHeight / sourceWidth * maxWidth);
131
- }
132
- const dataUrl = sourceCanvas.toDataURL("image/png");
133
- const img = new Image();
134
- img.onload = () => {
135
- const tempCanvas = document.createElement("canvas");
136
- tempCanvas.width = targetWidth;
137
- tempCanvas.height = targetHeight;
138
- const ctx = tempCanvas.getContext("2d");
139
- if (!ctx) {
140
- reject(/* @__PURE__ */ new Error("Failed to get canvas context"));
141
- return;
142
- }
143
- ctx.drawImage(img, 0, 0, targetWidth, targetHeight);
144
- tempCanvas.toBlob((blob) => {
145
- if (blob) resolve(blob);
146
- else reject(/* @__PURE__ */ new Error("Failed to capture screenshot"));
147
- }, "image/jpeg", .85);
148
- };
149
- img.onerror = () => {
150
- reject(/* @__PURE__ */ new Error("Failed to load canvas image"));
151
- };
152
- img.src = dataUrl;
153
- });
122
+ };
123
+ const canvasToBlob = (source, targetWidth, targetHeight, mimeType, quality) => new Promise((resolve, reject) => {
124
+ const tempCanvas = document.createElement("canvas");
125
+ tempCanvas.width = targetWidth;
126
+ tempCanvas.height = targetHeight;
127
+ const ctx = tempCanvas.getContext("2d");
128
+ if (!ctx) {
129
+ reject(/* @__PURE__ */ new Error("Failed to get canvas context"));
130
+ return;
131
+ }
132
+ ctx.imageSmoothingEnabled = true;
133
+ ctx.imageSmoothingQuality = "high";
134
+ ctx.drawImage(source, 0, 0, targetWidth, targetHeight);
135
+ tempCanvas.toBlob((blob) => {
136
+ if (blob) resolve(blob);
137
+ else reject(/* @__PURE__ */ new Error("Failed to encode image"));
138
+ }, mimeType, quality);
139
+ });
140
+ const captureImage = async (options = {}) => {
141
+ if (!canvasRef.value) throw new Error("Canvas not available");
142
+ await renderForCapture();
143
+ const source = canvasRef.value;
144
+ const format = options.format ?? "png";
145
+ const scale = Math.max(.1, options.scale ?? 1);
146
+ return canvasToBlob(source, Math.round(source.width * scale), Math.round(source.height * scale), format === "png" ? "image/png" : format === "webp" ? "image/webp" : "image/jpeg", format === "png" ? void 0 : options.quality ?? .95);
147
+ };
148
+ const captureScreenshot = async (maxWidth = 1200) => {
149
+ if (!canvasRef.value) throw new Error("Canvas not available");
150
+ await renderForCapture();
151
+ const source = canvasRef.value;
152
+ const sourceWidth = source.width;
153
+ const sourceHeight = source.height;
154
+ let targetWidth = sourceWidth;
155
+ let targetHeight = sourceHeight;
156
+ if (sourceWidth > maxWidth) {
157
+ targetWidth = maxWidth;
158
+ targetHeight = Math.round(sourceHeight / sourceWidth * maxWidth);
159
+ }
160
+ return canvasToBlob(source, targetWidth, targetHeight, "image/jpeg", .85);
154
161
  };
155
162
  const getPerformanceStats = () => {
156
163
  return rendererInstance.value.getPerformanceStats();
157
164
  };
165
+ const beginRecordingResolution = async (pixelRatio) => {
166
+ const internal = rendererInstance.value.getInternalRenderer();
167
+ if (!internal || !canvasRef.value) return async () => {};
168
+ const previousRatio = typeof internal.getPixelRatio === "function" ? internal.getPixelRatio() : Math.min(window.devicePixelRatio, 2);
169
+ const cssWidth = canvasRef.value.clientWidth;
170
+ const cssHeight = canvasRef.value.clientHeight;
171
+ const applyRatio = async (ratio) => {
172
+ internal.setPixelRatio(ratio);
173
+ if (typeof internal.setSize === "function") internal.setSize(cssWidth, cssHeight, false);
174
+ await renderForCapture();
175
+ };
176
+ const previousForce = rendererInstance.value.setForceFullFrameRate?.(true) ?? false;
177
+ await applyRatio(pixelRatio);
178
+ return async () => {
179
+ await applyRatio(previousRatio);
180
+ rendererInstance.value.setForceFullFrameRate?.(previousForce);
181
+ };
182
+ };
158
183
  __expose({
184
+ captureImage,
159
185
  captureScreenshot,
160
- getPerformanceStats
186
+ getPerformanceStats,
187
+ beginRecordingResolution,
188
+ getCanvas: () => canvasRef.value
161
189
  });
162
190
  onBeforeUnmount(() => {
163
191
  if (telemetryCollector) {
@@ -4,6 +4,13 @@ interface Props {
4
4
  colorSpace?: 'p3-linear' | 'srgb';
5
5
  isPreview?: boolean;
6
6
  }
7
+ type CaptureFormat = 'png' | 'jpeg' | 'webp';
8
+ interface CaptureImageOptions {
9
+ format?: CaptureFormat;
10
+ scale?: number;
11
+ quality?: number;
12
+ maxWidth?: number;
13
+ }
7
14
  declare function __VLS_template(): {
8
15
  default?(_: {}): any;
9
16
  };
@@ -13,8 +20,11 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
13
20
  colorSpace: string;
14
21
  isPreview: boolean;
15
22
  }>>, {
23
+ captureImage: (options?: CaptureImageOptions) => Promise<Blob>;
16
24
  captureScreenshot: (maxWidth?: number) => Promise<Blob>;
17
25
  getPerformanceStats: () => import('../../core').PerformanceStats;
26
+ beginRecordingResolution: (pixelRatio: number) => Promise<() => Promise<void>>;
27
+ getCanvas: () => HTMLCanvasElement | null;
18
28
  }, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
19
29
  ready: () => void;
20
30
  }, string, import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<Props>, {
@@ -1 +1 @@
1
- {"version":3,"file":"Shader.vue.d.ts","sourceRoot":"","sources":["../../src/engine/Shader.vue"],"names":[],"mappings":"AAYA,UAAU,KAAK;IACb,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,yBAAyB,CAAC,EAAE,OAAO,CAAA;IACnC,UAAU,CAAC,EAAE,WAAW,GAAG,MAAM,CAAA;IACjC,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAgUD,iBAAS,cAAc;qBAkDO,GAAG;EAKhC;AAWD,QAAA,MAAM,eAAe;;;;;;8CAlL8B,OAAO,CAAC,IAAI,CAAC;;;;;;;;;;;;gBAlNjD,WAAW,GAAG,MAAM;sBAFd,OAAO;+BACE,OAAO;eAEvB,OAAO;4EA2YnB,CAAC;wBACkB,uBAAuB,CAAC,OAAO,eAAe,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AAAvG,wBAAwG;AACxG,KAAK,sBAAsB,CAAC,CAAC,IAAI,CAAC,SAAS,SAAS,GAAG,KAAK,GAAG,CAAC,CAAC;AACjE,KAAK,6BAA6B,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,SAAS,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;QAAE,IAAI,EAAE,OAAO,KAAK,EAAE,QAAQ,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,OAAO,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAA;KAAE;CAAE,CAAC;AAC9M,KAAK,kBAAkB,CAAC,CAAC,EAAE,CAAC,IAAI;KAE1B,CAAC,IAAI,MAAM,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,MAAM,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG;QACxE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;KACb,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CACT,CAAC;AACN,KAAK,cAAc,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,GAAG,EAAE,CAAC;AACxD,KAAK,uBAAuB,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAAE,QAAO;QAClD,MAAM,EAAE,CAAC,CAAC;KACT,CAAA;CAAE,CAAC"}
1
+ {"version":3,"file":"Shader.vue.d.ts","sourceRoot":"","sources":["../../src/engine/Shader.vue"],"names":[],"mappings":"AAYA,UAAU,KAAK;IACb,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,yBAAyB,CAAC,EAAE,OAAO,CAAA;IACnC,UAAU,CAAC,EAAE,WAAW,GAAG,MAAM,CAAA;IACjC,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAgND,KAAK,aAAa,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAA;AAE5C,UAAU,mBAAmB;IAC3B,MAAM,CAAC,EAAE,aAAa,CAAA;IACtB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAsLD,iBAAS,cAAc;qBAkDO,GAAG;EAKhC;AAWD,QAAA,MAAM,eAAe;;;;;;6BAzMgB,mBAAmB,KAAQ,OAAO,CAAC,IAAI,CAAC;8CAsB1B,OAAO,CAAC,IAAI,CAAC;;2CAkCZ,MAAM,KAAG,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;;;;;;;;;;;;gBAhU1E,WAAW,GAAG,MAAM;sBAFd,OAAO;+BACE,OAAO;eAEvB,OAAO;4EAwdnB,CAAC;wBACkB,uBAAuB,CAAC,OAAO,eAAe,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AAAvG,wBAAwG;AACxG,KAAK,sBAAsB,CAAC,CAAC,IAAI,CAAC,SAAS,SAAS,GAAG,KAAK,GAAG,CAAC,CAAC;AACjE,KAAK,6BAA6B,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,SAAS,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;QAAE,IAAI,EAAE,OAAO,KAAK,EAAE,QAAQ,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,OAAO,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAA;KAAE;CAAE,CAAC;AAC9M,KAAK,kBAAkB,CAAC,CAAC,EAAE,CAAC,IAAI;KAE1B,CAAC,IAAI,MAAM,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,MAAM,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG;QACxE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;KACb,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CACT,CAAC;AACN,KAAK,cAAc,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,GAAG,EAAE,CAAC;AACxD,KAAK,uBAAuB,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAAE,QAAO;QAClD,MAAM,EAAE,CAAC,CAAC;KACT,CAAA;CAAE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shaders",
3
- "version": "2.5.113",
3
+ "version": "2.5.115",
4
4
  "description": "Shader magic for modern frontends",
5
5
  "author": "Shader Effects Inc.",
6
6
  "homepage": "https://shaders.com/",