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