@5even7/dlc-ui 0.2.11 → 0.2.13

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/dist/vue2.cjs CHANGED
@@ -187,9 +187,9 @@ function _unsupportedIterableToArray(r, a) {
187
187
  }
188
188
  }
189
189
 
190
- /**
191
- * Tiny event emitter. Accepts any event name so the API stays open for
192
- * future events (hover, click, custom) without breaking changes.
190
+ /**
191
+ * Tiny event emitter. Accepts any event name so the API stays open for
192
+ * future events (hover, click, custom) without breaking changes.
193
193
  */
194
194
  function createEmitter() {
195
195
  // Plain object storage (no Map/Set) so the legacy build has no API
@@ -239,9 +239,9 @@ function createEmitter() {
239
239
 
240
240
  var UNIT_PATTERN = /^[\d.]+(?:px|%|vw|vh|vmin|vmax|em|rem)$/;
241
241
 
242
- /**
243
- * Normalize a size option to a CSS length string.
244
- * Accepts numbers (treated as px) or strings with px/%, vw/vh/vmin/vmax, em/rem.
242
+ /**
243
+ * Normalize a size option to a CSS length string.
244
+ * Accepts numbers (treated as px) or strings with px/%, vw/vh/vmin/vmax, em/rem.
245
245
  */
246
246
  function parseSize(value) {
247
247
  if (typeof value === 'number') {
@@ -280,11 +280,17 @@ function dprCapFor(quality) {
280
280
  var tier = QUALITY_TIERS[quality] || QUALITY_TIERS.medium;
281
281
  return tier.dpr;
282
282
  }
283
+ function effectiveDprCap(quality) {
284
+ var renderScale = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
285
+ var scale = Number(renderScale);
286
+ var normalizedScale = Number.isFinite(scale) ? Math.min(1, Math.max(0.25, scale)) : 1;
287
+ return Math.max(0.5, dprCapFor(quality) * normalizedScale);
288
+ }
283
289
 
284
- /**
285
- * Merge defaults < preset < user. Unknown user keys are preserved so the
286
- * component API can grow (new props, cssVars, callbacks) without a breaking
287
- * change.
290
+ /**
291
+ * Merge defaults < preset < user. Unknown user keys are preserved so the
292
+ * component API can grow (new props, cssVars, callbacks) without a breaking
293
+ * change.
288
294
  */
289
295
  function normalizeOptions(defaults, preset, user) {
290
296
  // undefined means "not provided" (e.g. Vue $props with unset props):
@@ -302,9 +308,9 @@ function normalizeOptions(defaults, preset, user) {
302
308
  return _objectSpread2(_objectSpread2(_objectSpread2({}, defaults), presetOptions), userOptions);
303
309
  }
304
310
 
305
- /**
306
- * 公共色板:NC-01~NC-06 的四色组(底色 / 主色 / 辅色 / 高光色)。
307
- * Capsule 预置与 dlc-color 等组件共用,新增色板只改这里。
311
+ /**
312
+ * 公共色板:NC-01~NC-06 的四色组(底色 / 主色 / 辅色 / 高光色)。
313
+ * Capsule 预置与 dlc-color 等组件共用,新增色板只改这里。
308
314
  */
309
315
  var PALETTES$1 = {
310
316
  original: ['#FFF3EA', '#F5B27A', '#F67BC6', '#A978E8'],
@@ -315,9 +321,9 @@ var PALETTES$1 = {
315
321
  plus: ['#FFF0E6', '#F6C26B', '#F98A64', '#E86D74']
316
322
  };
317
323
 
318
- /**
319
- * Capsule 预置:仅星云材质 NC-01~NC-06(NC-07~09 aurora 已移除)。
320
- * 颜色引用公共色板,seed/speed 决定形态与流速。
324
+ /**
325
+ * Capsule 预置:仅星云材质 NC-01~NC-06(NC-07~09 aurora 已移除)。
326
+ * 颜色引用公共色板,seed/speed 决定形态与流速。
321
327
  */
322
328
  var CAPSULE_PRESETS = [{
323
329
  id: 'original',
@@ -405,6 +411,15 @@ var PROGRESS_PRESETS = [{
405
411
  initialProgress: 30,
406
412
  edgeStyle: 'tide',
407
413
  colors: ['#0A2239', '#2E9BFF', '#7FE3FF', '#EAF9FF']
414
+ }, {
415
+ id: 'botanic-lab',
416
+ code: 'NC-14',
417
+ name: '森息',
418
+ subtitle: 'MOSS CULTURE / ROOTING',
419
+ group: 'progress',
420
+ initialProgress: 46,
421
+ edgeStyle: 'flow',
422
+ colors: ['#102A23', '#287A58', '#9BD65B', '#F2FFC4']
408
423
  }];
409
424
 
410
425
  [].concat(_toConsumableArray(CAPSULE_PRESETS), _toConsumableArray(PROGRESS_PRESETS));
@@ -435,6 +450,11 @@ var DEFAULTS = {
435
450
  height: 160,
436
451
  quality: 'auto',
437
452
  renderer: 'auto',
453
+ renderScale: 1,
454
+ powerPreference: 'high-performance',
455
+ fps: 60,
456
+ paused: false,
457
+ static: false,
438
458
  respectReducedMotion: true,
439
459
  mouseColor: true,
440
460
  textRatio: 39
@@ -444,13 +464,22 @@ var DEFAULTS = {
444
464
  height: 104,
445
465
  min: 0,
446
466
  max: 100,
467
+ step: 'any',
447
468
  draggable: true,
469
+ keyboard: true,
448
470
  disabled: false,
449
471
  readonly: false,
472
+ direction: 'ltr',
473
+ precision: 0,
450
474
  valueSuffix: '%',
451
475
  edgeStyle: 'flow',
452
476
  quality: 'auto',
453
477
  renderer: 'auto',
478
+ renderScale: 1,
479
+ powerPreference: 'high-performance',
480
+ fps: 60,
481
+ paused: false,
482
+ static: false,
454
483
  textRatio: 54,
455
484
  showValue: true,
456
485
  respectReducedMotion: true
@@ -735,7 +764,7 @@ var CosmicRenderer = /*#__PURE__*/function () {
735
764
  alpha: false,
736
765
  antialias: false,
737
766
  depth: false,
738
- powerPreference: 'high-performance',
767
+ powerPreference: this.options.powerPreference || 'high-performance',
739
768
  preserveDrawingBuffer: false
740
769
  });
741
770
  if (!this.gl) throw new Error('WebGL2 is not available');
@@ -746,16 +775,19 @@ var CosmicRenderer = /*#__PURE__*/function () {
746
775
  this.motion = 0;
747
776
  this.motionTarget = 0;
748
777
  this.timeOffset = preset.seed * 0.73;
778
+ this.colors = preset.colors.map(hexToRgb01$1);
749
779
  this.visible = true;
750
780
  this.disposed = false;
751
781
  _assertClassBrand(_CosmicRenderer_brand, this, _setupGeometry).call(this);
752
782
  _assertClassBrand(_CosmicRenderer_brand, this, _bindEvents).call(this);
783
+ _assertClassBrand(_CosmicRenderer_brand, this, _bindContextEvents).call(this);
753
784
  this.resize();
754
785
  }
755
786
  return _createClass(CosmicRenderer, [{
756
787
  key: "setPreset",
757
788
  value: function setPreset(preset) {
758
789
  this.preset = _objectSpread2({}, preset);
790
+ this.colors = preset.colors.map(hexToRgb01$1);
759
791
  this.timeOffset = preset.seed * 0.73;
760
792
  }
761
793
  }, {
@@ -800,15 +832,14 @@ var CosmicRenderer = /*#__PURE__*/function () {
800
832
  if (this.canvas.width !== width || this.canvas.height !== height) {
801
833
  this.canvas.width = width;
802
834
  this.canvas.height = height;
803
- this.gl.viewport(0, 0, width, height);
804
835
  }
836
+ this.gl.viewport(0, 0, width, height);
805
837
  }
806
838
  }, {
807
839
  key: "draw",
808
840
  value: function draw(elapsedSeconds) {
809
841
  var paused = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
810
842
  if (this.disposed || !this.visible) return;
811
- this.resize();
812
843
  var gl = this.gl;
813
844
  this.pointer[0] += (this.pointerTarget[0] - this.pointer[0]) * 0.08;
814
845
  this.pointer[1] += (this.pointerTarget[1] - this.pointer[1]) * 0.08;
@@ -817,16 +848,15 @@ var CosmicRenderer = /*#__PURE__*/function () {
817
848
  gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
818
849
  gl.enableVertexAttribArray(this.locations.position);
819
850
  gl.vertexAttribPointer(this.locations.position, 2, gl.FLOAT, false, 0, 0);
820
- var colors = this.preset.colors.map(hexToRgb01$1);
821
851
  gl.uniform2f(this.locations.resolution, this.canvas.width, this.canvas.height);
822
852
  gl.uniform1f(this.locations.time, this.timeOffset + (paused ? 0 : elapsedSeconds * this.preset.speed));
823
853
  gl.uniform1f(this.locations.seed, this.preset.seed);
824
854
  gl.uniform1f(this.locations.motion, this.motion);
825
855
  gl.uniform2f(this.locations.pointer, this.pointer[0], this.pointer[1]);
826
- gl.uniform3fv(this.locations.colorA, colors[0]);
827
- gl.uniform3fv(this.locations.colorB, colors[1]);
828
- gl.uniform3fv(this.locations.colorC, colors[2]);
829
- gl.uniform3fv(this.locations.colorD, colors[3]);
856
+ gl.uniform3fv(this.locations.colorA, this.colors[0]);
857
+ gl.uniform3fv(this.locations.colorB, this.colors[1]);
858
+ gl.uniform3fv(this.locations.colorC, this.colors[2]);
859
+ gl.uniform3fv(this.locations.colorD, this.colors[3]);
830
860
  gl.drawArrays(gl.TRIANGLES, 0, 3);
831
861
  }
832
862
  }, {
@@ -837,6 +867,8 @@ var CosmicRenderer = /*#__PURE__*/function () {
837
867
  target.removeEventListener('pointermove', this.onPointerMove);
838
868
  target.removeEventListener('pointerdown', this.onPointerMove);
839
869
  target.removeEventListener('pointerleave', this.onPointerLeave);
870
+ this.canvas.removeEventListener('webglcontextlost', this.onContextLost, false);
871
+ this.canvas.removeEventListener('webglcontextrestored', this.onContextRestored, false);
840
872
  this.gl.deleteBuffer(this.buffer);
841
873
  this.gl.deleteProgram(this.program);
842
874
  var lose = this.gl.getExtension('WEBGL_lose_context');
@@ -893,6 +925,26 @@ function _bindEvents() {
893
925
  passive: true
894
926
  });
895
927
  }
928
+ function _bindContextEvents() {
929
+ var _this3 = this;
930
+ this.onContextLost = function (event) {
931
+ event.preventDefault();
932
+ if (_this3.disposed) return;
933
+ _this3.visible = false;
934
+ if (typeof _this3.options.onContextLost === 'function') _this3.options.onContextLost(event);
935
+ };
936
+ this.onContextRestored = function () {
937
+ if (_this3.disposed) return;
938
+ _this3.program = createProgram$1(_this3.gl);
939
+ _this3.locations = _assertClassBrand(_CosmicRenderer_brand, _this3, _getLocations).call(_this3);
940
+ _assertClassBrand(_CosmicRenderer_brand, _this3, _setupGeometry).call(_this3);
941
+ _this3.visible = true;
942
+ _this3.resize();
943
+ if (typeof _this3.options.onContextRestored === 'function') _this3.options.onContextRestored();
944
+ };
945
+ this.canvas.addEventListener('webglcontextlost', this.onContextLost, false);
946
+ this.canvas.addEventListener('webglcontextrestored', this.onContextRestored, false);
947
+ }
896
948
 
897
949
  function rgb(color) {
898
950
  var alpha = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
@@ -907,18 +959,20 @@ function rgb(color) {
907
959
  }
908
960
  var FallbackRenderer = /*#__PURE__*/function () {
909
961
  function FallbackRenderer(canvas, preset) {
962
+ var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
910
963
  _classCallCheck(this, FallbackRenderer);
911
964
  this.canvas = canvas;
912
965
  this.preset = preset;
913
966
  this.context = canvas.getContext('2d');
914
967
  this.visible = true;
915
968
  this.timePhase = 0;
969
+ this.dprCap = options.dprCap || 1.5;
916
970
  }
917
971
  return _createClass(FallbackRenderer, [{
918
972
  key: "resize",
919
973
  value: function resize() {
920
974
  var rect = this.canvas.getBoundingClientRect();
921
- var dpr = Math.min(window.devicePixelRatio || 1, 1.5);
975
+ var dpr = Math.min(window.devicePixelRatio || 1, this.dprCap);
922
976
  var width = Math.max(2, Math.round(rect.width * dpr));
923
977
  var height = Math.max(2, Math.round(rect.height * dpr));
924
978
  if (this.canvas.width !== width || this.canvas.height !== height) {
@@ -959,7 +1013,6 @@ var FallbackRenderer = /*#__PURE__*/function () {
959
1013
  key: "draw",
960
1014
  value: function draw(time) {
961
1015
  if (!this.visible) return;
962
- this.resize();
963
1016
  this.drawNebula(time);
964
1017
  }
965
1018
  }, {
@@ -967,6 +1020,12 @@ var FallbackRenderer = /*#__PURE__*/function () {
967
1020
  value: function setPreset(preset) {
968
1021
  this.preset = preset;
969
1022
  }
1023
+ }, {
1024
+ key: "setDprCap",
1025
+ value: function setDprCap(cap) {
1026
+ this.dprCap = cap;
1027
+ this.resize();
1028
+ }
970
1029
  }, {
971
1030
  key: "randomize",
972
1031
  value: function randomize() {
@@ -984,10 +1043,10 @@ var FallbackRenderer = /*#__PURE__*/function () {
984
1043
  }]);
985
1044
  }();
986
1045
 
987
- /**
988
- * Document-level shared rAF scheduler. Every component instance subscribes
989
- * its own frame callback; the whole page runs ONE animation loop (like the
990
- * original demo), which avoids jank from many competing rAF loops.
1046
+ /**
1047
+ * Document-level shared rAF scheduler. Every component instance subscribes
1048
+ * its own frame callback; the whole page runs ONE animation loop (like the
1049
+ * original demo), which avoids jank from many competing rAF loops.
991
1050
  */
992
1051
  var subscribers = [];
993
1052
  var running = false;
@@ -995,11 +1054,7 @@ var rafId = 0;
995
1054
  var last = 0;
996
1055
  function tick(now) {
997
1056
  if (!running) return;
998
- var delta = last ? Math.min((now - last) / 1000, 0.05) : 0;
999
- last = now;
1000
- // Schedule the next frame BEFORE running callbacks so one throwing
1001
- // subscriber can never kill the whole animation loop.
1002
- rafId = requestAnimationFrame(tick);
1057
+ var activeItems = [];
1003
1058
  {
1004
1059
  var _iterator = _createForOfIteratorHelper(subscribers.slice()),
1005
1060
  _step;
@@ -1007,10 +1062,8 @@ function tick(now) {
1007
1062
  for (_iterator.s(); !(_step = _iterator.n()).done;) {
1008
1063
  var item = _step.value;
1009
1064
  try {
1010
- if (!item.isPaused()) item.onFrame(delta, now);
1011
- } catch (error) {
1012
- console.warn('[dlc-ui] frame error:', error);
1013
- }
1065
+ if (!item.isPaused()) activeItems.push(item);
1066
+ } catch (_unused) {}
1014
1067
  }
1015
1068
  } catch (err) {
1016
1069
  _iterator.e(err);
@@ -1018,6 +1071,25 @@ function tick(now) {
1018
1071
  _iterator.f();
1019
1072
  }
1020
1073
  }
1074
+ if (activeItems.length === 0) {
1075
+ running = false;
1076
+ rafId = 0;
1077
+ last = 0;
1078
+ return;
1079
+ }
1080
+ var delta = last ? Math.min((now - last) / 1000, 0.05) : 0;
1081
+ last = now;
1082
+ // Schedule the next frame BEFORE running callbacks so one throwing
1083
+ // subscriber can never kill the whole animation loop.
1084
+ rafId = requestAnimationFrame(tick);
1085
+ for (var _i = 0, _activeItems = activeItems; _i < _activeItems.length; _i++) {
1086
+ var _item = _activeItems[_i];
1087
+ try {
1088
+ _item.onFrame(delta, now);
1089
+ } catch (error) {
1090
+ console.warn('[dlc-ui] frame error:', error);
1091
+ }
1092
+ }
1021
1093
  if (subscribers.length === 0) {
1022
1094
  cancelAnimationFrame(rafId);
1023
1095
  running = false;
@@ -1030,6 +1102,9 @@ function start() {
1030
1102
  last = 0;
1031
1103
  rafId = requestAnimationFrame(tick);
1032
1104
  }
1105
+ function wakeScheduler() {
1106
+ start();
1107
+ }
1033
1108
  function subscribeScheduler(onFrame, isPaused) {
1034
1109
  var item = {
1035
1110
  onFrame: onFrame,
@@ -1048,11 +1123,12 @@ function subscribeScheduler(onFrame, isPaused) {
1048
1123
  };
1049
1124
  }
1050
1125
 
1051
- /**
1052
- * Gates drawing on "element intersects viewport AND the page tab is visible".
1053
- * Falls back to always-visible when IntersectionObserver is unavailable.
1126
+ /**
1127
+ * Gates drawing on "element intersects viewport AND the page tab is visible".
1128
+ * Falls back to always-visible when IntersectionObserver is unavailable.
1054
1129
  */
1055
1130
  function createVisibilityGuard(element) {
1131
+ var onChange = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
1056
1132
  var intersecting = true;
1057
1133
  var pageVisible = typeof document === 'undefined' || !document.hidden;
1058
1134
  var disposed = false;
@@ -1062,6 +1138,7 @@ function createVisibilityGuard(element) {
1062
1138
  intersecting = entries.some(function (entry) {
1063
1139
  return entry.isIntersecting;
1064
1140
  });
1141
+ if (typeof onChange === 'function') onChange();
1065
1142
  }, {
1066
1143
  rootMargin: '180px'
1067
1144
  });
@@ -1069,6 +1146,7 @@ function createVisibilityGuard(element) {
1069
1146
  }
1070
1147
  var onVisibilityChange = function onVisibilityChange() {
1071
1148
  pageVisible = typeof document !== 'undefined' && !document.hidden;
1149
+ if (typeof onChange === 'function') onChange();
1072
1150
  };
1073
1151
  if (typeof document !== 'undefined') {
1074
1152
  document.addEventListener('visibilitychange', onVisibilityChange);
@@ -1104,18 +1182,69 @@ function nextTick(fn) {
1104
1182
  }
1105
1183
  }
1106
1184
 
1107
- function prefersReducedMotion$2() {
1108
- return typeof matchMedia !== 'undefined' && matchMedia('(prefers-reduced-motion: reduce)').matches;
1185
+ function normalizeFps(value) {
1186
+ var fallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 60;
1187
+ var fps = Number(value);
1188
+ if (!Number.isFinite(fps)) return fallback;
1189
+ return Math.min(60, Math.max(1, fps));
1190
+ }
1191
+ function createFrameGate() {
1192
+ var initialFps = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 60;
1193
+ var fps = normalizeFps(initialFps);
1194
+ var elapsed = 0;
1195
+ return {
1196
+ shouldDraw: function shouldDraw(delta) {
1197
+ elapsed += delta;
1198
+ var interval = 1 / fps;
1199
+ if (elapsed + 0.0001 < interval) return false;
1200
+ elapsed %= interval;
1201
+ return true;
1202
+ },
1203
+ setFps: function setFps(value) {
1204
+ fps = normalizeFps(value, fps);
1205
+ elapsed = 0;
1206
+ return fps;
1207
+ },
1208
+ getFps: function getFps() {
1209
+ return fps;
1210
+ }
1211
+ };
1212
+ }
1213
+ function createReducedMotionPreference(enabled, onChange) {
1214
+ var query = enabled && typeof matchMedia !== 'undefined' ? matchMedia('(prefers-reduced-motion: reduce)') : null;
1215
+ var notify = function notify() {
1216
+ if (typeof onChange === 'function') onChange(Boolean(query && query.matches));
1217
+ };
1218
+ if (query) {
1219
+ if (typeof query.addEventListener === 'function') query.addEventListener('change', notify);else if (typeof query.addListener === 'function') query.addListener(notify);
1220
+ }
1221
+ return {
1222
+ matches: function matches() {
1223
+ return Boolean(query && query.matches);
1224
+ },
1225
+ dispose: function dispose() {
1226
+ if (!query) return;
1227
+ if (typeof query.removeEventListener === 'function') query.removeEventListener('change', notify);else if (typeof query.removeListener === 'function') query.removeListener(notify);
1228
+ }
1229
+ };
1109
1230
  }
1110
1231
 
1111
- /**
1232
+ function toFiniteNumber(value) {
1233
+ if (value == null || typeof value === 'boolean') return null;
1234
+ if (typeof value === 'string' && value.trim() === '') return null;
1235
+ var number = Number(value);
1236
+ return Number.isFinite(number) ? number : null;
1237
+ }
1238
+
1239
+ /**
1112
1240
  * Mount a cosmic (nebula) capsule into `container`.
1113
1241
  *
1114
1242
  * Options: preset (literary name), width, height (number=px or string with
1115
1243
  * px/%/vw/vh/em/rem), colors, seed, speed, textRatio (0-100, text region
1116
1244
  * width in percent), text (HTML string or DOM nodes for the text slot),
1117
1245
  * colorContent (HTML string or DOM nodes for the color slot), quality,
1118
- * renderer, respectReducedMotion, mouseColor, cssVars.
1246
+ * renderer, quality, renderScale, powerPreference, fps, paused/static,
1247
+ * respectReducedMotion, mouseColor, cssVars.
1119
1248
  */
1120
1249
  function createCapsule(container) {
1121
1250
  var _options$preset;
@@ -1125,10 +1254,19 @@ function createCapsule(container) {
1125
1254
  }
1126
1255
  var preset = _objectSpread2({}, getPreset('capsule', (_options$preset = options.preset) !== null && _options$preset !== void 0 ? _options$preset : '初光'));
1127
1256
  var merged = normalizeOptions(DEFAULTS.capsule, preset, options);
1128
- var normalizedColors = merged.colors.map(normalizeColor);
1129
- if (normalizedColors.every(Boolean)) preset.colors = normalizedColors;
1130
- preset.seed = merged.seed;
1131
- preset.speed = merged.speed;
1257
+ var normalizedColors = Array.isArray(merged.colors) ? merged.colors.map(normalizeColor) : [];
1258
+ if (normalizedColors.length === 4 && normalizedColors.every(Boolean)) preset.colors = normalizedColors;
1259
+ var initialSeed = toFiniteNumber(merged.seed);
1260
+ var initialSpeed = toFiniteNumber(merged.speed);
1261
+ if (initialSeed !== null) preset.seed = initialSeed;
1262
+ if (initialSpeed !== null) preset.speed = initialSpeed;
1263
+ merged.colors = _toConsumableArray(preset.colors);
1264
+ merged.seed = preset.seed;
1265
+ merged.speed = preset.speed;
1266
+ var optionColors = Array.isArray(options.colors) ? options.colors.map(normalizeColor) : [];
1267
+ var colorOverride = optionColors.length === 4 && optionColors.every(Boolean) ? _toConsumableArray(optionColors) : null;
1268
+ var seedOverride = options.seed !== undefined ? toFiniteNumber(options.seed) : null;
1269
+ var speedOverride = options.speed !== undefined ? toFiniteNumber(options.speed) : null;
1132
1270
  var customLabel = typeof options.label === 'string' && options.label ? options.label : null;
1133
1271
  var root = document.createElement('div');
1134
1272
  root.className = 'hj-capsule-root hj-capsule-cosmic';
@@ -1180,25 +1318,49 @@ function createCapsule(container) {
1180
1318
  root.appendChild(canvas);
1181
1319
  container.appendChild(root);
1182
1320
  var emitter = createEmitter();
1183
- var paused = merged.respectReducedMotion && prefersReducedMotion$2();
1321
+ var manuallyPaused = merged.paused === true;
1322
+ var reducedPaused = false;
1323
+ var staticMode = merged.static === true;
1324
+ var contextLost = false;
1184
1325
  var disposed = false;
1326
+ var renderOnce = function renderOnce() {};
1185
1327
  var dirty = {
1186
1328
  preset: false,
1187
1329
  seed: false,
1188
1330
  speed: false,
1189
1331
  colors: false,
1190
1332
  textRatio: false,
1191
- cssVars: false
1333
+ cssVars: false,
1334
+ mouseColor: false,
1335
+ quality: false,
1336
+ renderScale: false,
1337
+ paused: false,
1338
+ static: false,
1339
+ fps: false
1192
1340
  };
1193
1341
  var renderer;
1194
1342
  var useWebgl = merged.renderer !== 'canvas2d';
1195
1343
  if (useWebgl) {
1196
1344
  try {
1197
1345
  renderer = new CosmicRenderer(canvas, merged, {
1198
- dprCap: dprCapFor(merged.quality)
1346
+ dprCap: effectiveDprCap(merged.quality, merged.renderScale),
1347
+ mouseColor: merged.mouseColor !== false,
1348
+ powerPreference: merged.powerPreference,
1349
+ onContextLost: function onContextLost() {
1350
+ contextLost = true;
1351
+ emitter.emit('contextlost', {});
1352
+ },
1353
+ onContextRestored: function onContextRestored() {
1354
+ contextLost = false;
1355
+ emitter.emit('contextrestored', {});
1356
+ renderOnce();
1357
+ wakeScheduler();
1358
+ }
1199
1359
  });
1200
1360
  } catch (error) {
1201
- renderer = new FallbackRenderer(canvas, merged);
1361
+ renderer = new FallbackRenderer(canvas, merged, {
1362
+ dprCap: effectiveDprCap(merged.quality, merged.renderScale)
1363
+ });
1202
1364
  nextTick(function () {
1203
1365
  if (disposed) return;
1204
1366
  emitter.emit('error', {
@@ -1207,8 +1369,15 @@ function createCapsule(container) {
1207
1369
  });
1208
1370
  }
1209
1371
  } else {
1210
- renderer = new FallbackRenderer(canvas, merged);
1372
+ renderer = new FallbackRenderer(canvas, merged, {
1373
+ dprCap: effectiveDprCap(merged.quality, merged.renderScale)
1374
+ });
1211
1375
  }
1376
+ var animationTime = 0;
1377
+ var frameGate = createFrameGate(merged.fps);
1378
+ renderOnce = function renderOnce() {
1379
+ return renderer.draw(animationTime);
1380
+ };
1212
1381
  var applySize = function applySize() {
1213
1382
  root.style.width = parseSize(merged.width);
1214
1383
  root.style.height = parseSize(merged.height);
@@ -1226,11 +1395,21 @@ function createCapsule(container) {
1226
1395
  renderer.resize();
1227
1396
  };
1228
1397
  applySize();
1229
- var resizeObserver = typeof ResizeObserver !== 'undefined' ? new ResizeObserver(function () {
1230
- return renderer.resize();
1231
- }) : null;
1232
- if (resizeObserver) resizeObserver.observe(root);else window.addEventListener('resize', renderer.resize);
1233
- var visibility = createVisibilityGuard(root);
1398
+ var resize = function resize() {
1399
+ renderer.resize();
1400
+ if (manuallyPaused || reducedPaused || staticMode) renderOnce();
1401
+ };
1402
+ var resizeObserver = typeof ResizeObserver !== 'undefined' ? new ResizeObserver(resize) : null;
1403
+ if (resizeObserver) resizeObserver.observe(root);else window.addEventListener('resize', resize);
1404
+ var visibility = createVisibilityGuard(root, wakeScheduler);
1405
+ var motionPreference = createReducedMotionPreference(merged.respectReducedMotion, function (matches) {
1406
+ reducedPaused = matches;
1407
+ if (matches) renderOnce();else wakeScheduler();
1408
+ });
1409
+ reducedPaused = motionPreference.matches();
1410
+ var isMotionPaused = function isMotionPaused() {
1411
+ return manuallyPaused || reducedPaused || staticMode || contextLost;
1412
+ };
1234
1413
  root.addEventListener('pointerenter', function () {
1235
1414
  return emitter.emit('pointerenter', {
1236
1415
  preset: _objectSpread2({}, preset)
@@ -1265,12 +1444,12 @@ function createCapsule(container) {
1265
1444
  preset: _objectSpread2({}, preset)
1266
1445
  });
1267
1446
  });
1268
- var animationTime = 0;
1447
+ renderOnce();
1269
1448
  var unsubscribe = subscribeScheduler(function (delta) {
1270
1449
  animationTime += delta;
1271
- if (visibility.isVisible()) renderer.draw(animationTime);
1450
+ if (frameGate.shouldDraw(delta)) renderer.draw(animationTime);
1272
1451
  }, function () {
1273
- return paused;
1452
+ return isMotionPaused() || !visibility.isVisible();
1274
1453
  });
1275
1454
  nextTick(function () {
1276
1455
  if (disposed) return;
@@ -1293,11 +1472,15 @@ function createCapsule(container) {
1293
1472
  var next = getPreset('capsule', ref);
1294
1473
  dirty.preset = true;
1295
1474
  Object.assign(preset, next);
1475
+ if (colorOverride) preset.colors = _toConsumableArray(colorOverride);
1476
+ if (seedOverride !== null) preset.seed = seedOverride;
1477
+ if (speedOverride !== null) preset.speed = speedOverride;
1296
1478
  var nextColors = preset.colors.map(normalizeColor);
1297
1479
  if (nextColors.every(Boolean)) preset.colors = nextColors;
1298
1480
  renderer.setPreset(_objectSpread2({}, preset));
1299
1481
  syncTheme();
1300
1482
  renderer.resize();
1483
+ if (isMotionPaused()) renderOnce();
1301
1484
  emitter.emit('presetchange', {
1302
1485
  preset: _objectSpread2({}, next)
1303
1486
  });
@@ -1309,26 +1492,32 @@ function createCapsule(container) {
1309
1492
  return !color;
1310
1493
  })) return this;
1311
1494
  dirty.colors = true;
1495
+ colorOverride = _toConsumableArray(next);
1312
1496
  preset.colors = next;
1313
1497
  renderer.setPreset(_objectSpread2(_objectSpread2({}, preset), {}, {
1314
1498
  colors: next
1315
1499
  }));
1500
+ if (isMotionPaused()) renderOnce();
1316
1501
  return this;
1317
1502
  },
1318
1503
  setSeed: function setSeed(seed) {
1319
- var value = Number(seed);
1320
- if (!Number.isFinite(value)) return this;
1504
+ var value = toFiniteNumber(seed);
1505
+ if (value === null) return this;
1321
1506
  dirty.seed = true;
1507
+ seedOverride = value;
1322
1508
  preset.seed = value;
1323
1509
  renderer.setPreset(_objectSpread2({}, preset));
1510
+ if (isMotionPaused()) renderOnce();
1324
1511
  return this;
1325
1512
  },
1326
1513
  setSpeed: function setSpeed(speed) {
1327
- var value = Number(speed);
1328
- if (!Number.isFinite(value)) return this;
1514
+ var value = toFiniteNumber(speed);
1515
+ if (value === null) return this;
1329
1516
  dirty.speed = true;
1517
+ speedOverride = value;
1330
1518
  preset.speed = value;
1331
1519
  renderer.setPreset(_objectSpread2({}, preset));
1520
+ if (isMotionPaused()) renderOnce();
1332
1521
  return this;
1333
1522
  },
1334
1523
  setText: function setText(content) {
@@ -1364,6 +1553,7 @@ function createCapsule(container) {
1364
1553
  return this;
1365
1554
  },
1366
1555
  setMouseColor: function setMouseColor(value) {
1556
+ dirty.mouseColor = true;
1367
1557
  merged.mouseColor = value !== false;
1368
1558
  if (typeof renderer.setMouseColor === 'function') renderer.setMouseColor(merged.mouseColor);
1369
1559
  return this;
@@ -1378,6 +1568,7 @@ function createCapsule(container) {
1378
1568
  merged.height = height;
1379
1569
  }
1380
1570
  applySize();
1571
+ if (isMotionPaused()) renderOnce();
1381
1572
  return this;
1382
1573
  },
1383
1574
  randomize: function randomize() {
@@ -1385,23 +1576,59 @@ function createCapsule(container) {
1385
1576
  return this;
1386
1577
  },
1387
1578
  pause: function pause() {
1388
- paused = true;
1579
+ dirty.paused = true;
1580
+ manuallyPaused = true;
1581
+ renderOnce();
1389
1582
  return this;
1390
1583
  },
1391
1584
  resume: function resume() {
1392
- paused = false;
1585
+ dirty.paused = true;
1586
+ manuallyPaused = false;
1587
+ wakeScheduler();
1588
+ return this;
1589
+ },
1590
+ setPaused: function setPaused(value) {
1591
+ return value ? this.pause() : this.resume();
1592
+ },
1593
+ setStatic: function setStatic(value) {
1594
+ dirty.static = true;
1595
+ staticMode = value === true;
1596
+ merged.static = staticMode;
1597
+ if (staticMode) renderOnce();else wakeScheduler();
1598
+ return this;
1599
+ },
1600
+ setFps: function setFps(fps) {
1601
+ dirty.fps = true;
1602
+ merged.fps = frameGate.setFps(fps);
1603
+ wakeScheduler();
1393
1604
  return this;
1394
1605
  },
1395
1606
  setQuality: function setQuality(quality) {
1607
+ dirty.quality = true;
1396
1608
  merged.quality = quality;
1397
- if (typeof renderer.setDprCap === 'function') renderer.setDprCap(dprCapFor(quality));
1609
+ if (typeof renderer.setDprCap === 'function') {
1610
+ renderer.setDprCap(effectiveDprCap(quality, merged.renderScale));
1611
+ }
1612
+ if (isMotionPaused()) renderOnce();
1613
+ return this;
1614
+ },
1615
+ setRenderScale: function setRenderScale(renderScale) {
1616
+ var value = Number(renderScale);
1617
+ if (!Number.isFinite(value)) return this;
1618
+ dirty.renderScale = true;
1619
+ merged.renderScale = Math.min(1, Math.max(0.25, value));
1620
+ if (typeof renderer.setDprCap === 'function') {
1621
+ renderer.setDprCap(effectiveDprCap(merged.quality, merged.renderScale));
1622
+ }
1623
+ if (isMotionPaused()) renderOnce();
1398
1624
  return this;
1399
1625
  },
1400
1626
  dispose: function dispose() {
1401
1627
  disposed = true;
1402
1628
  unsubscribe();
1403
1629
  visibility.dispose();
1404
- if (resizeObserver) resizeObserver.disconnect();else window.removeEventListener('resize', renderer.resize);
1630
+ motionPreference.dispose();
1631
+ if (resizeObserver) resizeObserver.disconnect();else window.removeEventListener('resize', resize);
1405
1632
  renderer.dispose();
1406
1633
  root.remove();
1407
1634
  },
@@ -1411,6 +1638,24 @@ function createCapsule(container) {
1411
1638
  get cssVars() {
1412
1639
  return merged.cssVars;
1413
1640
  },
1641
+ get mouseColor() {
1642
+ return merged.mouseColor;
1643
+ },
1644
+ get quality() {
1645
+ return merged.quality;
1646
+ },
1647
+ get renderScale() {
1648
+ return merged.renderScale;
1649
+ },
1650
+ get paused() {
1651
+ return manuallyPaused;
1652
+ },
1653
+ get static() {
1654
+ return staticMode;
1655
+ },
1656
+ get fps() {
1657
+ return frameGate.getFps();
1658
+ },
1414
1659
  dirty: dirty
1415
1660
  };
1416
1661
  }
@@ -1441,6 +1686,13 @@ var PROFILE_CONFIG = {
1441
1686
  detail: 0.06,
1442
1687
  lobe: 0.23
1443
1688
  },
1689
+ 'botanic-lab': {
1690
+ seed: 3.46,
1691
+ broad: 0.54,
1692
+ middle: 0.18,
1693
+ detail: 0.05,
1694
+ lobe: 0.28
1695
+ },
1444
1696
  // ponytail: first-pass tide = asymmetric time warp on the same motion pipeline.
1445
1697
  // Refine (foam line / wash streaks) in the shader after visual QA.
1446
1698
  'tide': {
@@ -1551,64 +1803,95 @@ function createProgram(gl) {
1551
1803
  var ProgressFlowRenderer = /*#__PURE__*/function () {
1552
1804
  function ProgressFlowRenderer(canvas, preset) {
1553
1805
  var _PROFILE_INDEX$preset;
1806
+ var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
1554
1807
  _classCallCheck(this, ProgressFlowRenderer);
1555
1808
  var gl = canvas.getContext('webgl2', {
1556
1809
  alpha: false,
1557
1810
  antialias: true,
1558
1811
  premultipliedAlpha: false,
1559
- powerPreference: 'high-performance'
1812
+ powerPreference: options.powerPreference || 'high-performance'
1560
1813
  });
1561
1814
  if (!gl) throw new Error('WebGL2 unavailable');
1562
1815
  this.canvas = canvas;
1816
+ this.options = options;
1563
1817
  this.gl = gl;
1564
- this.program = createProgram(gl);
1565
1818
  this.profile = preset.edgeStyle === 'tide' ? 3 : (_PROFILE_INDEX$preset = PROFILE_INDEX[preset.id]) !== null && _PROFILE_INDEX$preset !== void 0 ? _PROFILE_INDEX$preset : 2;
1566
1819
  this.seed = stringSeed$1("".concat(preset.id, "-shader")) * 13.7 + 1.0;
1567
1820
  this.colors = preset.colors.map(hexToRgb01);
1568
1821
  this.motionData = getProgressMotionData(preset.id, preset.edgeStyle);
1569
1822
  var motionFactor = preset.edgeStyle === 'tide' ? MOTION_SCALE_FACTORS.tide : MOTION_SCALE_FACTORS[preset.id] || 1.04;
1570
1823
  this.motionScale = PROGRESS_MOTION_MAX_PX * motionFactor / 1257;
1571
- this.position = gl.getAttribLocation(this.program, 'a_position');
1572
- this.uniforms = {
1573
- resolution: gl.getUniformLocation(this.program, 'u_resolution'),
1574
- time: gl.getUniformLocation(this.program, 'u_time'),
1575
- progress: gl.getUniformLocation(this.program, 'u_progress'),
1576
- seed: gl.getUniformLocation(this.program, 'u_seed'),
1577
- profile: gl.getUniformLocation(this.program, 'u_profile'),
1578
- motion: gl.getUniformLocation(this.program, 'u_motion'),
1579
- effect: gl.getUniformLocation(this.program, 'u_effect'),
1580
- hasEffect: gl.getUniformLocation(this.program, 'u_hasEffect'),
1581
- effectFrames: gl.getUniformLocation(this.program, 'u_effectFrames'),
1582
- motionDuration: gl.getUniformLocation(this.program, 'u_motionDuration'),
1583
- motionScale: gl.getUniformLocation(this.program, 'u_motionScale'),
1584
- dark: gl.getUniformLocation(this.program, 'u_dark'),
1585
- accentA: gl.getUniformLocation(this.program, 'u_accentA'),
1586
- accentB: gl.getUniformLocation(this.program, 'u_accentB'),
1587
- glow: gl.getUniformLocation(this.program, 'u_glow')
1588
- };
1589
- this.buffer = gl.createBuffer();
1590
- gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
1591
- gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]), gl.STATIC_DRAW);
1592
- this.motionTexture = gl.createTexture();
1593
- gl.activeTexture(gl.TEXTURE0);
1594
- gl.bindTexture(gl.TEXTURE_2D, this.motionTexture);
1595
- gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
1596
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.R8, PROGRESS_MOTION_WIDTH, PROGRESS_MOTION_HEIGHT, 0, gl.RED, gl.UNSIGNED_BYTE, this.motionData);
1597
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
1598
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
1599
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
1600
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
1601
- this.effectTexture = gl.createTexture();
1602
- gl.activeTexture(gl.TEXTURE1);
1603
- gl.bindTexture(gl.TEXTURE_2D, this.effectTexture);
1604
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, 1, 1, 0, gl.RGB, gl.UNSIGNED_BYTE, new Uint8Array([32, 33, 38]));
1605
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
1606
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
1607
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
1608
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
1609
- this.effectUploaded = false;
1824
+ this.disposed = false;
1825
+ this.contextLost = false;
1826
+ this.setupResources();
1827
+ this.bindContextEvents();
1610
1828
  }
1611
1829
  return _createClass(ProgressFlowRenderer, [{
1830
+ key: "setupResources",
1831
+ value: function setupResources() {
1832
+ var gl = this.gl;
1833
+ this.program = createProgram(gl);
1834
+ this.position = gl.getAttribLocation(this.program, 'a_position');
1835
+ this.uniforms = {
1836
+ resolution: gl.getUniformLocation(this.program, 'u_resolution'),
1837
+ time: gl.getUniformLocation(this.program, 'u_time'),
1838
+ progress: gl.getUniformLocation(this.program, 'u_progress'),
1839
+ seed: gl.getUniformLocation(this.program, 'u_seed'),
1840
+ profile: gl.getUniformLocation(this.program, 'u_profile'),
1841
+ motion: gl.getUniformLocation(this.program, 'u_motion'),
1842
+ effect: gl.getUniformLocation(this.program, 'u_effect'),
1843
+ hasEffect: gl.getUniformLocation(this.program, 'u_hasEffect'),
1844
+ effectFrames: gl.getUniformLocation(this.program, 'u_effectFrames'),
1845
+ motionDuration: gl.getUniformLocation(this.program, 'u_motionDuration'),
1846
+ motionScale: gl.getUniformLocation(this.program, 'u_motionScale'),
1847
+ dark: gl.getUniformLocation(this.program, 'u_dark'),
1848
+ accentA: gl.getUniformLocation(this.program, 'u_accentA'),
1849
+ accentB: gl.getUniformLocation(this.program, 'u_accentB'),
1850
+ glow: gl.getUniformLocation(this.program, 'u_glow')
1851
+ };
1852
+ this.buffer = gl.createBuffer();
1853
+ gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
1854
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]), gl.STATIC_DRAW);
1855
+ this.motionTexture = gl.createTexture();
1856
+ gl.activeTexture(gl.TEXTURE0);
1857
+ gl.bindTexture(gl.TEXTURE_2D, this.motionTexture);
1858
+ gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
1859
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.R8, PROGRESS_MOTION_WIDTH, PROGRESS_MOTION_HEIGHT, 0, gl.RED, gl.UNSIGNED_BYTE, this.motionData);
1860
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
1861
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
1862
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
1863
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
1864
+ this.effectTexture = gl.createTexture();
1865
+ gl.activeTexture(gl.TEXTURE1);
1866
+ gl.bindTexture(gl.TEXTURE_2D, this.effectTexture);
1867
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, 1, 1, 0, gl.RGB, gl.UNSIGNED_BYTE, new Uint8Array([32, 33, 38]));
1868
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
1869
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
1870
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
1871
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
1872
+ this.effectUploaded = false;
1873
+ }
1874
+ }, {
1875
+ key: "bindContextEvents",
1876
+ value: function bindContextEvents() {
1877
+ var _this = this;
1878
+ this.onContextLost = function (event) {
1879
+ event.preventDefault();
1880
+ if (_this.disposed) return;
1881
+ _this.contextLost = true;
1882
+ if (typeof _this.options.onContextLost === 'function') _this.options.onContextLost(event);
1883
+ };
1884
+ this.onContextRestored = function () {
1885
+ if (_this.disposed) return;
1886
+ _this.setupResources();
1887
+ _this.contextLost = false;
1888
+ _this.gl.viewport(0, 0, _this.canvas.width, _this.canvas.height);
1889
+ if (typeof _this.options.onContextRestored === 'function') _this.options.onContextRestored();
1890
+ };
1891
+ this.canvas.addEventListener('webglcontextlost', this.onContextLost, false);
1892
+ this.canvas.addEventListener('webglcontextrestored', this.onContextRestored, false);
1893
+ }
1894
+ }, {
1612
1895
  key: "resize",
1613
1896
  value: function resize(width, height, dpr) {
1614
1897
  var pixelWidth = Math.max(1, Math.round(width * dpr));
@@ -1623,6 +1906,7 @@ var ProgressFlowRenderer = /*#__PURE__*/function () {
1623
1906
  key: "draw",
1624
1907
  value: function draw(time, progress) {
1625
1908
  var effectImage = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
1909
+ if (this.disposed || this.contextLost) return;
1626
1910
  var gl = this.gl;
1627
1911
  gl.useProgram(this.program);
1628
1912
  gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
@@ -1639,7 +1923,8 @@ var ProgressFlowRenderer = /*#__PURE__*/function () {
1639
1923
  gl.uniform1f(this.uniforms.motionDuration, PROGRESS_MOTION_DURATION);
1640
1924
  gl.uniform1f(this.uniforms.motionScale, this.motionScale);
1641
1925
  var hasEffect = this.effectUploaded ? 1 : 0;
1642
- if (!this.effectUploaded && effectImage && effectImage.complete && effectImage.naturalWidth > 0) {
1926
+ var effectWidth = effectImage && (effectImage.naturalWidth || effectImage.width || 0);
1927
+ if (!this.effectUploaded && effectImage && effectWidth > 0) {
1643
1928
  gl.activeTexture(gl.TEXTURE1);
1644
1929
  gl.bindTexture(gl.TEXTURE_2D, this.effectTexture);
1645
1930
  gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
@@ -1671,7 +1956,10 @@ var ProgressFlowRenderer = /*#__PURE__*/function () {
1671
1956
  }, {
1672
1957
  key: "dispose",
1673
1958
  value: function dispose() {
1959
+ this.disposed = true;
1674
1960
  var gl = this.gl;
1961
+ this.canvas.removeEventListener('webglcontextlost', this.onContextLost, false);
1962
+ this.canvas.removeEventListener('webglcontextrestored', this.onContextRestored, false);
1675
1963
  gl.deleteBuffer(this.buffer);
1676
1964
  gl.deleteTexture(this.motionTexture);
1677
1965
  gl.deleteTexture(this.effectTexture);
@@ -1682,8 +1970,9 @@ var ProgressFlowRenderer = /*#__PURE__*/function () {
1682
1970
  }]);
1683
1971
  }();
1684
1972
  function createProgressFlowRenderer(canvas, preset) {
1973
+ var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
1685
1974
  try {
1686
- return new ProgressFlowRenderer(canvas, preset);
1975
+ return new ProgressFlowRenderer(canvas, preset, options);
1687
1976
  } catch (error) {
1688
1977
  console.warn('[画境观屿] 进度流体 WebGL2 不可用,使用 Canvas 2D 降级。', error);
1689
1978
  return null;
@@ -1699,7 +1988,8 @@ var PALETTES = {
1699
1988
  'model-training': ['#20131f', '#ff3f94', '#ff8a3d', '#fff06a'],
1700
1989
  'agent-migration': ['#111a31', '#245bff', '#00cfff', '#5dffe6'],
1701
1990
  'visual-training': ['#1f172b', '#7042ff', '#42f58d', '#c4ff8a'],
1702
- 'tide': ['#0a2239', '#2e9bff', '#7fe3ff', '#eaf9ff']
1991
+ 'tide': ['#0a2239', '#2e9bff', '#7fe3ff', '#eaf9ff'],
1992
+ 'botanic-lab': ['#102a23', '#287a58', '#9bd65b', '#f2ffc4']
1703
1993
  };
1704
1994
  function drawCloud(context, x, y, radiusX, radiusY, color, alpha) {
1705
1995
  context.save();
@@ -1743,50 +2033,49 @@ function createAtlas(id) {
1743
2033
  context.fillRect(20, 0, 44, FRAME_HEIGHT);
1744
2034
  context.restore();
1745
2035
  }
1746
- var image = new Image();
1747
- image.decoding = 'async';
1748
- var state = {
1749
- image: image,
1750
- ready: false
2036
+
2037
+ // A canvas is a valid TexImageSource. Keeping it directly avoids a PNG
2038
+ // encode -> base64 allocation -> Image decode round trip at startup.
2039
+ return {
2040
+ image: canvas,
2041
+ ready: true
1751
2042
  };
1752
- image.addEventListener('load', function () {
1753
- state.ready = true;
1754
- }, {
1755
- once: true
1756
- });
1757
- image.addEventListener('error', function () {
1758
- state.ready = false;
1759
- }, {
1760
- once: true
1761
- });
1762
- image.src = canvas.toDataURL('image/png');
1763
- return state;
1764
2043
  }
1765
2044
  function getProgressReferenceAtlas(id) {
1766
2045
  if (!CACHE[id]) CACHE[id] = createAtlas(id);
1767
2046
  return CACHE[id];
1768
2047
  }
1769
2048
 
1770
- /**
1771
- * Attach a WebGL2 fluid overlay to a progress capsule root.
1772
- *
1773
- * @param {object} params
1774
- * @param {HTMLElement} params.root progress capsule root element
1775
- * @param {HTMLCanvasElement} params.canvas 2D fallback canvas (kept beneath)
1776
- * @param {object} params.preset progress preset
1777
- * @param {() => number} params.getProgress reads the current progress value
1778
- * @returns {{ update(flowTime: number): void, dispose(): void } | null}
2049
+ /**
2050
+ * Attach a WebGL2 fluid overlay to a progress capsule root.
2051
+ *
2052
+ * @param {object} params
2053
+ * @param {HTMLElement} params.root progress capsule root element
2054
+ * @param {HTMLCanvasElement} params.canvas 2D fallback canvas (kept beneath)
2055
+ * @param {object} params.preset progress preset
2056
+ * @param {() => number} params.getProgress reads the current progress value
2057
+ * @returns {{ update(flowTime: number): void, setDprCap(cap: number): void, dispose(): void } | null}
1779
2058
  */
1780
2059
  function attachProgressFlowOverlay(_ref) {
1781
2060
  var root = _ref.root,
1782
2061
  canvas = _ref.canvas,
1783
2062
  preset = _ref.preset,
1784
- getProgress = _ref.getProgress;
2063
+ getProgress = _ref.getProgress,
2064
+ _ref$dprCap = _ref.dprCap,
2065
+ dprCap = _ref$dprCap === void 0 ? 2 : _ref$dprCap,
2066
+ _ref$powerPreference = _ref.powerPreference,
2067
+ powerPreference = _ref$powerPreference === void 0 ? 'high-performance' : _ref$powerPreference,
2068
+ onContextLost = _ref.onContextLost,
2069
+ onContextRestored = _ref.onContextRestored;
1785
2070
  var overlay = document.createElement('canvas');
1786
2071
  overlay.className = 'hj-progress-canvas hj-progress-overlay';
1787
2072
  overlay.setAttribute('aria-hidden', 'true');
1788
2073
  canvas.insertAdjacentElement('afterend', overlay);
1789
- var renderer = createProgressFlowRenderer(overlay, preset);
2074
+ var renderer = createProgressFlowRenderer(overlay, preset, {
2075
+ powerPreference: powerPreference,
2076
+ onContextLost: onContextLost,
2077
+ onContextRestored: onContextRestored
2078
+ });
1790
2079
  if (!renderer) {
1791
2080
  overlay.remove();
1792
2081
  return null;
@@ -1797,7 +2086,7 @@ function attachProgressFlowOverlay(_ref) {
1797
2086
  var bounds = root.getBoundingClientRect();
1798
2087
  var width = Math.max(1, bounds.width);
1799
2088
  var height = Math.max(1, bounds.height);
1800
- var dpr = Math.min(window.devicePixelRatio || 1, 2);
2089
+ var dpr = Math.min(window.devicePixelRatio || 1, dprCap);
1801
2090
  overlay.style.width = "".concat(width, "px");
1802
2091
  overlay.style.height = "".concat(height, "px");
1803
2092
  renderer.resize(width, height, dpr);
@@ -1821,6 +2110,10 @@ function attachProgressFlowOverlay(_ref) {
1821
2110
  setColors: function setColors(colors) {
1822
2111
  renderer.setColors(colors);
1823
2112
  },
2113
+ setDprCap: function setDprCap(cap) {
2114
+ dprCap = cap;
2115
+ resize();
2116
+ },
1824
2117
  dispose: function dispose() {
1825
2118
  if (resizeObserver) resizeObserver.disconnect();
1826
2119
  if (onWindowResize) window.removeEventListener('resize', onWindowResize);
@@ -1831,6 +2124,47 @@ function attachProgressFlowOverlay(_ref) {
1831
2124
  };
1832
2125
  }
1833
2126
 
2127
+ function normalizeRange(min, max) {
2128
+ var fallbackMin = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
2129
+ var fallbackMax = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 100;
2130
+ var nextMin = toFiniteNumber(min);
2131
+ var nextMax = toFiniteNumber(max);
2132
+ if (nextMin === null) nextMin = fallbackMin;
2133
+ if (nextMax === null) nextMax = fallbackMax;
2134
+ if (nextMin > nextMax) {
2135
+ var swap = nextMin;
2136
+ nextMin = nextMax;
2137
+ nextMax = swap;
2138
+ }
2139
+ return [nextMin, nextMax];
2140
+ }
2141
+ function clampProgressValue(value, min, max) {
2142
+ var number = toFiniteNumber(value);
2143
+ if (number === null) return null;
2144
+ return Math.min(Math.max(number, min), max);
2145
+ }
2146
+ function normalizeProgressStep(step) {
2147
+ var fallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'any';
2148
+ if (step === 'any' || step == null) return 'any';
2149
+ var increment = toFiniteNumber(step);
2150
+ return increment !== null && increment > 0 ? increment : fallback;
2151
+ }
2152
+ function snapProgressValue(value, min, max) {
2153
+ var step = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'any';
2154
+ var clamped = clampProgressValue(value, min, max);
2155
+ if (clamped === null) return null;
2156
+ if (step === 'any' || step == null) return clamped;
2157
+ var increment = normalizeProgressStep(step);
2158
+ if (increment === 'any') return clamped;
2159
+ var snapped = min + Math.round((clamped - min) / increment) * increment;
2160
+ return Math.min(Math.max(Number(snapped.toFixed(12)), min), max);
2161
+ }
2162
+ function progressRatio(value, min, max) {
2163
+ var range = max - min;
2164
+ if (!Number.isFinite(range) || range <= 0) return 0;
2165
+ return Math.min(Math.max((value - min) / range, 0), 1);
2166
+ }
2167
+
1834
2168
  var clamp = function clamp(value, min, max) {
1835
2169
  return Math.min(Math.max(value, min), max);
1836
2170
  };
@@ -1857,9 +2191,6 @@ function interpolate(template, values) {
1857
2191
  return values[key] !== undefined ? values[key] : '';
1858
2192
  });
1859
2193
  }
1860
- function prefersReducedMotion$1() {
1861
- return typeof matchMedia !== 'undefined' && matchMedia('(prefers-reduced-motion: reduce)').matches;
1862
- }
1863
2194
  var FLOW_PROFILES = {
1864
2195
  'model-training': {
1865
2196
  cycles: [0.98, 3.05, 5.45],
@@ -1920,8 +2251,6 @@ var FLOW_PROFILES = {
1920
2251
  var ProgressCapsuleController = /*#__PURE__*/function () {
1921
2252
  function ProgressCapsuleController(_ref) {
1922
2253
  var _options$valueSuffix,
1923
- _options$min,
1924
- _options$max,
1925
2254
  _options$value,
1926
2255
  _this = this;
1927
2256
  var root = _ref.root,
@@ -1943,11 +2272,18 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
1943
2272
  this.dirty = dirty;
1944
2273
  this.valueSuffix = (_options$valueSuffix = options.valueSuffix) !== null && _options$valueSuffix !== void 0 ? _options$valueSuffix : copy.valueSuffix;
1945
2274
  this.profile = preset.edgeStyle === 'tide' ? FLOW_PROFILES.tide : FLOW_PROFILES[preset.id] || FLOW_PROFILES['visual-training'];
1946
- this.min = (_options$min = options.min) !== null && _options$min !== void 0 ? _options$min : 0;
1947
- this.max = (_options$max = options.max) !== null && _options$max !== void 0 ? _options$max : 100;
1948
- this.dprCap = dprCapFor(options.quality);
2275
+ var _normalizeRange = normalizeRange(options.min, options.max);
2276
+ var _normalizeRange2 = _slicedToArray(_normalizeRange, 2);
2277
+ this.min = _normalizeRange2[0];
2278
+ this.max = _normalizeRange2[1];
2279
+ this.step = normalizeProgressStep(options.step);
2280
+ this.precision = Number.isInteger(Number(options.precision)) ? clamp(Number(options.precision), 0, 20) : 0;
2281
+ this.formatValue = typeof options.formatValue === 'function' ? options.formatValue : null;
2282
+ this.direction = options.direction === 'rtl' ? 'rtl' : 'ltr';
2283
+ this.dprCap = effectiveDprCap(options.quality, options.renderScale);
1949
2284
  this.ctx = canvas.getContext('2d');
1950
- this.value = clamp((_options$value = options.value) !== null && _options$value !== void 0 ? _options$value : preset.initialProgress, this.min, this.max);
2285
+ this.value = snapProgressValue((_options$value = options.value) !== null && _options$value !== void 0 ? _options$value : preset.initialProgress, this.min, this.max, this.step);
2286
+ if (this.value === null) this.value = clamp(preset.initialProgress, this.min, this.max);
1951
2287
  this.dragging = false;
1952
2288
  this.webglActive = false;
1953
2289
  this.flowTime = stringSeed(preset.id) * 31;
@@ -1957,10 +2293,12 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
1957
2293
  this.width = 0;
1958
2294
  this.height = 0;
1959
2295
  this.handlers = {};
1960
- this.resizeObserver = typeof ResizeObserver !== 'undefined' ? new ResizeObserver(function () {
1961
- return _this.resizeCanvas();
1962
- }) : null;
1963
- if (this.resizeObserver) this.resizeObserver.observe(this.root);else window.addEventListener('resize', this.resizeCanvas);
2296
+ this.onResize = function () {
2297
+ _this.resizeCanvas();
2298
+ if (typeof _this.options.onResize === 'function') _this.options.onResize();
2299
+ };
2300
+ this.resizeObserver = typeof ResizeObserver !== 'undefined' ? new ResizeObserver(this.onResize) : null;
2301
+ if (this.resizeObserver) this.resizeObserver.observe(this.root);else window.addEventListener('resize', this.onResize);
1964
2302
  this.suppressEvents = true;
1965
2303
  this.setProgress(this.value, 'init');
1966
2304
  this.suppressEvents = false;
@@ -1973,16 +2311,37 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
1973
2311
  this.randomState = Math.imul(this.randomState, 1664525) + 1013904223 >>> 0;
1974
2312
  return this.randomState / 4294967296;
1975
2313
  }
2314
+ }, {
2315
+ key: "displayText",
2316
+ value: function displayText() {
2317
+ if (this.formatValue) {
2318
+ return String(this.formatValue(this.value, {
2319
+ min: this.min,
2320
+ max: this.max,
2321
+ suffix: this.valueSuffix
2322
+ }));
2323
+ }
2324
+ var number = this.precision > 0 ? this.value.toFixed(this.precision) : String(Math.round(this.value));
2325
+ return "".concat(number).concat(this.valueSuffix);
2326
+ }
2327
+ }, {
2328
+ key: "syncValueDom",
2329
+ value: function syncValueDom() {
2330
+ var text = this.displayText();
2331
+ this.root.style.setProperty('--progress', this.value.toFixed(2));
2332
+ this.root.style.setProperty('--progress-ratio', progressRatio(this.value, this.min, this.max).toFixed(4));
2333
+ this.root.setAttribute('aria-valuenow', String(this.value));
2334
+ this.root.setAttribute('aria-valuetext', text);
2335
+ if (this.valueElement) this.valueElement.textContent = text;
2336
+ }
1976
2337
  }, {
1977
2338
  key: "setProgress",
1978
2339
  value: function setProgress(nextValue) {
1979
2340
  var source = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'auto';
1980
- this.value = clamp(nextValue, this.min, this.max);
1981
- var rounded = Math.round(this.value);
1982
- this.root.style.setProperty('--progress', this.value.toFixed(2));
1983
- this.root.setAttribute('aria-valuenow', String(rounded));
1984
- this.root.setAttribute('aria-valuetext', "".concat(rounded).concat(this.valueSuffix));
1985
- if (this.valueElement) this.valueElement.textContent = "".concat(rounded).concat(this.valueSuffix);
2341
+ var next = snapProgressValue(nextValue, this.min, this.max, this.step);
2342
+ if (next === null) return false;
2343
+ this.value = next;
2344
+ this.syncValueDom();
1986
2345
  if (!this.suppressEvents) {
1987
2346
  if (this.dirty) this.dirty.value = true;
1988
2347
  this.emitter.emit('change', {
@@ -1990,19 +2349,58 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
1990
2349
  source: source
1991
2350
  });
1992
2351
  }
2352
+ return true;
1993
2353
  }
1994
2354
  }, {
1995
2355
  key: "setValueSuffix",
1996
2356
  value: function setValueSuffix(suffix) {
2357
+ if (this.dirty) this.dirty.valueSuffix = true;
1997
2358
  this.valueSuffix = String(suffix == null ? '' : suffix);
1998
- var rounded = Math.round(this.value);
1999
- if (this.valueElement) this.valueElement.textContent = "".concat(rounded).concat(this.valueSuffix);
2000
- this.root.setAttribute('aria-valuetext', "".concat(rounded).concat(this.valueSuffix));
2359
+ this.syncValueDom();
2360
+ return this;
2361
+ }
2362
+ }, {
2363
+ key: "setStep",
2364
+ value: function setStep(step) {
2365
+ var nextStep = normalizeProgressStep(step, this.step);
2366
+ if (nextStep === this.step) return this;
2367
+ if (this.dirty) this.dirty.step = true;
2368
+ this.step = nextStep;
2369
+ var next = snapProgressValue(this.value, this.min, this.max, this.step);
2370
+ if (next !== null && next !== this.value) this.setProgress(next, 'prop');
2371
+ return this;
2372
+ }
2373
+ }, {
2374
+ key: "setPrecision",
2375
+ value: function setPrecision(precision) {
2376
+ var value = Number(precision);
2377
+ if (!Number.isInteger(value) || value < 0 || value > 20) return this;
2378
+ if (this.dirty) this.dirty.precision = true;
2379
+ this.precision = value;
2380
+ this.syncValueDom();
2381
+ return this;
2382
+ }
2383
+ }, {
2384
+ key: "setFormatValue",
2385
+ value: function setFormatValue(formatter) {
2386
+ if (formatter != null && typeof formatter !== 'function') return this;
2387
+ if (this.dirty) this.dirty.formatValue = true;
2388
+ this.formatValue = formatter || null;
2389
+ this.syncValueDom();
2390
+ return this;
2391
+ }
2392
+ }, {
2393
+ key: "setDirection",
2394
+ value: function setDirection(direction) {
2395
+ if (this.dirty) this.dirty.direction = true;
2396
+ this.direction = direction === 'rtl' ? 'rtl' : 'ltr';
2397
+ this.root.dataset.direction = this.direction;
2001
2398
  return this;
2002
2399
  }
2003
2400
  }, {
2004
2401
  key: "setShowValue",
2005
2402
  value: function setShowValue(show) {
2403
+ if (this.dirty) this.dirty.showValue = true;
2006
2404
  if (this.valueElement) this.valueElement.hidden = show === false;
2007
2405
  return this;
2008
2406
  }
@@ -2167,15 +2565,14 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
2167
2565
  }, {
2168
2566
  key: "setRange",
2169
2567
  value: function setRange(min, max) {
2170
- if (min > max) {
2171
- var swap = min;
2172
- min = max;
2173
- max = swap;
2174
- }
2175
- this.min = min;
2176
- this.max = max;
2177
- var clamped = clamp(this.value, this.min, this.max);
2178
- if (clamped !== this.value) this.setProgress(clamped, 'prop');
2568
+ var nextRange = normalizeRange(min, max, this.min, this.max);
2569
+ this.min = nextRange[0];
2570
+ this.max = nextRange[1];
2571
+ this.root.setAttribute('aria-valuemin', String(this.min));
2572
+ this.root.setAttribute('aria-valuemax', String(this.max));
2573
+ var next = snapProgressValue(this.value, this.min, this.max, this.step);
2574
+ if (next !== this.value) this.setProgress(next, 'prop');else this.syncValueDom();
2575
+ return this;
2179
2576
  }
2180
2577
  }, {
2181
2578
  key: "drawReferenceFlow",
@@ -2300,8 +2697,39 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
2300
2697
  value: function updateFromPointer(event) {
2301
2698
  var bounds = this.root.getBoundingClientRect();
2302
2699
  var ratio = bounds.width > 0 ? (event.clientX - bounds.left) / bounds.width : 0;
2700
+ if (this.direction === 'rtl') ratio = 1 - ratio;
2303
2701
  this.setProgress(this.min + ratio * (this.max - this.min), 'drag');
2304
2702
  }
2703
+ }, {
2704
+ key: "onKeyDown",
2705
+ value: function onKeyDown(event) {
2706
+ var range = this.max - this.min;
2707
+ var configuredStep = Number(this.step);
2708
+ var step = Number.isFinite(configuredStep) && configuredStep > 0 ? configuredStep : Math.max(range / 100, 1e-7);
2709
+ var direction = this.direction === 'rtl' ? -1 : 1;
2710
+ var aliases = {
2711
+ Left: 'ArrowLeft',
2712
+ Right: 'ArrowRight',
2713
+ Up: 'ArrowUp',
2714
+ Down: 'ArrowDown'
2715
+ };
2716
+ var keyCodes = {
2717
+ 35: 'End',
2718
+ 36: 'Home',
2719
+ 33: 'PageUp',
2720
+ 34: 'PageDown',
2721
+ 37: 'ArrowLeft',
2722
+ 38: 'ArrowUp',
2723
+ 39: 'ArrowRight',
2724
+ 40: 'ArrowDown'
2725
+ };
2726
+ var key = aliases[event.key] || event.key || keyCodes[event.keyCode];
2727
+ var next = null;
2728
+ if (key === 'ArrowRight') next = this.value + step * direction;else if (key === 'ArrowLeft') next = this.value - step * direction;else if (key === 'ArrowUp') next = this.value + step;else if (key === 'ArrowDown') next = this.value - step;else if (key === 'PageUp') next = this.value + step * 10;else if (key === 'PageDown') next = this.value - step * 10;else if (key === 'Home') next = this.min;else if (key === 'End') next = this.max;
2729
+ if (next === null) return;
2730
+ event.preventDefault();
2731
+ this.setProgress(next, 'keyboard');
2732
+ }
2305
2733
  }, {
2306
2734
  key: "beginDrag",
2307
2735
  value: function beginDrag(event) {
@@ -2389,6 +2817,12 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
2389
2817
  this.root.addEventListener('pointerup', this.handlers.pointerup);
2390
2818
  this.root.addEventListener('pointercancel', this.handlers.pointercancel);
2391
2819
  }
2820
+ if (this.options.keyboard !== false) {
2821
+ this.handlers.keydown = function (event) {
2822
+ return _this3.onKeyDown(event);
2823
+ };
2824
+ this.root.addEventListener('keydown', this.handlers.keydown);
2825
+ }
2392
2826
  }
2393
2827
  }, {
2394
2828
  key: "update",
@@ -2407,20 +2841,19 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
2407
2841
  key: "randomize",
2408
2842
  value: function randomize() {
2409
2843
  this.flowTime = this.random() * 40;
2844
+ return this.flowTime;
2410
2845
  }
2411
2846
  }, {
2412
2847
  key: "setColors",
2413
2848
  value: function setColors(colors) {
2414
2849
  if (!Array.isArray(colors) || colors.length !== 4) return;
2415
- this.preset = _objectSpread2(_objectSpread2({}, this.preset), {}, {
2416
- colors: colors
2417
- });
2850
+ this.preset.colors = _toConsumableArray(colors);
2418
2851
  }
2419
2852
  }, {
2420
2853
  key: "dispose",
2421
2854
  value: function dispose() {
2422
2855
  if (this._dragRaf) cancelAnimationFrame(this._dragRaf);
2423
- if (this.resizeObserver) this.resizeObserver.disconnect();else window.removeEventListener('resize', this.resizeCanvas);
2856
+ if (this.resizeObserver) this.resizeObserver.disconnect();else window.removeEventListener('resize', this.onResize);
2424
2857
  for (var _i = 0, _Object$keys = Object.keys(this.handlers); _i < _Object$keys.length; _i++) {
2425
2858
  var name = _Object$keys[_i];
2426
2859
  var handler = this.handlers[name];
@@ -2431,15 +2864,16 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
2431
2864
  }]);
2432
2865
  }();
2433
2866
 
2434
- /**
2867
+ /**
2435
2868
  * Mount a fluid progress capsule into `container`.
2436
2869
  *
2437
- * Options: preset (literary name), width, height, value, min, max,
2438
- * draggable, colors, edgeStyle, textRatio (0-100, text region
2870
+ * Options: preset (literary name), width, height, value/modelValue, min, max,
2871
+ * step, draggable, keyboard, direction, precision/formatValue, colors,
2872
+ * edgeStyle, textRatio (0-100, text region
2439
2873
  * width in percent), text (HTML string or DOM nodes for the text slot),
2440
2874
  * colorContent (HTML string or DOM nodes for the color slot),
2441
- * showValue (show/hide the right-side percentage), quality,
2442
- * respectReducedMotion, cssVars.
2875
+ * showValue (show/hide the right-side percentage), quality, renderScale,
2876
+ * powerPreference, fps, paused/static, respectReducedMotion, cssVars.
2443
2877
  */
2444
2878
  function createProgressCapsule(container) {
2445
2879
  var _options$preset, _merged$min, _merged$max;
@@ -2449,14 +2883,20 @@ function createProgressCapsule(container) {
2449
2883
  }
2450
2884
  var preset = _objectSpread2({}, getPreset('progress', (_options$preset = options.preset) !== null && _options$preset !== void 0 ? _options$preset : '星火'));
2451
2885
  var merged = normalizeOptions(DEFAULTS.progress, preset, options);
2452
- if (merged.min > merged.max) {
2453
- var swap = merged.min;
2454
- merged.min = merged.max;
2455
- merged.max = swap;
2456
- }
2457
- var normalizedColors = merged.colors.map(normalizeColor);
2458
- if (normalizedColors.every(Boolean)) preset.colors = normalizedColors;
2459
- preset.edgeStyle = merged.edgeStyle;
2886
+ var _normalizeRange3 = normalizeRange(merged.min, merged.max);
2887
+ var _normalizeRange4 = _slicedToArray(_normalizeRange3, 2);
2888
+ merged.min = _normalizeRange4[0];
2889
+ merged.max = _normalizeRange4[1];
2890
+ if (merged.modelValue !== undefined) merged.value = merged.modelValue;
2891
+ var normalizedColors = Array.isArray(merged.colors) ? merged.colors.map(normalizeColor) : [];
2892
+ if (normalizedColors.length === 4 && normalizedColors.every(Boolean)) preset.colors = normalizedColors;
2893
+ var initialEdgeStyle = merged.edgeStyle === 'tide' || merged.edgeStyle === 'flow' ? merged.edgeStyle : preset.edgeStyle;
2894
+ preset.edgeStyle = initialEdgeStyle;
2895
+ merged.edgeStyle = initialEdgeStyle;
2896
+ merged.colors = _toConsumableArray(preset.colors);
2897
+ var optionColors = Array.isArray(options.colors) ? options.colors.map(normalizeColor) : [];
2898
+ var colorOverride = optionColors.length === 4 && optionColors.every(Boolean) ? _toConsumableArray(optionColors) : null;
2899
+ var edgeStyleOverride = options.edgeStyle === 'flow' || options.edgeStyle === 'tide' ? merged.edgeStyle : null;
2460
2900
  var copy = COPY;
2461
2901
  var customLabel = typeof options.label === 'string' && options.label ? options.label : null;
2462
2902
  // Vue 的裸布尔属性(<ProgressCapsule disabled />)会传成空字符串,
@@ -2465,18 +2905,31 @@ function createProgressCapsule(container) {
2465
2905
  var readonly = merged.readonly === true || merged.readonly === '' || merged.readonly === 'true';
2466
2906
  var locked = disabled || readonly;
2467
2907
  var effectiveDraggable = locked ? false : merged.draggable !== false;
2908
+ var effectiveKeyboard = locked ? false : merged.keyboard !== false;
2468
2909
  var dirty = {
2469
2910
  preset: false,
2470
2911
  colors: false,
2471
2912
  textRatio: false,
2472
2913
  cssVars: false,
2473
2914
  edgeStyle: false,
2474
- value: false
2915
+ value: false,
2916
+ step: false,
2917
+ precision: false,
2918
+ formatValue: false,
2919
+ direction: false,
2920
+ showValue: false,
2921
+ valueSuffix: false,
2922
+ quality: false,
2923
+ renderScale: false,
2924
+ paused: false,
2925
+ static: false,
2926
+ fps: false
2475
2927
  };
2476
2928
  var root = document.createElement('div');
2477
2929
  root.className = 'hj-capsule-root hj-progress-root';
2478
2930
  root.setAttribute('role', 'slider');
2479
2931
  root.setAttribute('data-draggable', String(effectiveDraggable));
2932
+ root.dataset.direction = merged.direction === 'rtl' ? 'rtl' : 'ltr';
2480
2933
  if (disabled) {
2481
2934
  root.setAttribute('aria-disabled', 'true');
2482
2935
  root.classList.add('is-disabled');
@@ -2485,7 +2938,8 @@ function createProgressCapsule(container) {
2485
2938
  root.setAttribute('aria-readonly', 'true');
2486
2939
  root.classList.add('is-readonly');
2487
2940
  }
2488
- if (locked) root.setAttribute('tabindex', '-1');
2941
+ root.setAttribute('tabindex', locked ? '-1' : effectiveKeyboard ? '0' : '-1');
2942
+ root.setAttribute('aria-orientation', 'horizontal');
2489
2943
  root.setAttribute('aria-valuemin', String((_merged$min = merged.min) !== null && _merged$min !== void 0 ? _merged$min : 0));
2490
2944
  root.setAttribute('aria-valuemax', String((_merged$max = merged.max) !== null && _merged$max !== void 0 ? _merged$max : 100));
2491
2945
  root.setAttribute('aria-valuenow', String(preset.initialProgress));
@@ -2540,8 +2994,22 @@ function createProgressCapsule(container) {
2540
2994
  root.appendChild(valueElement);
2541
2995
  container.appendChild(root);
2542
2996
  var emitter = createEmitter();
2543
- var paused = merged.respectReducedMotion && prefersReducedMotion$1();
2997
+ var manuallyPaused = merged.paused === true;
2998
+ var reducedPaused = false;
2999
+ var staticMode = merged.static === true;
3000
+ var contextLost = false;
2544
3001
  var disposed = false;
3002
+ var renderOnce = function renderOnce() {};
3003
+ var onContextLost = function onContextLost() {
3004
+ contextLost = true;
3005
+ emitter.emit('contextlost', {});
3006
+ };
3007
+ var onContextRestored = function onContextRestored() {
3008
+ contextLost = false;
3009
+ emitter.emit('contextrestored', {});
3010
+ renderOnce();
3011
+ wakeScheduler();
3012
+ };
2545
3013
  var applySize = function applySize() {
2546
3014
  root.style.width = parseSize(merged.width);
2547
3015
  root.style.height = parseSize(merged.height);
@@ -2562,7 +3030,11 @@ function createProgressCapsule(container) {
2562
3030
  preset: preset,
2563
3031
  emitter: emitter,
2564
3032
  options: _objectSpread2(_objectSpread2({}, merged), {}, {
2565
- draggable: effectiveDraggable
3033
+ draggable: effectiveDraggable,
3034
+ keyboard: effectiveKeyboard,
3035
+ onResize: function onResize() {
3036
+ if (manuallyPaused || reducedPaused || staticMode) renderOnce();
3037
+ }
2566
3038
  }),
2567
3039
  copy: copy,
2568
3040
  dirty: dirty
@@ -2574,8 +3046,12 @@ function createProgressCapsule(container) {
2574
3046
  canvas: canvas,
2575
3047
  preset: preset,
2576
3048
  getProgress: function getProgress() {
2577
- return controller.value;
2578
- }
3049
+ return progressRatio(controller.value, controller.min, controller.max) * 100;
3050
+ },
3051
+ dprCap: effectiveDprCap(merged.quality, merged.renderScale),
3052
+ powerPreference: merged.powerPreference,
3053
+ onContextLost: onContextLost,
3054
+ onContextRestored: onContextRestored
2579
3055
  });
2580
3056
  }
2581
3057
  if (overlay) controller.webglActive = true;else if (merged.renderer !== 'canvas2d') {
@@ -2586,17 +3062,34 @@ function createProgressCapsule(container) {
2586
3062
  });
2587
3063
  });
2588
3064
  }
2589
- var visibility = createVisibilityGuard(root);
3065
+ var visibility = createVisibilityGuard(root, wakeScheduler);
3066
+ var motionPreference = createReducedMotionPreference(merged.respectReducedMotion, function (matches) {
3067
+ reducedPaused = matches;
3068
+ if (matches) renderOnce();else wakeScheduler();
3069
+ });
3070
+ reducedPaused = motionPreference.matches();
3071
+ var isMotionPaused = function isMotionPaused() {
3072
+ return manuallyPaused || reducedPaused || staticMode || contextLost;
3073
+ };
2590
3074
  var flowTime = 0;
3075
+ var frameGate = createFrameGate(merged.fps);
3076
+ renderOnce = function renderOnce() {
3077
+ controller.draw();
3078
+ if (overlay) overlay.update(flowTime);
3079
+ };
3080
+ renderOnce();
3081
+ var offPausedChange = emitter.on('change', function () {
3082
+ if (isMotionPaused()) renderOnce();
3083
+ });
2591
3084
  var unsubscribe = subscribeScheduler(function (delta, now) {
2592
3085
  flowTime += delta;
2593
3086
  controller.update(delta, false);
2594
- if (visibility.isVisible()) {
3087
+ if (frameGate.shouldDraw(delta)) {
2595
3088
  controller.draw();
2596
3089
  if (overlay) overlay.update(flowTime);
2597
3090
  }
2598
3091
  }, function () {
2599
- return paused;
3092
+ return isMotionPaused() || !visibility.isVisible();
2600
3093
  });
2601
3094
  nextTick(function () {
2602
3095
  if (disposed) return;
@@ -2623,32 +3116,41 @@ function createProgressCapsule(container) {
2623
3116
  },
2624
3117
  setRange: function setRange(min, max) {
2625
3118
  controller.setRange(min, max);
3119
+ if (isMotionPaused()) renderOnce();
2626
3120
  return this;
2627
3121
  },
2628
3122
  setPreset: function setPreset(ref) {
2629
3123
  var next = getPreset('progress', ref);
2630
3124
  dirty.preset = true;
2631
3125
  Object.assign(preset, next);
3126
+ if (colorOverride) preset.colors = _toConsumableArray(colorOverride);
3127
+ if (edgeStyleOverride) preset.edgeStyle = edgeStyleOverride;
2632
3128
  var nextColors = preset.colors.map(normalizeColor);
2633
3129
  if (nextColors.every(Boolean)) preset.colors = nextColors;
2634
3130
  controller.preset = preset;
2635
- controller.profile = next.edgeStyle === 'tide' ? FLOW_PROFILES.tide : FLOW_PROFILES[next.id] || FLOW_PROFILES['visual-training'];
3131
+ controller.profile = preset.edgeStyle === 'tide' ? FLOW_PROFILES.tide : FLOW_PROFILES[preset.id] || FLOW_PROFILES['visual-training'];
2636
3132
  controller.flowTime = stringSeed(next.id) * 31;
2637
3133
  controller.seed = stringSeed("".concat(next.id, "-reference")) * Math.PI * 2;
2638
3134
  syncDom();
2639
3135
  if (overlay) {
2640
3136
  overlay.dispose();
3137
+ contextLost = false;
2641
3138
  overlay = attachProgressFlowOverlay({
2642
3139
  root: root,
2643
3140
  canvas: canvas,
2644
3141
  preset: preset,
2645
3142
  getProgress: function getProgress() {
2646
- return controller.value;
2647
- }
3143
+ return progressRatio(controller.value, controller.min, controller.max) * 100;
3144
+ },
3145
+ dprCap: effectiveDprCap(merged.quality, merged.renderScale),
3146
+ powerPreference: merged.powerPreference,
3147
+ onContextLost: onContextLost,
3148
+ onContextRestored: onContextRestored
2648
3149
  });
2649
3150
  }
2650
3151
  controller.webglActive = Boolean(overlay);
2651
3152
  controller.resizeCanvas();
3153
+ if (isMotionPaused()) renderOnce();
2652
3154
  emitter.emit('presetchange', {
2653
3155
  preset: _objectSpread2({}, preset)
2654
3156
  });
@@ -2658,21 +3160,28 @@ function createProgressCapsule(container) {
2658
3160
  var value = String(edgeStyle || '').toLowerCase();
2659
3161
  if (value !== 'flow' && value !== 'tide') return this;
2660
3162
  dirty.edgeStyle = true;
3163
+ edgeStyleOverride = value;
2661
3164
  preset.edgeStyle = value;
2662
3165
  controller.profile = value === 'tide' ? FLOW_PROFILES.tide : FLOW_PROFILES[preset.id] || FLOW_PROFILES['visual-training'];
2663
3166
  if (overlay) {
2664
3167
  overlay.dispose();
3168
+ contextLost = false;
2665
3169
  overlay = attachProgressFlowOverlay({
2666
3170
  root: root,
2667
3171
  canvas: canvas,
2668
3172
  preset: preset,
2669
3173
  getProgress: function getProgress() {
2670
- return controller.value;
2671
- }
3174
+ return progressRatio(controller.value, controller.min, controller.max) * 100;
3175
+ },
3176
+ dprCap: effectiveDprCap(merged.quality, merged.renderScale),
3177
+ powerPreference: merged.powerPreference,
3178
+ onContextLost: onContextLost,
3179
+ onContextRestored: onContextRestored
2672
3180
  });
2673
3181
  }
2674
3182
  controller.webglActive = Boolean(overlay);
2675
3183
  controller.resizeCanvas();
3184
+ if (isMotionPaused()) renderOnce();
2676
3185
  return this;
2677
3186
  },
2678
3187
  setText: function setText(content) {
@@ -2710,6 +3219,22 @@ function createProgressCapsule(container) {
2710
3219
  controller.setValueSuffix(suffix);
2711
3220
  return this;
2712
3221
  },
3222
+ setStep: function setStep(step) {
3223
+ controller.setStep(step);
3224
+ return this;
3225
+ },
3226
+ setPrecision: function setPrecision(precision) {
3227
+ controller.setPrecision(precision);
3228
+ return this;
3229
+ },
3230
+ setFormatValue: function setFormatValue(formatter) {
3231
+ controller.setFormatValue(formatter);
3232
+ return this;
3233
+ },
3234
+ setDirection: function setDirection(direction) {
3235
+ controller.setDirection(direction);
3236
+ return this;
3237
+ },
2713
3238
  setShowValue: function setShowValue(show) {
2714
3239
  controller.setShowValue(show);
2715
3240
  return this;
@@ -2720,9 +3245,12 @@ function createProgressCapsule(container) {
2720
3245
  return !color;
2721
3246
  })) return this;
2722
3247
  dirty.colors = true;
3248
+ colorOverride = _toConsumableArray(next);
3249
+ preset.colors = _toConsumableArray(next);
2723
3250
  controller.setColors(next);
2724
3251
  if (overlay) overlay.setColors(next);
2725
3252
  controller.resizeCanvas();
3253
+ if (isMotionPaused()) renderOnce();
2726
3254
  return this;
2727
3255
  },
2728
3256
  setSize: function setSize(width, height) {
@@ -2736,30 +3264,68 @@ function createProgressCapsule(container) {
2736
3264
  }
2737
3265
  applySize();
2738
3266
  controller.resizeCanvas();
3267
+ if (isMotionPaused()) renderOnce();
2739
3268
  return this;
2740
3269
  },
2741
3270
  randomize: function randomize() {
2742
- controller.randomize();
3271
+ flowTime = controller.randomize();
3272
+ if (isMotionPaused()) renderOnce();
2743
3273
  return this;
2744
3274
  },
2745
3275
  pause: function pause() {
2746
- paused = true;
3276
+ dirty.paused = true;
3277
+ manuallyPaused = true;
3278
+ renderOnce();
2747
3279
  return this;
2748
3280
  },
2749
3281
  resume: function resume() {
2750
- paused = false;
3282
+ dirty.paused = true;
3283
+ manuallyPaused = false;
3284
+ wakeScheduler();
3285
+ return this;
3286
+ },
3287
+ setPaused: function setPaused(value) {
3288
+ return value ? this.pause() : this.resume();
3289
+ },
3290
+ setStatic: function setStatic(value) {
3291
+ dirty.static = true;
3292
+ staticMode = value === true;
3293
+ merged.static = staticMode;
3294
+ if (staticMode) renderOnce();else wakeScheduler();
3295
+ return this;
3296
+ },
3297
+ setFps: function setFps(fps) {
3298
+ dirty.fps = true;
3299
+ merged.fps = frameGate.setFps(fps);
3300
+ wakeScheduler();
2751
3301
  return this;
2752
3302
  },
2753
3303
  setQuality: function setQuality(quality) {
3304
+ dirty.quality = true;
2754
3305
  merged.quality = quality;
2755
- controller.dprCap = dprCapFor(quality);
3306
+ controller.dprCap = effectiveDprCap(quality, merged.renderScale);
2756
3307
  controller.resizeCanvas();
3308
+ if (overlay) overlay.setDprCap(controller.dprCap);
3309
+ if (isMotionPaused()) renderOnce();
3310
+ return this;
3311
+ },
3312
+ setRenderScale: function setRenderScale(renderScale) {
3313
+ var value = Number(renderScale);
3314
+ if (!Number.isFinite(value)) return this;
3315
+ dirty.renderScale = true;
3316
+ merged.renderScale = Math.min(1, Math.max(0.25, value));
3317
+ controller.dprCap = effectiveDprCap(merged.quality, merged.renderScale);
3318
+ controller.resizeCanvas();
3319
+ if (overlay) overlay.setDprCap(controller.dprCap);
3320
+ if (isMotionPaused()) renderOnce();
2757
3321
  return this;
2758
3322
  },
2759
3323
  dispose: function dispose() {
2760
3324
  disposed = true;
2761
3325
  unsubscribe();
3326
+ offPausedChange();
2762
3327
  visibility.dispose();
3328
+ motionPreference.dispose();
2763
3329
  if (overlay) overlay.dispose();
2764
3330
  controller.dispose();
2765
3331
  root.remove();
@@ -2770,26 +3336,89 @@ function createProgressCapsule(container) {
2770
3336
  get cssVars() {
2771
3337
  return merged.cssVars;
2772
3338
  },
3339
+ get min() {
3340
+ return controller.min;
3341
+ },
3342
+ get max() {
3343
+ return controller.max;
3344
+ },
3345
+ get step() {
3346
+ return controller.step;
3347
+ },
3348
+ get precision() {
3349
+ return controller.precision;
3350
+ },
3351
+ get formatValue() {
3352
+ return controller.formatValue;
3353
+ },
3354
+ get direction() {
3355
+ return controller.direction;
3356
+ },
3357
+ get showValue() {
3358
+ return !valueElement.hidden;
3359
+ },
3360
+ get valueSuffix() {
3361
+ return controller.valueSuffix;
3362
+ },
3363
+ get quality() {
3364
+ return merged.quality;
3365
+ },
3366
+ get renderScale() {
3367
+ return merged.renderScale;
3368
+ },
3369
+ get paused() {
3370
+ return manuallyPaused;
3371
+ },
3372
+ get static() {
3373
+ return staticMode;
3374
+ },
3375
+ get fps() {
3376
+ return frameGate.getFps();
3377
+ },
2773
3378
  dirty: dirty
2774
3379
  };
2775
3380
  }
2776
3381
 
2777
- function prefersReducedMotion() {
2778
- return typeof matchMedia !== 'undefined' && matchMedia('(prefers-reduced-motion: reduce)').matches;
3382
+ var HOST_STYLES = new WeakMap();
3383
+ function acquireHostStyles(host) {
3384
+ var active = HOST_STYLES.get(host);
3385
+ if (active) {
3386
+ active.count += 1;
3387
+ return;
3388
+ }
3389
+ var state = {
3390
+ count: 1,
3391
+ position: host.style.position,
3392
+ isolation: host.style.isolation
3393
+ };
3394
+ var computed = getComputedStyle(host);
3395
+ if (computed.position === 'static' || computed.position === '') host.style.position = 'relative';
3396
+ host.style.isolation = 'isolate';
3397
+ HOST_STYLES.set(host, state);
3398
+ }
3399
+ function releaseHostStyles(host) {
3400
+ var state = HOST_STYLES.get(host);
3401
+ if (!state) return;
3402
+ state.count -= 1;
3403
+ if (state.count > 0) return;
3404
+ host.style.position = state.position;
3405
+ host.style.isolation = state.isolation;
3406
+ HOST_STYLES.delete(host);
2779
3407
  }
2780
3408
 
2781
- /**
2782
- * Mount the cosmic (nebula) material as a background layer inside `host`.
2783
- *
2784
- * The layer is absolutely positioned and defaults to `z-index: -1`, so it
2785
- * paints behind the host's in-flow content: text/buttons/images inside the
2786
- * host sit on top with zero extra CSS. Host gets `position: relative;
2787
- * isolation: isolate` automatically so the layer can never escape its box
2788
- * (or break stacking outside it).
2789
- *
3409
+ /**
3410
+ * Mount the cosmic (nebula) material as a background layer inside `host`.
3411
+ *
3412
+ * The layer is absolutely positioned and defaults to `z-index: -1`, so it
3413
+ * paints behind the host's in-flow content: text/buttons/images inside the
3414
+ * host sit on top with zero extra CSS. Host gets `position: relative;
3415
+ * isolation: isolate` automatically so the layer can never escape its box
3416
+ * (or break stacking outside it).
3417
+ *
2790
3418
  * Options: preset (literary name), colors, seed, speed, quality,
2791
- * renderer, mouseColor, respectReducedMotion, opacity (0-1), fallbackColor
2792
- * (true=preset base color, a hex string, or false to disable).
3419
+ * renderer, renderScale, powerPreference, fps, paused/static, mouseColor,
3420
+ * respectReducedMotion, opacity (0-1), fallbackColor (true=preset base
3421
+ * color, a hex string, or false to disable).
2793
3422
  */
2794
3423
  function createColorBackground(host) {
2795
3424
  var _options$preset;
@@ -2803,18 +3432,29 @@ function createColorBackground(host) {
2803
3432
  renderer: DEFAULTS.capsule.renderer,
2804
3433
  respectReducedMotion: DEFAULTS.capsule.respectReducedMotion,
2805
3434
  mouseColor: true,
3435
+ renderScale: 1,
3436
+ powerPreference: 'high-performance',
3437
+ fps: DEFAULTS.capsule.fps,
3438
+ paused: false,
3439
+ static: false,
2806
3440
  opacity: 1,
2807
3441
  fallbackColor: true
2808
3442
  }, preset, options);
2809
- var normalizedColors = merged.colors.map(normalizeColor);
2810
- if (normalizedColors.every(Boolean)) preset.colors = normalizedColors;
2811
- preset.seed = merged.seed;
2812
- preset.speed = merged.speed;
2813
- var computed = getComputedStyle(host);
2814
- if (computed.position === 'static' || computed.position === '') {
2815
- host.style.position = 'relative';
2816
- }
2817
- host.style.isolation = 'isolate';
3443
+ merged.opacity = Number.isFinite(Number(merged.opacity)) ? Math.min(1, Math.max(0, Number(merged.opacity))) : 1;
3444
+ var normalizedColors = Array.isArray(merged.colors) ? merged.colors.map(normalizeColor) : [];
3445
+ if (normalizedColors.length === 4 && normalizedColors.every(Boolean)) preset.colors = normalizedColors;
3446
+ var initialSeed = toFiniteNumber(merged.seed);
3447
+ var initialSpeed = toFiniteNumber(merged.speed);
3448
+ if (initialSeed !== null) preset.seed = initialSeed;
3449
+ if (initialSpeed !== null) preset.speed = initialSpeed;
3450
+ merged.colors = _toConsumableArray(preset.colors);
3451
+ merged.seed = preset.seed;
3452
+ merged.speed = preset.speed;
3453
+ var optionColors = Array.isArray(options.colors) ? options.colors.map(normalizeColor) : [];
3454
+ var colorOverride = optionColors.length === 4 && optionColors.every(Boolean) ? _toConsumableArray(optionColors) : null;
3455
+ var seedOverride = options.seed !== undefined ? toFiniteNumber(options.seed) : null;
3456
+ var speedOverride = options.speed !== undefined ? toFiniteNumber(options.speed) : null;
3457
+ acquireHostStyles(host);
2818
3458
  var layer = document.createElement('div');
2819
3459
  layer.className = 'dlc-color-layer';
2820
3460
  var syncLayerVars = function syncLayerVars() {
@@ -2829,8 +3469,12 @@ function createColorBackground(host) {
2829
3469
  layer.appendChild(canvas);
2830
3470
  host.appendChild(layer);
2831
3471
  var emitter = createEmitter();
2832
- var paused = merged.respectReducedMotion && prefersReducedMotion();
3472
+ var manuallyPaused = merged.paused === true;
3473
+ var reducedPaused = false;
3474
+ var staticMode = merged.static === true;
3475
+ var contextLost = false;
2833
3476
  var disposed = false;
3477
+ var renderOnce = function renderOnce() {};
2834
3478
  var dirty = {
2835
3479
  preset: false,
2836
3480
  seed: false,
@@ -2838,19 +3482,37 @@ function createColorBackground(host) {
2838
3482
  colors: false,
2839
3483
  opacity: false,
2840
3484
  fallbackColor: false,
2841
- mouseColor: false
3485
+ mouseColor: false,
3486
+ quality: false,
3487
+ renderScale: false,
3488
+ paused: false,
3489
+ static: false,
3490
+ fps: false
2842
3491
  };
2843
3492
  var renderer;
2844
3493
  var useWebgl = merged.renderer !== 'canvas2d';
2845
3494
  if (useWebgl) {
2846
3495
  try {
2847
3496
  renderer = new CosmicRenderer(canvas, merged, {
2848
- dprCap: dprCapFor(merged.quality),
3497
+ dprCap: effectiveDprCap(merged.quality, merged.renderScale),
2849
3498
  mouseColor: merged.mouseColor !== false,
2850
- eventTarget: host
3499
+ eventTarget: host,
3500
+ powerPreference: merged.powerPreference,
3501
+ onContextLost: function onContextLost() {
3502
+ contextLost = true;
3503
+ emitter.emit('contextlost', {});
3504
+ },
3505
+ onContextRestored: function onContextRestored() {
3506
+ contextLost = false;
3507
+ emitter.emit('contextrestored', {});
3508
+ renderOnce();
3509
+ wakeScheduler();
3510
+ }
2851
3511
  });
2852
3512
  } catch (error) {
2853
- renderer = new FallbackRenderer(canvas, merged);
3513
+ renderer = new FallbackRenderer(canvas, merged, {
3514
+ dprCap: effectiveDprCap(merged.quality, merged.renderScale)
3515
+ });
2854
3516
  nextTick(function () {
2855
3517
  if (disposed) return;
2856
3518
  emitter.emit('error', {
@@ -2859,19 +3521,37 @@ function createColorBackground(host) {
2859
3521
  });
2860
3522
  }
2861
3523
  } else {
2862
- renderer = new FallbackRenderer(canvas, merged);
3524
+ renderer = new FallbackRenderer(canvas, merged, {
3525
+ dprCap: effectiveDprCap(merged.quality, merged.renderScale)
3526
+ });
2863
3527
  }
2864
- var resizeObserver = typeof ResizeObserver !== 'undefined' ? new ResizeObserver(function () {
2865
- return renderer.resize();
2866
- }) : null;
2867
- if (resizeObserver) resizeObserver.observe(host);else window.addEventListener('resize', renderer.resize);
2868
- var visibility = createVisibilityGuard(layer);
3528
+ renderer.resize();
2869
3529
  var animationTime = 0;
3530
+ var frameGate = createFrameGate(merged.fps);
3531
+ renderOnce = function renderOnce() {
3532
+ return renderer.draw(animationTime);
3533
+ };
3534
+ var resize = function resize() {
3535
+ renderer.resize();
3536
+ if (manuallyPaused || reducedPaused || staticMode) renderOnce();
3537
+ };
3538
+ var resizeObserver = typeof ResizeObserver !== 'undefined' ? new ResizeObserver(resize) : null;
3539
+ if (resizeObserver) resizeObserver.observe(host);else window.addEventListener('resize', resize);
3540
+ var visibility = createVisibilityGuard(layer, wakeScheduler);
3541
+ var motionPreference = createReducedMotionPreference(merged.respectReducedMotion, function (matches) {
3542
+ reducedPaused = matches;
3543
+ if (matches) renderOnce();else wakeScheduler();
3544
+ });
3545
+ reducedPaused = motionPreference.matches();
3546
+ var isMotionPaused = function isMotionPaused() {
3547
+ return manuallyPaused || reducedPaused || staticMode || contextLost;
3548
+ };
3549
+ renderOnce();
2870
3550
  var unsubscribe = subscribeScheduler(function (delta) {
2871
3551
  animationTime += delta;
2872
- if (visibility.isVisible()) renderer.draw(animationTime);
3552
+ if (frameGate.shouldDraw(delta)) renderer.draw(animationTime);
2873
3553
  }, function () {
2874
- return paused;
3554
+ return isMotionPaused() || !visibility.isVisible();
2875
3555
  });
2876
3556
  nextTick(function () {
2877
3557
  if (disposed) return;
@@ -2890,11 +3570,15 @@ function createColorBackground(host) {
2890
3570
  var next = getPreset('capsule', ref);
2891
3571
  dirty.preset = true;
2892
3572
  Object.assign(preset, next);
3573
+ if (colorOverride) preset.colors = _toConsumableArray(colorOverride);
3574
+ if (seedOverride !== null) preset.seed = seedOverride;
3575
+ if (speedOverride !== null) preset.speed = speedOverride;
2893
3576
  var nextColors = preset.colors.map(normalizeColor);
2894
3577
  if (nextColors.every(Boolean)) preset.colors = nextColors;
2895
3578
  renderer.setPreset(_objectSpread2({}, preset));
2896
3579
  renderer.resize();
2897
3580
  syncLayerVars();
3581
+ if (isMotionPaused()) renderOnce();
2898
3582
  emitter.emit('presetchange', {
2899
3583
  preset: _objectSpread2({}, preset)
2900
3584
  });
@@ -2906,27 +3590,33 @@ function createColorBackground(host) {
2906
3590
  return !color;
2907
3591
  })) return this;
2908
3592
  dirty.colors = true;
3593
+ colorOverride = _toConsumableArray(next);
2909
3594
  preset.colors = next;
2910
3595
  renderer.setPreset(_objectSpread2(_objectSpread2({}, preset), {}, {
2911
3596
  colors: next
2912
3597
  }));
2913
3598
  syncLayerVars();
3599
+ if (isMotionPaused()) renderOnce();
2914
3600
  return this;
2915
3601
  },
2916
3602
  setSeed: function setSeed(seed) {
2917
- var value = Number(seed);
2918
- if (!Number.isFinite(value)) return this;
3603
+ var value = toFiniteNumber(seed);
3604
+ if (value === null) return this;
2919
3605
  dirty.seed = true;
3606
+ seedOverride = value;
2920
3607
  preset.seed = value;
2921
3608
  renderer.setPreset(_objectSpread2({}, preset));
3609
+ if (isMotionPaused()) renderOnce();
2922
3610
  return this;
2923
3611
  },
2924
3612
  setSpeed: function setSpeed(speed) {
2925
- var value = Number(speed);
2926
- if (!Number.isFinite(value)) return this;
3613
+ var value = toFiniteNumber(speed);
3614
+ if (value === null) return this;
2927
3615
  dirty.speed = true;
3616
+ speedOverride = value;
2928
3617
  preset.speed = value;
2929
3618
  renderer.setPreset(_objectSpread2({}, preset));
3619
+ if (isMotionPaused()) renderOnce();
2930
3620
  return this;
2931
3621
  },
2932
3622
  setFallbackColor: function setFallbackColor(value) {
@@ -2942,8 +3632,23 @@ function createColorBackground(host) {
2942
3632
  return this;
2943
3633
  },
2944
3634
  setQuality: function setQuality(quality) {
3635
+ dirty.quality = true;
2945
3636
  merged.quality = quality;
2946
- if (typeof renderer.setDprCap === 'function') renderer.setDprCap(dprCapFor(quality));
3637
+ if (typeof renderer.setDprCap === 'function') {
3638
+ renderer.setDprCap(effectiveDprCap(quality, merged.renderScale));
3639
+ }
3640
+ if (isMotionPaused()) renderOnce();
3641
+ return this;
3642
+ },
3643
+ setRenderScale: function setRenderScale(renderScale) {
3644
+ var value = Number(renderScale);
3645
+ if (!Number.isFinite(value)) return this;
3646
+ dirty.renderScale = true;
3647
+ merged.renderScale = Math.min(1, Math.max(0.25, value));
3648
+ if (typeof renderer.setDprCap === 'function') {
3649
+ renderer.setDprCap(effectiveDprCap(merged.quality, merged.renderScale));
3650
+ }
3651
+ if (isMotionPaused()) renderOnce();
2947
3652
  return this;
2948
3653
  },
2949
3654
  setOpacity: function setOpacity(value) {
@@ -2959,20 +3664,42 @@ function createColorBackground(host) {
2959
3664
  return this;
2960
3665
  },
2961
3666
  pause: function pause() {
2962
- paused = true;
3667
+ dirty.paused = true;
3668
+ manuallyPaused = true;
3669
+ renderOnce();
2963
3670
  return this;
2964
3671
  },
2965
3672
  resume: function resume() {
2966
- paused = false;
3673
+ dirty.paused = true;
3674
+ manuallyPaused = false;
3675
+ wakeScheduler();
3676
+ return this;
3677
+ },
3678
+ setPaused: function setPaused(value) {
3679
+ return value ? this.pause() : this.resume();
3680
+ },
3681
+ setStatic: function setStatic(value) {
3682
+ dirty.static = true;
3683
+ staticMode = value === true;
3684
+ merged.static = staticMode;
3685
+ if (staticMode) renderOnce();else wakeScheduler();
3686
+ return this;
3687
+ },
3688
+ setFps: function setFps(fps) {
3689
+ dirty.fps = true;
3690
+ merged.fps = frameGate.setFps(fps);
3691
+ wakeScheduler();
2967
3692
  return this;
2968
3693
  },
2969
3694
  dispose: function dispose() {
2970
3695
  disposed = true;
2971
3696
  unsubscribe();
2972
3697
  visibility.dispose();
2973
- if (resizeObserver) resizeObserver.disconnect();else window.removeEventListener('resize', renderer.resize);
3698
+ motionPreference.dispose();
3699
+ if (resizeObserver) resizeObserver.disconnect();else window.removeEventListener('resize', resize);
2974
3700
  renderer.dispose();
2975
3701
  layer.remove();
3702
+ releaseHostStyles(host);
2976
3703
  },
2977
3704
  get opacity() {
2978
3705
  return merged.opacity;
@@ -2983,31 +3710,51 @@ function createColorBackground(host) {
2983
3710
  get mouseColor() {
2984
3711
  return merged.mouseColor;
2985
3712
  },
3713
+ get quality() {
3714
+ return merged.quality;
3715
+ },
3716
+ get renderScale() {
3717
+ return merged.renderScale;
3718
+ },
3719
+ get paused() {
3720
+ return manuallyPaused;
3721
+ },
3722
+ get static() {
3723
+ return staticMode;
3724
+ },
3725
+ get fps() {
3726
+ return frameGate.getFps();
3727
+ },
2986
3728
  dirty: dirty
2987
3729
  };
2988
3730
  }
2989
3731
 
2990
- /**
2991
- * Shared Options-API wrapper factory. The only framework difference is the
2992
- * render function: Vue2 passes `h` as an argument, Vue3 needs the imported
2993
- * `h` (see vue2.js / vue3.js). Lifecycle options cover both.
3732
+ /**
3733
+ * Shared Options-API wrapper factory. The only framework difference is the
3734
+ * render function: Vue2 passes `h` as an argument, Vue3 needs the imported
3735
+ * `h` (see vue2.js / vue3.js). Lifecycle options cover both.
2994
3736
  */
2995
3737
 
2996
- var CAPSULE_EVENTS = ['ready', 'error', 'click', 'pointerdown', 'pointerup', 'dblclick', 'pointerenter', 'pointerleave', 'presetchange'];
2997
- var PROGRESS_EVENTS = ['ready', 'error', 'change', 'dragstart', 'dragend', 'presetchange'];
2998
- var COLOR_EVENTS = ['ready', 'error', 'presetchange'];
3738
+ var CAPSULE_EVENTS = ['ready', 'error', 'click', 'pointerdown', 'pointerup', 'dblclick', 'pointerenter', 'pointerleave', 'presetchange', 'contextlost', 'contextrestored'];
3739
+ var PROGRESS_EVENTS = ['ready', 'error', 'change', 'input', 'update:modelValue', 'dragstart', 'dragend', 'presetchange', 'contextlost', 'contextrestored'];
3740
+ var COLOR_EVENTS = ['ready', 'error', 'presetchange', 'contextlost', 'contextrestored'];
2999
3741
  function hookEvents(controller, events, emit) {
3000
3742
  var _iterator = _createForOfIteratorHelper(events),
3001
3743
  _step;
3002
3744
  try {
3003
3745
  var _loop = function _loop() {
3004
3746
  var event = _step.value;
3747
+ if (event === 'input' || event === 'update:modelValue') return 1; // continue
3005
3748
  controller.on(event, function (payload) {
3006
- return emit(event, payload);
3749
+ emit(event, payload);
3750
+ if (event === 'change' && payload && (payload.source === 'drag' || payload.source === 'keyboard')) {
3751
+ if (events.indexOf('input') !== -1) emit('input', payload.value);
3752
+ if (events.indexOf('update:modelValue') !== -1) emit('update:modelValue', payload.value);
3753
+ }
3007
3754
  });
3008
3755
  };
3009
3756
  for (_iterator.s(); !(_step = _iterator.n()).done;) {
3010
- _loop();
3757
+ if (_loop()) continue;
3011
3758
  }
3012
3759
  } catch (err) {
3013
3760
  _iterator.e(err);
@@ -3098,6 +3845,17 @@ function makeWrapper(_ref) {
3098
3845
  if (dirty.opacity) state.opacity = controller.opacity;
3099
3846
  if (dirty.fallbackColor) state.fallbackColor = controller.fallbackColor;
3100
3847
  if (dirty.mouseColor) state.mouseColor = controller.mouseColor;
3848
+ if (dirty.quality) state.quality = controller.quality;
3849
+ if (dirty.renderScale) state.renderScale = controller.renderScale;
3850
+ if (dirty.paused) state.paused = controller.paused;
3851
+ if (dirty.static) state.static = controller.static;
3852
+ if (dirty.fps) state.fps = controller.fps;
3853
+ if (dirty.step) state.step = controller.step;
3854
+ if (dirty.precision) state.precision = controller.precision;
3855
+ if (dirty.formatValue) state.formatValue = controller.formatValue;
3856
+ if (dirty.direction) state.direction = controller.direction;
3857
+ if (dirty.showValue) state.showValue = controller.showValue;
3858
+ if (dirty.valueSuffix) state.valueSuffix = controller.valueSuffix;
3101
3859
  return state;
3102
3860
  }
3103
3861
  };
@@ -3143,7 +3901,7 @@ function makeWrapper(_ref) {
3143
3901
  function makeCapsuleWrapper(createCapsule, render) {
3144
3902
  return makeWrapper({
3145
3903
  name: 'dlc-capsule',
3146
- props: ['preset', 'width', 'height', 'colors', 'seed', 'speed', 'textRatio', 'label', 'mouseColor', 'renderer', 'quality', 'respectReducedMotion', 'cssVars'],
3904
+ props: ['preset', 'width', 'height', 'colors', 'seed', 'speed', 'textRatio', 'label', 'mouseColor', 'renderer', 'quality', 'respectReducedMotion', 'cssVars', 'paused', 'static', 'fps', 'renderScale', 'powerPreference'],
3147
3905
  events: CAPSULE_EVENTS,
3148
3906
  create: createCapsule,
3149
3907
  render: render,
@@ -3172,8 +3930,26 @@ function makeCapsuleWrapper(createCapsule, render) {
3172
3930
  mouseColor: function mouseColor(value) {
3173
3931
  if (this.controller) this.controller.setMouseColor(value);
3174
3932
  },
3933
+ paused: function paused(value) {
3934
+ if (this.controller) this.controller.setPaused(value);
3935
+ },
3936
+ static: function _static(value) {
3937
+ if (this.controller) this.controller.setStatic(value);
3938
+ },
3939
+ fps: function fps(value) {
3940
+ if (value !== undefined && this.controller) this.controller.setFps(value);
3941
+ },
3942
+ renderScale: function renderScale(value) {
3943
+ if (value !== undefined && this.controller) this.controller.setRenderScale(value);
3944
+ },
3175
3945
  renderer: function renderer() {
3176
3946
  this.scheduleRecreate();
3947
+ },
3948
+ powerPreference: function powerPreference() {
3949
+ this.scheduleRecreate();
3950
+ },
3951
+ respectReducedMotion: function respectReducedMotion() {
3952
+ this.scheduleRecreate();
3177
3953
  }
3178
3954
  },
3179
3955
  methods: {
@@ -3216,6 +3992,18 @@ function makeCapsuleWrapper(createCapsule, render) {
3216
3992
  setQuality: function setQuality(quality) {
3217
3993
  return this.controller && this.controller.setQuality(quality);
3218
3994
  },
3995
+ setRenderScale: function setRenderScale(value) {
3996
+ return this.controller && this.controller.setRenderScale(value);
3997
+ },
3998
+ setPaused: function setPaused(value) {
3999
+ return this.controller && this.controller.setPaused(value);
4000
+ },
4001
+ setStatic: function setStatic(value) {
4002
+ return this.controller && this.controller.setStatic(value);
4003
+ },
4004
+ setFps: function setFps(value) {
4005
+ return this.controller && this.controller.setFps(value);
4006
+ },
3219
4007
  getController: function getController() {
3220
4008
  return this.controller;
3221
4009
  }
@@ -3225,13 +4013,16 @@ function makeCapsuleWrapper(createCapsule, render) {
3225
4013
  function makeProgressWrapper(createProgressCapsule, render) {
3226
4014
  return makeWrapper({
3227
4015
  name: 'dlc-progress',
3228
- props: ['preset', 'width', 'height', 'value', 'min', 'max', 'draggable', 'disabled', 'readonly', 'edgeStyle', 'colors', 'textRatio', 'label', 'showValue', 'valueSuffix', 'quality', 'renderer', 'respectReducedMotion', 'cssVars'],
4016
+ props: ['preset', 'width', 'height', 'value', 'modelValue', 'min', 'max', 'step', 'draggable', 'disabled', 'readonly', 'edgeStyle', 'colors', 'textRatio', 'label', 'showValue', 'valueSuffix', 'keyboard', 'direction', 'precision', 'formatValue', 'quality', 'renderer', 'respectReducedMotion', 'cssVars', 'paused', 'static', 'fps', 'renderScale', 'powerPreference'],
3229
4017
  events: PROGRESS_EVENTS,
3230
4018
  create: createProgressCapsule,
3231
4019
  render: render,
3232
4020
  watch: {
3233
4021
  value: function value(_value) {
3234
- if (_value !== undefined && this.controller) this.controller.setValue(_value);
4022
+ if (_value !== undefined && this.modelValue === undefined && this.controller) this.controller.setValue(_value);
4023
+ },
4024
+ modelValue: function modelValue(value) {
4025
+ if (value !== undefined && this.controller) this.controller.setValue(value);
3235
4026
  },
3236
4027
  min: function min(value) {
3237
4028
  if (value !== undefined && this.controller) this.controller.setRange(value, this.controller.max);
@@ -3239,6 +4030,9 @@ function makeProgressWrapper(createProgressCapsule, render) {
3239
4030
  max: function max(value) {
3240
4031
  if (value !== undefined && this.controller) this.controller.setRange(this.controller.min, value);
3241
4032
  },
4033
+ step: function step(value) {
4034
+ if (value !== undefined && this.controller) this.controller.setStep(value);
4035
+ },
3242
4036
  edgeStyle: function edgeStyle(value) {
3243
4037
  if (value && this.controller) this.controller.setEdgeStyle(value);
3244
4038
  },
@@ -3257,6 +4051,27 @@ function makeProgressWrapper(createProgressCapsule, render) {
3257
4051
  showValue: function showValue(value) {
3258
4052
  if (this.controller) this.controller.setShowValue(value);
3259
4053
  },
4054
+ direction: function direction(value) {
4055
+ if (value && this.controller) this.controller.setDirection(value);
4056
+ },
4057
+ precision: function precision(value) {
4058
+ if (value !== undefined && this.controller) this.controller.setPrecision(value);
4059
+ },
4060
+ formatValue: function formatValue(value) {
4061
+ if (this.controller) this.controller.setFormatValue(value);
4062
+ },
4063
+ paused: function paused(value) {
4064
+ if (this.controller) this.controller.setPaused(value);
4065
+ },
4066
+ static: function _static(value) {
4067
+ if (this.controller) this.controller.setStatic(value);
4068
+ },
4069
+ fps: function fps(value) {
4070
+ if (value !== undefined && this.controller) this.controller.setFps(value);
4071
+ },
4072
+ renderScale: function renderScale(value) {
4073
+ if (value !== undefined && this.controller) this.controller.setRenderScale(value);
4074
+ },
3260
4075
  disabled: function disabled() {
3261
4076
  this.scheduleRecreate();
3262
4077
  },
@@ -3268,6 +4083,15 @@ function makeProgressWrapper(createProgressCapsule, render) {
3268
4083
  },
3269
4084
  renderer: function renderer() {
3270
4085
  this.scheduleRecreate();
4086
+ },
4087
+ keyboard: function keyboard() {
4088
+ this.scheduleRecreate();
4089
+ },
4090
+ powerPreference: function powerPreference() {
4091
+ this.scheduleRecreate();
4092
+ },
4093
+ respectReducedMotion: function respectReducedMotion() {
4094
+ this.scheduleRecreate();
3271
4095
  }
3272
4096
  },
3273
4097
  methods: {
@@ -3280,6 +4104,9 @@ function makeProgressWrapper(createProgressCapsule, render) {
3280
4104
  setRange: function setRange(min, max) {
3281
4105
  return this.controller && this.controller.setRange(min, max);
3282
4106
  },
4107
+ setStep: function setStep(step) {
4108
+ return this.controller && this.controller.setStep(step);
4109
+ },
3283
4110
  randomize: function randomize() {
3284
4111
  return this.controller && this.controller.randomize();
3285
4112
  },
@@ -3319,9 +4146,30 @@ function makeProgressWrapper(createProgressCapsule, render) {
3319
4146
  setShowValue: function setShowValue(show) {
3320
4147
  return this.controller && this.controller.setShowValue(show);
3321
4148
  },
4149
+ setDirection: function setDirection(direction) {
4150
+ return this.controller && this.controller.setDirection(direction);
4151
+ },
4152
+ setPrecision: function setPrecision(precision) {
4153
+ return this.controller && this.controller.setPrecision(precision);
4154
+ },
4155
+ setFormatValue: function setFormatValue(formatter) {
4156
+ return this.controller && this.controller.setFormatValue(formatter);
4157
+ },
3322
4158
  setQuality: function setQuality(quality) {
3323
4159
  return this.controller && this.controller.setQuality(quality);
3324
4160
  },
4161
+ setRenderScale: function setRenderScale(value) {
4162
+ return this.controller && this.controller.setRenderScale(value);
4163
+ },
4164
+ setPaused: function setPaused(value) {
4165
+ return this.controller && this.controller.setPaused(value);
4166
+ },
4167
+ setStatic: function setStatic(value) {
4168
+ return this.controller && this.controller.setStatic(value);
4169
+ },
4170
+ setFps: function setFps(value) {
4171
+ return this.controller && this.controller.setFps(value);
4172
+ },
3325
4173
  getController: function getController() {
3326
4174
  return this.controller;
3327
4175
  }
@@ -3331,7 +4179,7 @@ function makeProgressWrapper(createProgressCapsule, render) {
3331
4179
  function makeColorWrapper(createColorBackground, render) {
3332
4180
  return makeWrapper({
3333
4181
  name: 'dlc-color',
3334
- props: ['preset', 'colors', 'seed', 'speed', 'quality', 'renderer', 'mouseColor', 'respectReducedMotion', 'opacity', 'fallbackColor'],
4182
+ props: ['preset', 'colors', 'seed', 'speed', 'quality', 'renderer', 'mouseColor', 'respectReducedMotion', 'opacity', 'fallbackColor', 'paused', 'static', 'fps', 'renderScale', 'powerPreference'],
3335
4183
  events: COLOR_EVENTS,
3336
4184
  create: createColorBackground,
3337
4185
  render: render,
@@ -3353,11 +4201,26 @@ function makeColorWrapper(createColorBackground, render) {
3353
4201
  mouseColor: function mouseColor(value) {
3354
4202
  if (this.controller) this.controller.setMouseColor(value);
3355
4203
  },
4204
+ paused: function paused(value) {
4205
+ if (this.controller) this.controller.setPaused(value);
4206
+ },
4207
+ static: function _static(value) {
4208
+ if (this.controller) this.controller.setStatic(value);
4209
+ },
4210
+ fps: function fps(value) {
4211
+ if (value !== undefined && this.controller) this.controller.setFps(value);
4212
+ },
4213
+ renderScale: function renderScale(value) {
4214
+ if (value !== undefined && this.controller) this.controller.setRenderScale(value);
4215
+ },
3356
4216
  renderer: function renderer() {
3357
4217
  this.scheduleRecreate();
3358
4218
  },
3359
4219
  respectReducedMotion: function respectReducedMotion() {
3360
4220
  this.scheduleRecreate();
4221
+ },
4222
+ powerPreference: function powerPreference() {
4223
+ this.scheduleRecreate();
3361
4224
  }
3362
4225
  },
3363
4226
  methods: {
@@ -3376,6 +4239,9 @@ function makeColorWrapper(createColorBackground, render) {
3376
4239
  setQuality: function setQuality(quality) {
3377
4240
  return this.controller && this.controller.setQuality(quality);
3378
4241
  },
4242
+ setRenderScale: function setRenderScale(value) {
4243
+ return this.controller && this.controller.setRenderScale(value);
4244
+ },
3379
4245
  setOpacity: function setOpacity(value) {
3380
4246
  return this.controller && this.controller.setOpacity(value);
3381
4247
  },
@@ -3394,6 +4260,15 @@ function makeColorWrapper(createColorBackground, render) {
3394
4260
  resume: function resume() {
3395
4261
  return this.controller && this.controller.resume();
3396
4262
  },
4263
+ setPaused: function setPaused(value) {
4264
+ return this.controller && this.controller.setPaused(value);
4265
+ },
4266
+ setStatic: function setStatic(value) {
4267
+ return this.controller && this.controller.setStatic(value);
4268
+ },
4269
+ setFps: function setFps(value) {
4270
+ return this.controller && this.controller.setFps(value);
4271
+ },
3397
4272
  getController: function getController() {
3398
4273
  return this.controller;
3399
4274
  }