@5even7/dlc-ui 0.1.0

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.
@@ -0,0 +1,1751 @@
1
+ 'use strict';
2
+
3
+ function _arrayLikeToArray(r, a) {
4
+ (null == a || a > r.length) && (a = r.length);
5
+ for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
6
+ return n;
7
+ }
8
+ function _arrayWithHoles(r) {
9
+ if (Array.isArray(r)) return r;
10
+ }
11
+ function _arrayWithoutHoles(r) {
12
+ if (Array.isArray(r)) return _arrayLikeToArray(r);
13
+ }
14
+ function _classCallCheck(a, n) {
15
+ if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function");
16
+ }
17
+ function _defineProperties(e, r) {
18
+ for (var t = 0; t < r.length; t++) {
19
+ var o = r[t];
20
+ o.enumerable = o.enumerable || false, o.configurable = true, "value" in o && (o.writable = true), Object.defineProperty(e, _toPropertyKey(o.key), o);
21
+ }
22
+ }
23
+ function _createClass(e, r, t) {
24
+ return r && _defineProperties(e.prototype, r), Object.defineProperty(e, "prototype", {
25
+ writable: false
26
+ }), e;
27
+ }
28
+ function _createForOfIteratorHelper(r, e) {
29
+ var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
30
+ if (!t) {
31
+ if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e) {
32
+ t && (r = t);
33
+ var n = 0,
34
+ F = function () {};
35
+ return {
36
+ s: F,
37
+ n: function () {
38
+ return n >= r.length ? {
39
+ done: true
40
+ } : {
41
+ done: false,
42
+ value: r[n++]
43
+ };
44
+ },
45
+ e: function (r) {
46
+ throw r;
47
+ },
48
+ f: F
49
+ };
50
+ }
51
+ throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
52
+ }
53
+ var o,
54
+ a = true,
55
+ u = false;
56
+ return {
57
+ s: function () {
58
+ t = t.call(r);
59
+ },
60
+ n: function () {
61
+ var r = t.next();
62
+ return a = r.done, r;
63
+ },
64
+ e: function (r) {
65
+ u = true, o = r;
66
+ },
67
+ f: function () {
68
+ try {
69
+ a || null == t.return || t.return();
70
+ } finally {
71
+ if (u) throw o;
72
+ }
73
+ }
74
+ };
75
+ }
76
+ function _defineProperty(e, r, t) {
77
+ return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
78
+ value: t,
79
+ enumerable: true,
80
+ configurable: true,
81
+ writable: true
82
+ }) : e[r] = t, e;
83
+ }
84
+ function _iterableToArray(r) {
85
+ if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r);
86
+ }
87
+ function _iterableToArrayLimit(r, l) {
88
+ var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
89
+ if (null != t) {
90
+ var e,
91
+ n,
92
+ i,
93
+ u,
94
+ a = [],
95
+ f = true,
96
+ o = false;
97
+ try {
98
+ if (i = (t = t.call(r)).next, 0 === l) ; else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
99
+ } catch (r) {
100
+ o = true, n = r;
101
+ } finally {
102
+ try {
103
+ if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
104
+ } finally {
105
+ if (o) throw n;
106
+ }
107
+ }
108
+ return a;
109
+ }
110
+ }
111
+ function _nonIterableRest() {
112
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
113
+ }
114
+ function _nonIterableSpread() {
115
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
116
+ }
117
+ function ownKeys(e, r) {
118
+ var t = Object.keys(e);
119
+ if (Object.getOwnPropertySymbols) {
120
+ var o = Object.getOwnPropertySymbols(e);
121
+ r && (o = o.filter(function (r) {
122
+ return Object.getOwnPropertyDescriptor(e, r).enumerable;
123
+ })), t.push.apply(t, o);
124
+ }
125
+ return t;
126
+ }
127
+ function _objectSpread2(e) {
128
+ for (var r = 1; r < arguments.length; r++) {
129
+ var t = null != arguments[r] ? arguments[r] : {};
130
+ r % 2 ? ownKeys(Object(t), true).forEach(function (r) {
131
+ _defineProperty(e, r, t[r]);
132
+ }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {
133
+ Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
134
+ });
135
+ }
136
+ return e;
137
+ }
138
+ function _slicedToArray(r, e) {
139
+ return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
140
+ }
141
+ function _toConsumableArray(r) {
142
+ return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread();
143
+ }
144
+ function _toPrimitive(t, r) {
145
+ if ("object" != typeof t || !t) return t;
146
+ var e = t[Symbol.toPrimitive];
147
+ if (void 0 !== e) {
148
+ var i = e.call(t, r);
149
+ if ("object" != typeof i) return i;
150
+ throw new TypeError("@@toPrimitive must return a primitive value.");
151
+ }
152
+ return ("string" === r ? String : Number)(t);
153
+ }
154
+ function _toPropertyKey(t) {
155
+ var i = _toPrimitive(t, "string");
156
+ return "symbol" == typeof i ? i : i + "";
157
+ }
158
+ function _typeof(o) {
159
+ "@babel/helpers - typeof";
160
+
161
+ return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
162
+ return typeof o;
163
+ } : function (o) {
164
+ return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
165
+ }, _typeof(o);
166
+ }
167
+ function _unsupportedIterableToArray(r, a) {
168
+ if (r) {
169
+ if ("string" == typeof r) return _arrayLikeToArray(r, a);
170
+ var t = {}.toString.call(r).slice(8, -1);
171
+ return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
172
+ }
173
+ }
174
+
175
+ /**
176
+ * Tiny event emitter. Accepts any event name so the API stays open for
177
+ * future events (hover, click, custom) without breaking changes.
178
+ */
179
+ function createEmitter() {
180
+ // Plain object storage (no Map/Set) so the legacy build has no API
181
+ // dependencies beyond what IE11 provides.
182
+ var listeners = Object.create(null);
183
+ return {
184
+ on: function on(event, fn) {
185
+ if (!listeners[event]) listeners[event] = [];
186
+ listeners[event].push(fn);
187
+ return function () {
188
+ var current = listeners[event];
189
+ if (current) {
190
+ var index = current.indexOf(fn);
191
+ if (index !== -1) current.splice(index, 1);
192
+ }
193
+ };
194
+ },
195
+ off: function off(event, fn) {
196
+ var current = listeners[event];
197
+ if (!current) return false;
198
+ var index = current.indexOf(fn);
199
+ if (index === -1) return false;
200
+ current.splice(index, 1);
201
+ return true;
202
+ },
203
+ emit: function emit(event) {
204
+ var current = listeners[event];
205
+ if (!current) return;
206
+ for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
207
+ args[_key - 1] = arguments[_key];
208
+ }
209
+ var _iterator = _createForOfIteratorHelper(current.slice()),
210
+ _step;
211
+ try {
212
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
213
+ var fn = _step.value;
214
+ fn.apply(void 0, args);
215
+ }
216
+ } catch (err) {
217
+ _iterator.e(err);
218
+ } finally {
219
+ _iterator.f();
220
+ }
221
+ }
222
+ };
223
+ }
224
+
225
+ var UNIT_PATTERN = /^[\d.]+(?:px|%|vw|vh|vmin|vmax|em|rem)$/;
226
+
227
+ /**
228
+ * Normalize a size option to a CSS length string.
229
+ * Accepts numbers (treated as px) or strings with px/%, vw/vh/vmin/vmax, em/rem.
230
+ */
231
+ function parseSize(value) {
232
+ if (typeof value === 'number') {
233
+ if (!Number.isFinite(value) || value < 0) throw new Error("Invalid size: ".concat(value));
234
+ return "".concat(value, "px");
235
+ }
236
+ if (typeof value !== 'string') throw new Error("Invalid size: ".concat(String(value)));
237
+ var trimmed = value.trim();
238
+ if (!trimmed) throw new Error('Invalid size: empty string');
239
+ if (/^\d+(?:\.\d+)?$/.test(trimmed)) return "".concat(trimmed, "px");
240
+ if (!UNIT_PATTERN.test(trimmed)) {
241
+ throw new Error("Invalid size or unsupported unit: \"".concat(value, "\" (use px, %, vw, vh, vmin, vmax, em, rem)"));
242
+ }
243
+ return trimmed;
244
+ }
245
+
246
+ var QUALITY_TIERS = {
247
+ low: {
248
+ dpr: 1
249
+ },
250
+ medium: {
251
+ dpr: 1.5
252
+ },
253
+ high: {
254
+ dpr: 2
255
+ }
256
+ };
257
+ function autoDprCap() {
258
+ var nav = typeof navigator !== 'undefined' ? navigator : null;
259
+ var memory = nav && typeof nav.deviceMemory === 'number' ? nav.deviceMemory : 8;
260
+ var cores = nav && typeof nav.hardwareConcurrency === 'number' ? nav.hardwareConcurrency : 8;
261
+ return memory <= 4 || cores <= 4 ? 1.5 : 2;
262
+ }
263
+ function dprCapFor(quality) {
264
+ if (quality === 'auto') return autoDprCap();
265
+ var tier = QUALITY_TIERS[quality] || QUALITY_TIERS.medium;
266
+ return tier.dpr;
267
+ }
268
+
269
+ /**
270
+ * Merge defaults < preset < user. Unknown user keys are preserved so the
271
+ * component API can grow (new props, cssVars, callbacks) without a breaking
272
+ * change.
273
+ */
274
+ function normalizeOptions(defaults, preset, user) {
275
+ // undefined means "not provided" (e.g. Vue $props with unset props):
276
+ // drop those keys before merging so defaults/preset values survive.
277
+ var omitUndefined = function omitUndefined(source) {
278
+ var result = {};
279
+ for (var _i = 0, _Object$keys = Object.keys(source); _i < _Object$keys.length; _i++) {
280
+ var key = _Object$keys[_i];
281
+ if (source[key] !== undefined) result[key] = source[key];
282
+ }
283
+ return result;
284
+ };
285
+ var presetOptions = omitUndefined(preset && _typeof(preset) === 'object' ? preset : {});
286
+ var userOptions = omitUndefined(user && _typeof(user) === 'object' ? user : {});
287
+ return _objectSpread2(_objectSpread2(_objectSpread2({}, defaults), presetOptions), userOptions);
288
+ }
289
+
290
+ /**
291
+ * 公共色板:NC-01~NC-06 的四色组(底色 / 主色 / 辅色 / 高光色)。
292
+ * Capsule 预置与 dlc-color 等组件共用,新增色板只改这里。
293
+ */
294
+ var PALETTES$1 = {
295
+ original: ['#FFF3EA', '#F5B27A', '#F67BC6', '#A978E8'],
296
+ ocean: ['#EAF6FF', '#8FD0FF', '#3B87F6', '#6B58E9'],
297
+ klein: ['#EDF2FF', '#2F58D5', '#1B2040', '#E07A43'],
298
+ ultraviolet: ['#F2EEFF', '#B99AF1', '#8F74DB', '#D7D85C'],
299
+ chrome: ['#F5F6F8', '#B9C0CC', '#7F8793', '#4A4F59'],
300
+ plus: ['#FFF0E6', '#F6C26B', '#F98A64', '#E86D74']
301
+ };
302
+
303
+ /**
304
+ * Capsule 预置:仅星云材质 NC-01~NC-06(NC-07~09 aurora 已移除)。
305
+ * 颜色引用公共色板,seed/speed 决定形态与流速。
306
+ */
307
+ var CAPSULE_PRESETS = [{
308
+ id: 'original',
309
+ code: 'NC-01',
310
+ name: 'ORIGINAL',
311
+ group: 'warm',
312
+ seed: 1.7,
313
+ speed: 0.5,
314
+ colors: _toConsumableArray(PALETTES$1.original)
315
+ }, {
316
+ id: 'ocean',
317
+ code: 'NC-02',
318
+ name: 'OCEAN',
319
+ group: 'cold',
320
+ seed: 8.2,
321
+ speed: 0.48,
322
+ colors: _toConsumableArray(PALETTES$1.ocean)
323
+ }, {
324
+ id: 'klein',
325
+ code: 'NC-03',
326
+ name: 'KLEIN',
327
+ group: 'cold',
328
+ seed: 14.1,
329
+ speed: 0.49,
330
+ colors: _toConsumableArray(PALETTES$1.klein)
331
+ }, {
332
+ id: 'ultraviolet',
333
+ code: 'NC-04',
334
+ name: 'ULTRAVIOLET',
335
+ group: 'cold',
336
+ seed: 23.4,
337
+ speed: 0.47,
338
+ colors: _toConsumableArray(PALETTES$1.ultraviolet)
339
+ }, {
340
+ id: 'chrome',
341
+ code: 'NC-05',
342
+ name: 'CHROME',
343
+ group: 'cold',
344
+ seed: 37.8,
345
+ speed: 0.42,
346
+ colors: _toConsumableArray(PALETTES$1.chrome)
347
+ }, {
348
+ id: 'plus',
349
+ code: 'NC-06',
350
+ name: 'PLUS',
351
+ group: 'warm',
352
+ seed: 51.3,
353
+ speed: 0.5,
354
+ colors: _toConsumableArray(PALETTES$1.plus)
355
+ }];
356
+
357
+ var PROGRESS_PRESETS = [{
358
+ id: 'model-training',
359
+ code: 'NC-10',
360
+ name: 'MODEL TRAINING',
361
+ subtitle: 'SHA 4.5 + 100 2026 TKN',
362
+ group: 'progress',
363
+ initialProgress: 43,
364
+ edgeStyle: 'flow',
365
+ colors: ['#2B1025', '#FF3F94', '#FF8A3D', '#FFF06A']
366
+ }, {
367
+ id: 'agent-migration',
368
+ code: 'NC-11',
369
+ name: 'AGENT MIGRATION',
370
+ subtitle: 'TRANSFERRING PROTOCOL',
371
+ group: 'progress',
372
+ initialProgress: 33,
373
+ edgeStyle: 'flow',
374
+ colors: ['#101C37', '#245BFF', '#00CFFF', '#5DFFE6']
375
+ }, {
376
+ id: 'visual-training',
377
+ code: 'NC-12',
378
+ name: 'VISUAL TRAINING',
379
+ subtitle: 'GENERATING POWER ++',
380
+ group: 'progress',
381
+ initialProgress: 58,
382
+ edgeStyle: 'flow',
383
+ colors: ['#21142D', '#7042FF', '#42F58D', '#C4FF8A']
384
+ }, {
385
+ id: 'tide',
386
+ code: 'NC-13',
387
+ name: 'TIDE',
388
+ subtitle: 'MOON PULL / COAST',
389
+ group: 'progress',
390
+ initialProgress: 30,
391
+ edgeStyle: 'tide',
392
+ colors: ['#0A2239', '#2E9BFF', '#7FE3FF', '#EAF9FF']
393
+ }];
394
+
395
+ [].concat(_toConsumableArray(CAPSULE_PRESETS), _toConsumableArray(PROGRESS_PRESETS));
396
+ function validateProgressPreset(preset) {
397
+ return Boolean(preset && typeof preset.id === 'string' && typeof preset.code === 'string' && typeof preset.name === 'string' && preset.group === 'progress' && Number.isFinite(preset.initialProgress) && ['flow', 'tide'].indexOf(preset.edgeStyle || 'flow') !== -1 && Array.isArray(preset.colors) && preset.colors.length === 4);
398
+ }
399
+ function getPreset(kind, ref) {
400
+ var list = PROGRESS_PRESETS ;
401
+ if (!list) throw new Error("Unknown preset kind: ".concat(kind, " (use \"capsule\" or \"progress\")"));
402
+ if (ref && _typeof(ref) === 'object') {
403
+ var valid = validateProgressPreset(ref);
404
+ if (!valid) throw new Error("Invalid ".concat(kind, " preset object"));
405
+ return ref;
406
+ }
407
+ var key = String(ref).trim().toLowerCase();
408
+ var found = list.find(function (preset) {
409
+ return preset.id.toLowerCase() === key || preset.code.toLowerCase() === key || preset.name.toLowerCase() === key;
410
+ });
411
+ if (!found) throw new Error("Unknown ".concat(kind, " preset: ").concat(ref));
412
+ return found;
413
+ }
414
+
415
+ var DEFAULTS = {
416
+ progress: {
417
+ width: 454,
418
+ height: 104,
419
+ min: 0,
420
+ max: 100,
421
+ draggable: true,
422
+ keyboard: true,
423
+ edgeStyle: 'flow',
424
+ quality: 'auto',
425
+ renderer: 'auto',
426
+ showCopy: true,
427
+ respectReducedMotion: true
428
+ }
429
+ };
430
+
431
+ /**
432
+ * All user-facing copy lives here so wording/brand changes never require a
433
+ * global search. Templates use {brand} {code} {name} placeholders.
434
+ */
435
+ var COPY = {
436
+ brandName: '画境观屿',
437
+ dragLabel: 'DRAG',
438
+ valueSuffix: '%',
439
+ progressAria: '{brand} {code} 加载进度',
440
+ capsuleAria: '打开 {name} 沉浸预览'
441
+ };
442
+
443
+ function hexToRgba(hex) {
444
+ var alpha = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
445
+ var normalized = hex.replace('#', '');
446
+ var value = Number.parseInt(normalized, 16);
447
+ var red = value >> 16 & 255;
448
+ var green = value >> 8 & 255;
449
+ var blue = value & 255;
450
+ return "rgba(".concat(red, ", ").concat(green, ", ").concat(blue, ", ").concat(alpha, ")");
451
+ }
452
+
453
+ /**
454
+ * Document-level shared rAF scheduler. Every component instance subscribes
455
+ * its own frame callback; the whole page runs ONE animation loop (like the
456
+ * original demo), which avoids jank from many competing rAF loops.
457
+ */
458
+ var subscribers = [];
459
+ var running = false;
460
+ var rafId = 0;
461
+ var last = 0;
462
+ function tick(now) {
463
+ if (!running) return;
464
+ var delta = last ? Math.min((now - last) / 1000, 0.05) : 0;
465
+ last = now;
466
+ // Schedule the next frame BEFORE running callbacks so one throwing
467
+ // subscriber can never kill the whole animation loop.
468
+ rafId = requestAnimationFrame(tick);
469
+ {
470
+ var _iterator = _createForOfIteratorHelper(subscribers.slice()),
471
+ _step;
472
+ try {
473
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
474
+ var item = _step.value;
475
+ try {
476
+ if (!item.isPaused()) item.onFrame(delta, now);
477
+ } catch (error) {
478
+ console.warn('[dlc-ui] frame error:', error);
479
+ }
480
+ }
481
+ } catch (err) {
482
+ _iterator.e(err);
483
+ } finally {
484
+ _iterator.f();
485
+ }
486
+ }
487
+ if (subscribers.length === 0) {
488
+ cancelAnimationFrame(rafId);
489
+ running = false;
490
+ rafId = 0;
491
+ }
492
+ }
493
+ function start() {
494
+ if (running) return;
495
+ running = true;
496
+ last = 0;
497
+ rafId = requestAnimationFrame(tick);
498
+ }
499
+ function subscribeScheduler(onFrame, isPaused) {
500
+ var item = {
501
+ onFrame: onFrame,
502
+ isPaused: isPaused
503
+ };
504
+ subscribers.push(item);
505
+ start();
506
+ return function () {
507
+ var index = subscribers.indexOf(item);
508
+ if (index !== -1) subscribers.splice(index, 1);
509
+ if (subscribers.length === 0 && rafId) {
510
+ cancelAnimationFrame(rafId);
511
+ running = false;
512
+ rafId = 0;
513
+ }
514
+ };
515
+ }
516
+
517
+ /**
518
+ * Gates drawing on "element intersects viewport AND the page tab is visible".
519
+ * Falls back to always-visible when IntersectionObserver is unavailable.
520
+ */
521
+ function createVisibilityGuard(element) {
522
+ var intersecting = true;
523
+ var pageVisible = typeof document === 'undefined' || !document.hidden;
524
+ var disposed = false;
525
+ var observer = null;
526
+ if (typeof IntersectionObserver !== 'undefined') {
527
+ observer = new IntersectionObserver(function (entries) {
528
+ intersecting = entries.some(function (entry) {
529
+ return entry.isIntersecting;
530
+ });
531
+ }, {
532
+ rootMargin: '180px'
533
+ });
534
+ observer.observe(element);
535
+ }
536
+ var onVisibilityChange = function onVisibilityChange() {
537
+ pageVisible = typeof document !== 'undefined' && !document.hidden;
538
+ };
539
+ if (typeof document !== 'undefined') {
540
+ document.addEventListener('visibilitychange', onVisibilityChange);
541
+ }
542
+ return {
543
+ isVisible: function isVisible() {
544
+ return intersecting && pageVisible;
545
+ },
546
+ dispose: function dispose() {
547
+ if (disposed) return;
548
+ disposed = true;
549
+ if (observer) observer.disconnect();
550
+ if (typeof document !== 'undefined') {
551
+ document.removeEventListener('visibilitychange', onVisibilityChange);
552
+ }
553
+ }
554
+ };
555
+ }
556
+
557
+ var PROGRESS_MOTION_WIDTH = 240;
558
+ var PROGRESS_MOTION_HEIGHT = 80;
559
+ var PROGRESS_MOTION_DURATION = 12.0;
560
+ var PROGRESS_MOTION_MAX_PX = 40.0;
561
+ var PROFILE_CONFIG = {
562
+ 'model-training': {
563
+ seed: 0.37,
564
+ broad: 0.58,
565
+ middle: 0.25,
566
+ detail: 0.13,
567
+ lobe: 0.24
568
+ },
569
+ 'agent-migration': {
570
+ seed: 1.71,
571
+ broad: 0.72,
572
+ middle: 0.10,
573
+ detail: 0.03,
574
+ lobe: 0.18
575
+ },
576
+ 'visual-training': {
577
+ seed: 2.83,
578
+ broad: 0.66,
579
+ middle: 0.16,
580
+ detail: 0.06,
581
+ lobe: 0.23
582
+ },
583
+ // ponytail: first-pass tide = asymmetric time warp on the same motion pipeline.
584
+ // Refine (foam line / wash streaks) in the shader after visual QA.
585
+ 'tide': {
586
+ seed: 4.12,
587
+ broad: 0.82,
588
+ middle: 0.07,
589
+ detail: 0.02,
590
+ lobe: 0.30,
591
+ warp: 0.5
592
+ }
593
+ };
594
+ var CACHE$1 = Object.create(null);
595
+ function gaussian(value, center, width) {
596
+ var delta = (value - center) / Math.max(width, 0.001);
597
+ return Math.exp(-delta * delta);
598
+ }
599
+ function createMotionData(id) {
600
+ var edgeStyle = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'flow';
601
+ var profile = edgeStyle === 'tide' ? PROFILE_CONFIG.tide : PROFILE_CONFIG[id] || PROFILE_CONFIG['visual-training'];
602
+ var data = new Uint8Array(PROGRESS_MOTION_WIDTH * PROGRESS_MOTION_HEIGHT);
603
+ for (var x = 0; x < PROGRESS_MOTION_WIDTH; x += 1) {
604
+ var time = x / PROGRESS_MOTION_WIDTH * Math.PI * 2;
605
+ if (profile.warp) time += profile.warp * Math.sin(time * 2);
606
+ var centerA = 0.28 + Math.sin(time * 0.53 + profile.seed) * 0.13;
607
+ var centerB = 0.70 + Math.cos(time * 0.47 + profile.seed * 1.7) * 0.12;
608
+ for (var y = 0; y < PROGRESS_MOTION_HEIGHT; y += 1) {
609
+ var ratio = y / Math.max(PROGRESS_MOTION_HEIGHT - 1, 1);
610
+ var envelope = Math.pow(Math.max(Math.sin(Math.PI * ratio), 0), 0.48);
611
+ var broad = Math.sin(ratio * Math.PI * 2 * 1.35 + time * 0.58 + profile.seed) * profile.broad;
612
+ var middle = Math.sin(ratio * Math.PI * 2 * 3.2 - time * 0.91 + profile.seed * 2.1) * profile.middle;
613
+ var detail = Math.sin(ratio * Math.PI * 2 * 6.1 + time * 1.31 + profile.seed * 3.2) * profile.detail;
614
+ var lobes = (gaussian(ratio, centerA, 0.09) * Math.sin(time * 1.11 + profile.seed * 4.0) - gaussian(ratio, centerB, 0.10) * Math.cos(time * 0.97 + profile.seed * 3.3)) * profile.lobe;
615
+ var normalized = Math.max(-1, Math.min(1, (broad + middle + detail + lobes) * envelope));
616
+ data[y * PROGRESS_MOTION_WIDTH + x] = Math.round((normalized * 0.5 + 0.5) * 255);
617
+ }
618
+ }
619
+ return data;
620
+ }
621
+ function getProgressMotionData(id) {
622
+ var edgeStyle = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'flow';
623
+ var key = "".concat(id, ":").concat(edgeStyle);
624
+ if (!CACHE$1[key]) CACHE$1[key] = createMotionData(id, edgeStyle);
625
+ return CACHE$1[key];
626
+ }
627
+
628
+ function hexToRgb01(hex) {
629
+ var value = Number.parseInt(hex.replace('#', ''), 16);
630
+ return [(value >> 16 & 255) / 255, (value >> 8 & 255) / 255, (value & 255) / 255];
631
+ }
632
+ function stringSeed$1(value) {
633
+ var hash = 2166136261;
634
+ var _iterator = _createForOfIteratorHelper(value),
635
+ _step;
636
+ try {
637
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
638
+ var character = _step.value;
639
+ hash ^= character.charCodeAt(0);
640
+ hash = Math.imul(hash, 16777619);
641
+ }
642
+ } catch (err) {
643
+ _iterator.e(err);
644
+ } finally {
645
+ _iterator.f();
646
+ }
647
+ return (hash >>> 0) / 4294967295;
648
+ }
649
+ var PROFILE_INDEX = {
650
+ 'model-training': 0,
651
+ 'agent-migration': 1,
652
+ 'visual-training': 2,
653
+ 'tide': 3
654
+ };
655
+ var MOTION_SCALE_FACTORS = {
656
+ 'model-training': 1.05,
657
+ 'agent-migration': 1.04,
658
+ 'visual-training': 1.04,
659
+ 'tide': 1.18
660
+ };
661
+ var VERTEX_SHADER = "#version 300 es\nin vec2 a_position;\nout vec2 v_uv;\nvoid main() {\n v_uv = a_position * 0.5 + 0.5;\n gl_Position = vec4(a_position, 0.0, 1.0);\n}";
662
+ var FRAGMENT_SHADER = "#version 300 es\nprecision highp float;\n\nin vec2 v_uv;\nout vec4 outColor;\n\nuniform vec2 u_resolution;\nuniform float u_time;\nuniform float u_progress;\nuniform float u_seed;\nuniform float u_profile;\nuniform sampler2D u_motion;\nuniform sampler2D u_effect;\nuniform float u_hasEffect;\nuniform float u_effectFrames;\nuniform float u_motionDuration;\nuniform float u_motionScale;\nuniform vec3 u_dark;\nuniform vec3 u_accentA;\nuniform vec3 u_accentB;\nuniform vec3 u_glow;\n\nfloat hash21(vec2 p) {\n p = fract(p * vec2(123.34, 456.21));\n p += dot(p, p + 45.32 + u_seed * 11.7);\n return fract(p.x * p.y);\n}\n\nfloat noise(vec2 p) {\n vec2 i = floor(p);\n vec2 f = fract(p);\n f = f * f * (3.0 - 2.0 * f);\n float a = hash21(i);\n float b = hash21(i + vec2(1.0, 0.0));\n float c = hash21(i + vec2(0.0, 1.0));\n float d = hash21(i + vec2(1.0, 1.0));\n return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);\n}\n\nfloat fbm(vec2 p) {\n float value = 0.0;\n float amplitude = 0.55;\n mat2 rotation = mat2(0.82, 0.57, -0.57, 0.82);\n for (int i = 0; i < 6; i++) {\n value += noise(p) * amplitude;\n p = rotation * p * 2.02 + 13.7;\n amplitude *= 0.48;\n }\n return value;\n}\n\nfloat gaussian(float value, float center, float width) {\n float delta = (value - center) / max(width, 0.0001);\n return exp(-delta * delta);\n}\n\nfloat profileMix(float model, float agent, float visual) {\n if (u_profile < 0.5) return model;\n if (u_profile < 1.5) return agent;\n return visual;\n}\n\nfloat motionSample(float y, float t) {\n float phase = fract(t / max(u_motionDuration, 0.001));\n float captured = texture(u_motion, vec2(phase, 1.0 - clamp(y, 0.0, 1.0))).r;\n return (captured * 2.0 - 1.0) * u_motionScale;\n}\n\nfloat edgeDisplacement(float y, float t) {\n return motionSample(y, t);\n}\n\nfloat flowDisplacement(float y, float t) {\n return (\n motionSample(y - 0.024, t) * 0.08 +\n motionSample(y - 0.012, t) * 0.18 +\n motionSample(y, t) * 0.48 +\n motionSample(y + 0.012, t) * 0.18 +\n motionSample(y + 0.024, t) * 0.08\n );\n}\n\nfloat ellipseRing(vec2 p, float radius, float width) {\n return gaussian(length(p), radius, width);\n}\n\nvoid main() {\n vec2 uv = v_uv;\n float t = u_time;\n float edge = u_progress + edgeDisplacement(uv.y, t);\n float flowEdge = u_progress + flowDisplacement(uv.y, t);\n float d = uv.x - edge;\n float fd = uv.x - flowEdge;\n\n vec3 rightBase = vec3(0.125, 0.129, 0.145);\n vec3 color = rightBase;\n\n float leftMask = 1.0 - smoothstep(-0.001, 0.002, d);\n color = mix(color, u_dark, leftMask * profileMix(0.96, 0.92, 0.96));\n\n vec2 flowP = vec2((fd + 0.10) * 6.2, uv.y * 1.95);\n float flowA = fbm(flowP + vec2(-t * 0.22, t * 0.27) + u_seed * 1.7);\n float flowB = fbm(flowP * 1.52 + vec2(t * 0.28, -t * 0.36) + 8.2 + u_seed);\n float flowC = fbm(flowP * 2.25 + vec2(-t * 0.41, t * 0.46) + 19.0);\n\n float farCenter = profileMix(-0.060, -0.079, -0.045) + (flowA - 0.5) * profileMix(0.018, 0.022, 0.014);\n float midCenter = profileMix(-0.039, -0.052, -0.030) + (flowB - 0.5) * profileMix(0.013, 0.016, 0.010);\n float hotCenter = profileMix(-0.026, -0.029, -0.023) + (flowC - 0.5) * 0.010;\n\n float farBand = gaussian(fd, farCenter, profileMix(0.035, 0.049, 0.030));\n float midBand = gaussian(fd, midCenter, profileMix(0.026, 0.034, 0.026));\n float hotBand = gaussian(fd, hotCenter, profileMix(0.023, 0.027, 0.026));\n float darkTrough = gaussian(fd, profileMix(-0.050, -0.058, -0.044) + (flowB - 0.5) * 0.010, profileMix(0.020, 0.025, 0.021));\n\n float ringY = 0.47 + sin(t * 0.58 + u_seed * 2.4) * 0.12;\n vec2 ringP = vec2((fd + 0.086) / 0.078, (uv.y - ringY) / 0.25);\n ringP += vec2((flowB - 0.5) * 0.08, (flowA - 0.5) * 0.06);\n float ringTexture = fbm(ringP * 2.15 + vec2(t * 0.18, -t * 0.14) + u_seed * 1.9);\n float ring = ellipseRing(ringP, 0.66, 0.32) * (0.30 + 0.64 * ringTexture);\n float ringCore = gaussian(length(ringP), 0.25, 0.25);\n float ringPulse = smoothstep(0.58, 0.90, 0.5 + 0.5 * sin(t * 0.82 + u_seed * 4.1));\n float modelRing = ring * ringPulse * (1.0 - step(0.5, u_profile));\n float visualRing = ring * 0.16 * step(1.5, u_profile) * ringPulse;\n\n float cloudGate = leftMask * smoothstep(-0.30, -0.008, fd);\n float textureA = smoothstep(0.24, 0.92, flowA * 0.72 + flowB * 0.42);\n float textureB = smoothstep(0.28, 0.94, flowB * 0.68 + flowC * 0.38);\n\n vec3 hotColor = u_accentB;\n color += u_accentA * farBand * cloudGate * (0.07 + textureA * profileMix(0.42, 0.24, 0.40));\n color += u_accentB * midBand * cloudGate * (0.15 + textureB * profileMix(0.70, 0.46, 0.68));\n color += hotColor * hotBand * cloudGate * profileMix(0.88, 0.62, 0.84);\n float modelMask = 1.0 - step(0.5, u_profile);\n color += u_accentA * (modelRing + visualRing) * cloudGate * profileMix(0.54, 0.0, 0.34);\n color *= 1.0 - darkTrough * profileMix(0.44, 0.24, 0.24) * cloudGate;\n color *= 1.0 - ringCore * modelMask * ringPulse * 0.44 * cloudGate;\n\n float broadHalo = exp(-abs(d) * 96.0);\n float innerHalo = exp(-abs(d) * 176.0);\n float colorCore = exp(-abs(d) * 360.0);\n float sharpCore = exp(-abs(d) * 760.0);\n float leftGate = 1.0 - smoothstep(-0.003, 0.005, d);\n\n color += u_accentA * broadHalo * leftGate * profileMix(0.09, 0.04, 0.06);\n color += hotColor * innerHalo * leftGate * profileMix(0.76, 0.72, 0.78);\n color += u_glow * colorCore * profileMix(0.72, 0.34, 0.24);\n\n float whiteStrength = profileMix(0.10, 0.0, 0.0);\n color += vec3(1.0, 0.99, 0.91) * sharpCore * whiteStrength;\n\n float rightCut = smoothstep(0.001, 0.006, d);\n color = mix(color, rightBase, rightCut);\n\n float effectX = (d * 1257.0 + 260.0) / 320.0;\n float atlasPhase = fract(t / 12.0) * u_effectFrames;\n float atlasFrameA = floor(atlasPhase);\n float atlasFrameB = mod(atlasFrameA + 1.0, u_effectFrames);\n float atlasMix = smoothstep(0.0, 1.0, fract(atlasPhase));\n float atlasXA = (atlasFrameA + clamp(effectX, 0.0, 1.0)) / u_effectFrames;\n float atlasXB = (atlasFrameB + clamp(effectX, 0.0, 1.0)) / u_effectFrames;\n vec3 referenceA = texture(u_effect, vec2(atlasXA, uv.y)).rgb;\n vec3 referenceB = texture(u_effect, vec2(atlasXB, uv.y)).rgb;\n vec3 referenceColor = mix(referenceA, referenceB, atlasMix);\n float stripMask = smoothstep(0.0, 0.018, effectX) * (1.0 - smoothstep(0.982, 1.0, effectX));\n float referenceLeft = 1.0 - smoothstep(-0.026, -0.012, d);\n color = mix(color, referenceColor, stripMask * referenceLeft * u_hasEffect);\n\n outColor = vec4(clamp(color, 0.0, 1.0), 1.0);\n}";
663
+ function compileShader(gl, type, source) {
664
+ var shader = gl.createShader(type);
665
+ gl.shaderSource(shader, source);
666
+ gl.compileShader(shader);
667
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
668
+ var message = gl.getShaderInfoLog(shader) || 'Unknown shader compile error';
669
+ gl.deleteShader(shader);
670
+ throw new Error(message);
671
+ }
672
+ return shader;
673
+ }
674
+ function createProgram(gl) {
675
+ var vertex = compileShader(gl, gl.VERTEX_SHADER, VERTEX_SHADER);
676
+ var fragment = compileShader(gl, gl.FRAGMENT_SHADER, FRAGMENT_SHADER);
677
+ var program = gl.createProgram();
678
+ gl.attachShader(program, vertex);
679
+ gl.attachShader(program, fragment);
680
+ gl.linkProgram(program);
681
+ gl.deleteShader(vertex);
682
+ gl.deleteShader(fragment);
683
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
684
+ var message = gl.getProgramInfoLog(program) || 'Unknown shader link error';
685
+ gl.deleteProgram(program);
686
+ throw new Error(message);
687
+ }
688
+ return program;
689
+ }
690
+ var ProgressFlowRenderer = /*#__PURE__*/function () {
691
+ function ProgressFlowRenderer(canvas, preset) {
692
+ var _PROFILE_INDEX$preset;
693
+ _classCallCheck(this, ProgressFlowRenderer);
694
+ var gl = canvas.getContext('webgl2', {
695
+ alpha: false,
696
+ antialias: true,
697
+ premultipliedAlpha: false,
698
+ powerPreference: 'high-performance'
699
+ });
700
+ if (!gl) throw new Error('WebGL2 unavailable');
701
+ this.canvas = canvas;
702
+ this.gl = gl;
703
+ this.program = createProgram(gl);
704
+ this.profile = preset.edgeStyle === 'tide' ? 3 : (_PROFILE_INDEX$preset = PROFILE_INDEX[preset.id]) !== null && _PROFILE_INDEX$preset !== void 0 ? _PROFILE_INDEX$preset : 2;
705
+ this.seed = stringSeed$1("".concat(preset.id, "-shader")) * 13.7 + 1.0;
706
+ this.colors = preset.colors.map(hexToRgb01);
707
+ this.motionData = getProgressMotionData(preset.id, preset.edgeStyle);
708
+ var motionFactor = preset.edgeStyle === 'tide' ? MOTION_SCALE_FACTORS.tide : MOTION_SCALE_FACTORS[preset.id] || 1.04;
709
+ this.motionScale = PROGRESS_MOTION_MAX_PX * motionFactor / 1257;
710
+ this.position = gl.getAttribLocation(this.program, 'a_position');
711
+ this.uniforms = {
712
+ resolution: gl.getUniformLocation(this.program, 'u_resolution'),
713
+ time: gl.getUniformLocation(this.program, 'u_time'),
714
+ progress: gl.getUniformLocation(this.program, 'u_progress'),
715
+ seed: gl.getUniformLocation(this.program, 'u_seed'),
716
+ profile: gl.getUniformLocation(this.program, 'u_profile'),
717
+ motion: gl.getUniformLocation(this.program, 'u_motion'),
718
+ effect: gl.getUniformLocation(this.program, 'u_effect'),
719
+ hasEffect: gl.getUniformLocation(this.program, 'u_hasEffect'),
720
+ effectFrames: gl.getUniformLocation(this.program, 'u_effectFrames'),
721
+ motionDuration: gl.getUniformLocation(this.program, 'u_motionDuration'),
722
+ motionScale: gl.getUniformLocation(this.program, 'u_motionScale'),
723
+ dark: gl.getUniformLocation(this.program, 'u_dark'),
724
+ accentA: gl.getUniformLocation(this.program, 'u_accentA'),
725
+ accentB: gl.getUniformLocation(this.program, 'u_accentB'),
726
+ glow: gl.getUniformLocation(this.program, 'u_glow')
727
+ };
728
+ this.buffer = gl.createBuffer();
729
+ gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
730
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]), gl.STATIC_DRAW);
731
+ this.motionTexture = gl.createTexture();
732
+ gl.activeTexture(gl.TEXTURE0);
733
+ gl.bindTexture(gl.TEXTURE_2D, this.motionTexture);
734
+ gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
735
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.R8, PROGRESS_MOTION_WIDTH, PROGRESS_MOTION_HEIGHT, 0, gl.RED, gl.UNSIGNED_BYTE, this.motionData);
736
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
737
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
738
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
739
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
740
+ this.effectTexture = gl.createTexture();
741
+ gl.activeTexture(gl.TEXTURE1);
742
+ gl.bindTexture(gl.TEXTURE_2D, this.effectTexture);
743
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, 1, 1, 0, gl.RGB, gl.UNSIGNED_BYTE, new Uint8Array([32, 33, 38]));
744
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
745
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
746
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
747
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
748
+ this.effectUploaded = false;
749
+ }
750
+ return _createClass(ProgressFlowRenderer, [{
751
+ key: "resize",
752
+ value: function resize(width, height, dpr) {
753
+ var pixelWidth = Math.max(1, Math.round(width * dpr));
754
+ var pixelHeight = Math.max(1, Math.round(height * dpr));
755
+ if (this.canvas.width !== pixelWidth || this.canvas.height !== pixelHeight) {
756
+ this.canvas.width = pixelWidth;
757
+ this.canvas.height = pixelHeight;
758
+ }
759
+ this.gl.viewport(0, 0, pixelWidth, pixelHeight);
760
+ }
761
+ }, {
762
+ key: "draw",
763
+ value: function draw(time, progress) {
764
+ var effectImage = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
765
+ var gl = this.gl;
766
+ gl.useProgram(this.program);
767
+ gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
768
+ gl.enableVertexAttribArray(this.position);
769
+ gl.vertexAttribPointer(this.position, 2, gl.FLOAT, false, 0, 0);
770
+ gl.uniform2f(this.uniforms.resolution, this.canvas.width, this.canvas.height);
771
+ gl.uniform1f(this.uniforms.time, time);
772
+ gl.uniform1f(this.uniforms.progress, progress / 100);
773
+ gl.uniform1f(this.uniforms.seed, this.seed);
774
+ gl.uniform1f(this.uniforms.profile, this.profile);
775
+ gl.activeTexture(gl.TEXTURE0);
776
+ gl.bindTexture(gl.TEXTURE_2D, this.motionTexture);
777
+ gl.uniform1i(this.uniforms.motion, 0);
778
+ gl.uniform1f(this.uniforms.motionDuration, PROGRESS_MOTION_DURATION);
779
+ gl.uniform1f(this.uniforms.motionScale, this.motionScale);
780
+ var hasEffect = this.effectUploaded ? 1 : 0;
781
+ if (!this.effectUploaded && effectImage && effectImage.complete && effectImage.naturalWidth > 0) {
782
+ gl.activeTexture(gl.TEXTURE1);
783
+ gl.bindTexture(gl.TEXTURE_2D, this.effectTexture);
784
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
785
+ try {
786
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, effectImage);
787
+ this.effectUploaded = true;
788
+ hasEffect = 1;
789
+ } catch (error) {
790
+ console.warn('[画境观屿] 参考纹理图集上传失败,继续使用程序化降级。', error);
791
+ }
792
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
793
+ }
794
+ gl.activeTexture(gl.TEXTURE1);
795
+ gl.bindTexture(gl.TEXTURE_2D, this.effectTexture);
796
+ gl.uniform1i(this.uniforms.effect, 1);
797
+ gl.uniform1f(this.uniforms.hasEffect, hasEffect);
798
+ gl.uniform1f(this.uniforms.effectFrames, 24);
799
+ gl.uniform3fv(this.uniforms.dark, this.colors[0]);
800
+ gl.uniform3fv(this.uniforms.accentA, this.colors[1]);
801
+ gl.uniform3fv(this.uniforms.accentB, this.colors[2]);
802
+ gl.uniform3fv(this.uniforms.glow, this.colors[3]);
803
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
804
+ }
805
+ }, {
806
+ key: "setColors",
807
+ value: function setColors(colors) {
808
+ this.colors = colors.map(hexToRgb01);
809
+ }
810
+ }, {
811
+ key: "dispose",
812
+ value: function dispose() {
813
+ var gl = this.gl;
814
+ gl.deleteBuffer(this.buffer);
815
+ gl.deleteTexture(this.motionTexture);
816
+ gl.deleteTexture(this.effectTexture);
817
+ gl.deleteProgram(this.program);
818
+ var lose = gl.getExtension('WEBGL_lose_context');
819
+ if (lose) lose.loseContext();
820
+ }
821
+ }]);
822
+ }();
823
+ function createProgressFlowRenderer(canvas, preset) {
824
+ try {
825
+ return new ProgressFlowRenderer(canvas, preset);
826
+ } catch (error) {
827
+ console.warn('[画境观屿] 进度流体 WebGL2 不可用,使用 Canvas 2D 降级。', error);
828
+ return null;
829
+ }
830
+ }
831
+
832
+ var PROGRESS_REFERENCE_DURATION = 12;
833
+ var PROGRESS_REFERENCE_FRAME_COUNT = 24;
834
+ var FRAME_WIDTH = 64;
835
+ var FRAME_HEIGHT = 32;
836
+ var CACHE = Object.create(null);
837
+ var PALETTES = {
838
+ 'model-training': ['#20131f', '#ff3f94', '#ff8a3d', '#fff06a'],
839
+ 'agent-migration': ['#111a31', '#245bff', '#00cfff', '#5dffe6'],
840
+ 'visual-training': ['#1f172b', '#7042ff', '#42f58d', '#c4ff8a'],
841
+ 'tide': ['#0a2239', '#2e9bff', '#7fe3ff', '#eaf9ff']
842
+ };
843
+ function drawCloud(context, x, y, radiusX, radiusY, color, alpha) {
844
+ context.save();
845
+ context.translate(x, y);
846
+ context.scale(1, radiusY / radiusX);
847
+ var gradient = context.createRadialGradient(0, 0, 0, 0, 0, radiusX);
848
+ gradient.addColorStop(0, "".concat(color).concat(Math.round(alpha * 255).toString(16).padStart(2, '0')));
849
+ gradient.addColorStop(0.46, "".concat(color).concat(Math.round(alpha * 0.42 * 255).toString(16).padStart(2, '0')));
850
+ gradient.addColorStop(1, "".concat(color, "00"));
851
+ context.fillStyle = gradient;
852
+ context.fillRect(-radiusX, -radiusX, radiusX * 2, radiusX * 2);
853
+ context.restore();
854
+ }
855
+ function createAtlas(id) {
856
+ var palette = PALETTES[id] || PALETTES['visual-training'];
857
+ var canvas = document.createElement('canvas');
858
+ canvas.width = FRAME_WIDTH * PROGRESS_REFERENCE_FRAME_COUNT;
859
+ canvas.height = FRAME_HEIGHT;
860
+ var context = canvas.getContext('2d');
861
+ for (var frame = 0; frame < PROGRESS_REFERENCE_FRAME_COUNT; frame += 1) {
862
+ var phase = frame / PROGRESS_REFERENCE_FRAME_COUNT * Math.PI * 2;
863
+ var left = frame * FRAME_WIDTH;
864
+ context.save();
865
+ context.translate(left, 0);
866
+ context.fillStyle = palette[0];
867
+ context.fillRect(0, 0, FRAME_WIDTH, FRAME_HEIGHT);
868
+ context.globalCompositeOperation = 'screen';
869
+ drawCloud(context, 35 + Math.sin(phase * 0.83) * 5, 10 + Math.cos(phase * 0.61) * 5, 27, 18, palette[1], id === 'agent-migration' ? 0.32 : 0.42);
870
+ drawCloud(context, 45 + Math.cos(phase * 0.72) * 4, 23 + Math.sin(phase * 0.54) * 4, 22, 15, palette[2], 0.44);
871
+ drawCloud(context, 53 + Math.sin(phase * 1.07) * 2, 16 + Math.cos(phase * 0.89) * 6, 12, 13, palette[3], id === 'model-training' ? 0.30 : 0.20);
872
+ context.globalCompositeOperation = 'source-over';
873
+ var trough = context.createRadialGradient(41, 16, 1, 41, 16, 17);
874
+ trough.addColorStop(0, 'rgba(5,6,11,0.64)');
875
+ trough.addColorStop(0.58, 'rgba(6,7,12,0.26)');
876
+ trough.addColorStop(1, 'rgba(6,7,12,0)');
877
+ context.fillStyle = trough;
878
+ context.fillRect(20, 0, 44, FRAME_HEIGHT);
879
+ context.restore();
880
+ }
881
+ var image = new Image();
882
+ image.decoding = 'async';
883
+ var state = {
884
+ image: image,
885
+ ready: false
886
+ };
887
+ image.addEventListener('load', function () {
888
+ state.ready = true;
889
+ }, {
890
+ once: true
891
+ });
892
+ image.addEventListener('error', function () {
893
+ state.ready = false;
894
+ }, {
895
+ once: true
896
+ });
897
+ image.src = canvas.toDataURL('image/png');
898
+ return state;
899
+ }
900
+ function getProgressReferenceAtlas(id) {
901
+ if (!CACHE[id]) CACHE[id] = createAtlas(id);
902
+ return CACHE[id];
903
+ }
904
+
905
+ /**
906
+ * Attach a WebGL2 fluid overlay to a progress capsule root.
907
+ *
908
+ * @param {object} params
909
+ * @param {HTMLElement} params.root progress capsule root element
910
+ * @param {HTMLCanvasElement} params.canvas 2D fallback canvas (kept beneath)
911
+ * @param {object} params.preset progress preset
912
+ * @param {() => number} params.getProgress reads the current progress value
913
+ * @returns {{ update(flowTime: number): void, dispose(): void } | null}
914
+ */
915
+ function attachProgressFlowOverlay(_ref) {
916
+ var root = _ref.root,
917
+ canvas = _ref.canvas,
918
+ preset = _ref.preset,
919
+ getProgress = _ref.getProgress;
920
+ var overlay = document.createElement('canvas');
921
+ overlay.className = 'hj-progress-canvas hj-progress-overlay';
922
+ overlay.setAttribute('aria-hidden', 'true');
923
+ canvas.insertAdjacentElement('afterend', overlay);
924
+ var renderer = createProgressFlowRenderer(overlay, preset);
925
+ if (!renderer) {
926
+ overlay.remove();
927
+ return null;
928
+ }
929
+ var atlas = getProgressReferenceAtlas(preset.id);
930
+ root.classList.add('has-webgl-progress');
931
+ var resize = function resize() {
932
+ var bounds = root.getBoundingClientRect();
933
+ var width = Math.max(1, bounds.width);
934
+ var height = Math.max(1, bounds.height);
935
+ var dpr = Math.min(window.devicePixelRatio || 1, 2);
936
+ overlay.style.width = "".concat(width, "px");
937
+ overlay.style.height = "".concat(height, "px");
938
+ renderer.resize(width, height, dpr);
939
+ };
940
+ var resizeObserver = null;
941
+ var onWindowResize = null;
942
+ if (typeof ResizeObserver !== 'undefined') {
943
+ resizeObserver = new ResizeObserver(resize);
944
+ resizeObserver.observe(root);
945
+ } else {
946
+ onWindowResize = resize;
947
+ window.addEventListener('resize', onWindowResize);
948
+ }
949
+ resize();
950
+ return {
951
+ update: function update(flowTime) {
952
+ var effectTime = flowTime % PROGRESS_REFERENCE_DURATION;
953
+ var progress = getProgress();
954
+ renderer.draw(effectTime, Number.isFinite(progress) ? progress : preset.initialProgress, atlas.ready ? atlas.image : null);
955
+ },
956
+ setColors: function setColors(colors) {
957
+ renderer.setColors(colors);
958
+ },
959
+ dispose: function dispose() {
960
+ if (resizeObserver) resizeObserver.disconnect();
961
+ if (onWindowResize) window.removeEventListener('resize', onWindowResize);
962
+ renderer.dispose();
963
+ overlay.remove();
964
+ root.classList.remove('has-webgl-progress');
965
+ }
966
+ };
967
+ }
968
+
969
+ var clamp = function clamp(value, min, max) {
970
+ return Math.min(Math.max(value, min), max);
971
+ };
972
+ var SUPPORTS_CTX_FILTER = typeof CanvasRenderingContext2D !== 'undefined' && 'filter' in CanvasRenderingContext2D.prototype;
973
+ function stringSeed(value) {
974
+ var hash = 2166136261;
975
+ var _iterator = _createForOfIteratorHelper(value),
976
+ _step;
977
+ try {
978
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
979
+ var character = _step.value;
980
+ hash ^= character.charCodeAt(0);
981
+ hash = Math.imul(hash, 16777619);
982
+ }
983
+ } catch (err) {
984
+ _iterator.e(err);
985
+ } finally {
986
+ _iterator.f();
987
+ }
988
+ return (hash >>> 0) / 4294967295;
989
+ }
990
+ function interpolate(template, values) {
991
+ return template.replace(/\{(\w+)\}/g, function (_, key) {
992
+ return values[key] !== undefined ? values[key] : '';
993
+ });
994
+ }
995
+ function prefersReducedMotion() {
996
+ return typeof matchMedia !== 'undefined' && matchMedia('(prefers-reduced-motion: reduce)').matches;
997
+ }
998
+ var FLOW_PROFILES = {
999
+ 'model-training': {
1000
+ cycles: [0.98, 3.05, 5.45],
1001
+ amplitudes: [11.2, 11.0, 5.2],
1002
+ speeds: [0.31, -0.53, 0.78],
1003
+ bulgeAmplitude: 8.2,
1004
+ timeScale: 1.0,
1005
+ glowWidth: 5.8,
1006
+ haloWidth: 20,
1007
+ whiteAlpha: 0.72,
1008
+ whiteWidth: 1.15,
1009
+ cloudWidth: 0.17,
1010
+ autoRange: [25, 66]
1011
+ },
1012
+ 'agent-migration': {
1013
+ cycles: [0.62, 1.55, 2.95],
1014
+ amplitudes: [16.0, 7.8, 2.3],
1015
+ speeds: [0.25, -0.4, 0.60],
1016
+ bulgeAmplitude: 8.4,
1017
+ timeScale: 0.82,
1018
+ glowWidth: 6.3,
1019
+ haloWidth: 21,
1020
+ whiteAlpha: 0.18,
1021
+ whiteWidth: 0.45,
1022
+ cloudWidth: 0.18,
1023
+ autoRange: [24, 62]
1024
+ },
1025
+ 'visual-training': {
1026
+ cycles: [0.88, 2.45, 4.35],
1027
+ amplitudes: [12.8, 10.2, 4.3],
1028
+ speeds: [0.28, -0.47, 0.69],
1029
+ bulgeAmplitude: 7.3,
1030
+ timeScale: 0.91,
1031
+ glowWidth: 6.0,
1032
+ haloWidth: 21,
1033
+ whiteAlpha: 0.30,
1034
+ whiteWidth: 0.55,
1035
+ cloudWidth: 0.175,
1036
+ autoRange: [20, 75]
1037
+ },
1038
+ // ponytail: first-pass tide = asymmetric surge on the 2D fallback path.
1039
+ // Tune surge/amplitudes after visual QA against the WebGL overlay.
1040
+ 'tide': {
1041
+ cycles: [0.72, 1.9, 4.2],
1042
+ amplitudes: [19.0, 6.5, 1.5],
1043
+ speeds: [0.42, -0.5, 0.66],
1044
+ bulgeAmplitude: 9.5,
1045
+ timeScale: 0.85,
1046
+ glowWidth: 6.2,
1047
+ haloWidth: 21,
1048
+ whiteAlpha: 0.5,
1049
+ whiteWidth: 1.0,
1050
+ cloudWidth: 0.18,
1051
+ autoRange: [18, 70],
1052
+ surge: 0.55
1053
+ }
1054
+ };
1055
+ var ProgressCapsuleController = /*#__PURE__*/function () {
1056
+ function ProgressCapsuleController(_ref) {
1057
+ var _options$min,
1058
+ _options$max,
1059
+ _options$value,
1060
+ _this = this;
1061
+ var root = _ref.root,
1062
+ canvas = _ref.canvas,
1063
+ valueElement = _ref.valueElement,
1064
+ preset = _ref.preset,
1065
+ emitter = _ref.emitter,
1066
+ options = _ref.options,
1067
+ copy = _ref.copy;
1068
+ _classCallCheck(this, ProgressCapsuleController);
1069
+ this.root = root;
1070
+ this.canvas = canvas;
1071
+ this.valueElement = valueElement;
1072
+ this.preset = preset;
1073
+ this.emitter = emitter;
1074
+ this.options = options;
1075
+ this.copy = copy;
1076
+ this.profile = preset.edgeStyle === 'tide' ? FLOW_PROFILES.tide : FLOW_PROFILES[preset.id] || FLOW_PROFILES['visual-training'];
1077
+ this.min = (_options$min = options.min) !== null && _options$min !== void 0 ? _options$min : 0;
1078
+ this.max = (_options$max = options.max) !== null && _options$max !== void 0 ? _options$max : 100;
1079
+ this.dprCap = dprCapFor(options.quality);
1080
+ this.ctx = canvas.getContext('2d');
1081
+ this.value = clamp((_options$value = options.value) !== null && _options$value !== void 0 ? _options$value : preset.initialProgress, this.min, this.max);
1082
+ this.dragging = false;
1083
+ this.webglActive = false;
1084
+ this.flowTime = stringSeed(preset.id) * 31;
1085
+ this.seed = stringSeed("".concat(preset.id, "-reference")) * Math.PI * 2;
1086
+ this.randomState = Math.floor(stringSeed("".concat(preset.id, "-auto")) * 0x7fffffff) || 1;
1087
+ this.dpr = 1;
1088
+ this.width = 0;
1089
+ this.height = 0;
1090
+ this.handlers = {};
1091
+ this.resizeObserver = typeof ResizeObserver !== 'undefined' ? new ResizeObserver(function () {
1092
+ return _this.resizeCanvas();
1093
+ }) : null;
1094
+ if (this.resizeObserver) this.resizeObserver.observe(this.root);else window.addEventListener('resize', this.resizeCanvas);
1095
+ this.suppressEvents = true;
1096
+ this.setProgress(this.value, 'init');
1097
+ this.suppressEvents = false;
1098
+ this.bindEvents();
1099
+ this.resizeCanvas();
1100
+ }
1101
+ return _createClass(ProgressCapsuleController, [{
1102
+ key: "random",
1103
+ value: function random() {
1104
+ this.randomState = Math.imul(this.randomState, 1664525) + 1013904223 >>> 0;
1105
+ return this.randomState / 4294967296;
1106
+ }
1107
+ }, {
1108
+ key: "setProgress",
1109
+ value: function setProgress(nextValue) {
1110
+ var source = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'auto';
1111
+ this.value = clamp(nextValue, this.min, this.max);
1112
+ var rounded = Math.round(this.value);
1113
+ this.root.style.setProperty('--progress', this.value.toFixed(2));
1114
+ this.root.setAttribute('aria-valuenow', String(rounded));
1115
+ this.root.setAttribute('aria-valuetext', "".concat(rounded).concat(this.copy.valueSuffix));
1116
+ this.valueElement.textContent = "".concat(rounded).concat(this.copy.valueSuffix);
1117
+ if (!this.suppressEvents) this.emitter.emit('change', {
1118
+ value: this.value,
1119
+ source: source
1120
+ });
1121
+ }
1122
+ }, {
1123
+ key: "resizeCanvas",
1124
+ value: function resizeCanvas() {
1125
+ var bounds = this.root.getBoundingClientRect();
1126
+ this.dpr = Math.min(window.devicePixelRatio || 1, this.dprCap);
1127
+ this.width = Math.max(1, bounds.width);
1128
+ this.height = Math.max(1, bounds.height);
1129
+ this.canvas.width = Math.round(this.width * this.dpr);
1130
+ this.canvas.height = Math.round(this.height * this.dpr);
1131
+ this.canvas.style.width = "".concat(this.width, "px");
1132
+ this.canvas.style.height = "".concat(this.height, "px");
1133
+ this.ctx.setTransform(this.dpr, 0, 0, this.dpr, 0, 0);
1134
+ }
1135
+ }, {
1136
+ key: "edgeEnvelope",
1137
+ value: function edgeEnvelope(yRatio) {
1138
+ var edge = Math.sin(Math.PI * clamp(yRatio, 0, 1));
1139
+ return Math.pow(Math.max(edge, 0), 0.48);
1140
+ }
1141
+ }, {
1142
+ key: "localBulge",
1143
+ value: function localBulge(yRatio, time, index) {
1144
+ var direction = index === 0 ? 1 : -1;
1145
+ var center = 0.28 + index * 0.40 + Math.sin(time * (0.19 + index * 0.035) + this.seed * (1.1 + index)) * 0.13;
1146
+ var width = 0.075 + index * 0.016 + Math.sin(time * 0.13 + this.seed * 2.1) * 0.012;
1147
+ var distance = (yRatio - center) / Math.max(width, 0.035);
1148
+ var gaussian = Math.exp(-0.5 * distance * distance);
1149
+ return gaussian * Math.sin(time * (0.71 + index * 0.09) + this.seed * (2.7 + index)) * this.profile.bulgeAmplitude * direction;
1150
+ }
1151
+ }, {
1152
+ key: "edgeOffset",
1153
+ value: function edgeOffset(y, time) {
1154
+ var phase = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
1155
+ var amplitudeScale = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1;
1156
+ var yRatio = this.height > 0 ? y / this.height : 0;
1157
+ var envelope = this.edgeEnvelope(yRatio);
1158
+ var scaledTime = time * this.profile.timeScale;
1159
+ var phaseTime = this.profile.surge ? scaledTime + this.profile.surge * Math.sin(scaledTime * 2) : scaledTime;
1160
+ var offset = 0;
1161
+ for (var index = 0; index < this.profile.cycles.length; index += 1) {
1162
+ var cycle = this.profile.cycles[index];
1163
+ var amplitude = this.profile.amplitudes[index];
1164
+ var speed = this.profile.speeds[index];
1165
+ var amplitudeMotion = 0.74 + 0.26 * Math.sin(phaseTime * (0.17 + index * 0.045) + this.seed * (index + 2.4));
1166
+ offset += Math.sin(yRatio * Math.PI * 2 * cycle + phaseTime * speed * Math.PI * 2 + this.seed * (index + 1) + phase) * amplitude * amplitudeMotion;
1167
+ }
1168
+ offset += this.localBulge(yRatio, phaseTime + phase, 0);
1169
+ offset += this.localBulge(yRatio, phaseTime - phase * 0.7, 1);
1170
+ return offset * envelope * amplitudeScale;
1171
+ }
1172
+ }, {
1173
+ key: "createEdgePath",
1174
+ value: function createEdgePath(ctx, baseX, time) {
1175
+ var phase = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
1176
+ var amplitudeScale = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
1177
+ var step = Math.max(1.8, this.height / 92);
1178
+ ctx.beginPath();
1179
+ for (var y = 0; y <= this.height + step; y += step) {
1180
+ var x = baseX + this.edgeOffset(y, time, phase, amplitudeScale);
1181
+ if (y === 0) ctx.moveTo(x, y);else ctx.lineTo(x, y);
1182
+ }
1183
+ }
1184
+ }, {
1185
+ key: "createFillPath",
1186
+ value: function createFillPath(ctx, baseX, time) {
1187
+ var phase = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
1188
+ var amplitudeScale = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
1189
+ var step = Math.max(1.8, this.height / 92);
1190
+ ctx.beginPath();
1191
+ ctx.moveTo(0, 0);
1192
+ ctx.lineTo(baseX + this.edgeOffset(0, time, phase, amplitudeScale), 0);
1193
+ for (var y = step; y <= this.height + step; y += step) {
1194
+ ctx.lineTo(baseX + this.edgeOffset(y, time, phase, amplitudeScale), y);
1195
+ }
1196
+ ctx.lineTo(0, this.height);
1197
+ ctx.closePath();
1198
+ }
1199
+ }, {
1200
+ key: "drawEllipticalGlow",
1201
+ value: function drawEllipticalGlow(x, y, radiusX, radiusY, color, alpha) {
1202
+ var ctx = this.ctx;
1203
+ ctx.save();
1204
+ ctx.translate(x, y);
1205
+ ctx.scale(1, radiusY / radiusX);
1206
+ var gradient = ctx.createRadialGradient(0, 0, 0, 0, 0, radiusX);
1207
+ gradient.addColorStop(0, hexToRgba(color, alpha));
1208
+ gradient.addColorStop(0.42, hexToRgba(color, alpha * 0.48));
1209
+ gradient.addColorStop(1, hexToRgba(color, 0));
1210
+ ctx.globalCompositeOperation = 'screen';
1211
+ ctx.fillStyle = gradient;
1212
+ ctx.fillRect(-radiusX, -radiusX, radiusX * 2, radiusX * 2);
1213
+ ctx.restore();
1214
+ }
1215
+ }, {
1216
+ key: "drawDarkEllipticalShadow",
1217
+ value: function drawDarkEllipticalShadow(x, y, radiusX, radiusY, alpha) {
1218
+ var ctx = this.ctx;
1219
+ ctx.save();
1220
+ ctx.translate(x, y);
1221
+ ctx.scale(1, radiusY / radiusX);
1222
+ var gradient = ctx.createRadialGradient(0, 0, 0, 0, 0, radiusX);
1223
+ gradient.addColorStop(0, "rgba(6, 6, 11, ".concat(alpha, ")"));
1224
+ gradient.addColorStop(0.54, "rgba(8, 8, 14, ".concat(alpha * 0.62, ")"));
1225
+ gradient.addColorStop(1, 'rgba(8, 8, 14, 0)');
1226
+ ctx.globalCompositeOperation = 'source-over';
1227
+ ctx.fillStyle = gradient;
1228
+ ctx.fillRect(-radiusX, -radiusX, radiusX * 2, radiusX * 2);
1229
+ ctx.restore();
1230
+ }
1231
+ }, {
1232
+ key: "drawColorClouds",
1233
+ value: function drawColorClouds(shoreline, time, accentA, accentB, glow) {
1234
+ this.ctx;
1235
+ var width = this.width;
1236
+ var height = this.height;
1237
+ var scale = this.profile.cloudWidth;
1238
+ var t = time * this.profile.timeScale;
1239
+ var upperY = height * (0.28 + Math.sin(t * 0.24 + this.seed) * 0.13);
1240
+ var lowerY = height * (0.70 + Math.cos(t * 0.21 + this.seed * 1.7) * 0.12);
1241
+ var middleY = height * (0.49 + Math.sin(t * 0.31 + this.seed * 2.3) * 0.15);
1242
+ var farX = shoreline - width * 0.095;
1243
+ var farRx = Math.max(52, width * scale);
1244
+ var farRy = height * 0.42;
1245
+ this.drawEllipticalGlow(farX, upperY, farRx, farRy, accentA, 0.38);
1246
+ this.drawDarkEllipticalShadow(farX + farRx * 0.16, upperY, farRx * 0.58, farRy * 0.66, 0.74);
1247
+ var lowerX = shoreline - width * 0.072;
1248
+ var lowerRx = Math.max(44, width * scale * 0.82);
1249
+ var lowerRy = height * 0.36;
1250
+ this.drawEllipticalGlow(lowerX, lowerY, lowerRx, lowerRy, accentB, 0.31);
1251
+ this.drawDarkEllipticalShadow(lowerX + lowerRx * 0.14, lowerY, lowerRx * 0.54, lowerRy * 0.62, 0.64);
1252
+ this.drawEllipticalGlow(shoreline - width * 0.034, middleY, Math.max(30, width * scale * 0.48), height * 0.27, glow, 0.20);
1253
+ }
1254
+ }, {
1255
+ key: "drawPathBand",
1256
+ value: function drawPathBand(_ref2) {
1257
+ var baseX = _ref2.baseX,
1258
+ time = _ref2.time,
1259
+ phase = _ref2.phase,
1260
+ amplitudeScale = _ref2.amplitudeScale,
1261
+ color = _ref2.color,
1262
+ alpha = _ref2.alpha,
1263
+ blur = _ref2.blur,
1264
+ width = _ref2.width,
1265
+ _ref2$composite = _ref2.composite,
1266
+ composite = _ref2$composite === void 0 ? 'screen' : _ref2$composite;
1267
+ var ctx = this.ctx;
1268
+ this.createEdgePath(ctx, baseX, time, phase, amplitudeScale);
1269
+ ctx.save();
1270
+ ctx.globalCompositeOperation = composite;
1271
+ ctx.globalAlpha = alpha;
1272
+ // Safari < 18 and some old WebViews ignore ctx.filter; setting it is a
1273
+ // no-op there, so only assign when supported to keep intent explicit.
1274
+ if (SUPPORTS_CTX_FILTER) ctx.filter = "blur(".concat(blur, "px)");
1275
+ ctx.strokeStyle = color;
1276
+ ctx.lineWidth = width;
1277
+ ctx.stroke();
1278
+ ctx.restore();
1279
+ }
1280
+ }, {
1281
+ key: "setRange",
1282
+ value: function setRange(min, max) {
1283
+ this.min = min;
1284
+ this.max = max;
1285
+ var clamped = clamp(this.value, this.min, this.max);
1286
+ if (clamped !== this.value) this.setProgress(clamped, 'prop');
1287
+ }
1288
+ }, {
1289
+ key: "drawReferenceFlow",
1290
+ value: function drawReferenceFlow() {
1291
+ var ctx = this.ctx;
1292
+ var width = this.width;
1293
+ var height = this.height;
1294
+ if (!ctx || width <= 0 || height <= 0) return;
1295
+ var shoreline = width * (this.value / 100);
1296
+ var time = this.flowTime;
1297
+ var _this$preset$colors = _slicedToArray(this.preset.colors, 4),
1298
+ dark = _this$preset$colors[0],
1299
+ accentA = _this$preset$colors[1],
1300
+ accentB = _this$preset$colors[2],
1301
+ glow = _this$preset$colors[3];
1302
+ ctx.clearRect(0, 0, width, height);
1303
+ ctx.fillStyle = '#202126';
1304
+ ctx.fillRect(0, 0, width, height);
1305
+ this.createFillPath(ctx, shoreline, time, 0, 1);
1306
+ var bodyGradient = ctx.createLinearGradient(0, 0, Math.max(shoreline, 1), 0);
1307
+ bodyGradient.addColorStop(0, dark);
1308
+ bodyGradient.addColorStop(0.74, dark);
1309
+ bodyGradient.addColorStop(0.89, hexToRgba(dark, 0.99));
1310
+ bodyGradient.addColorStop(0.955, hexToRgba(accentA, 0.09));
1311
+ bodyGradient.addColorStop(0.992, hexToRgba(accentB, 0.54));
1312
+ bodyGradient.addColorStop(1, hexToRgba(glow, 0.78));
1313
+ ctx.fillStyle = bodyGradient;
1314
+ ctx.fill();
1315
+ this.drawColorClouds(shoreline, time, accentA, accentB, glow);
1316
+ this.drawPathBand({
1317
+ baseX: shoreline - width * 0.105,
1318
+ time: time,
1319
+ phase: 1.42,
1320
+ amplitudeScale: 1.18,
1321
+ color: accentA,
1322
+ alpha: 0.22,
1323
+ blur: 21,
1324
+ width: 54
1325
+ });
1326
+ this.drawPathBand({
1327
+ baseX: shoreline - width * 0.073,
1328
+ time: time,
1329
+ phase: -0.92,
1330
+ amplitudeScale: 1.06,
1331
+ color: accentB,
1332
+ alpha: 0.30,
1333
+ blur: 15,
1334
+ width: 42
1335
+ });
1336
+ this.drawPathBand({
1337
+ baseX: shoreline - width * 0.047,
1338
+ time: time,
1339
+ phase: 0.42,
1340
+ amplitudeScale: 0.94,
1341
+ color: 'rgba(5, 5, 10, 0.92)',
1342
+ alpha: 0.72,
1343
+ blur: 12,
1344
+ width: 34,
1345
+ composite: 'source-over'
1346
+ });
1347
+ this.drawPathBand({
1348
+ baseX: shoreline - width * 0.025,
1349
+ time: time,
1350
+ phase: -0.28,
1351
+ amplitudeScale: 0.96,
1352
+ color: accentB,
1353
+ alpha: 0.66,
1354
+ blur: 8,
1355
+ width: 28
1356
+ });
1357
+ ctx.save();
1358
+ this.createFillPath(ctx, shoreline, time, 0, 1);
1359
+ ctx.clip();
1360
+ this.createEdgePath(ctx, shoreline, time, 0, 1);
1361
+ ctx.save();
1362
+ ctx.globalCompositeOperation = 'screen';
1363
+ ctx.strokeStyle = hexToRgba(accentA, 0.20);
1364
+ ctx.lineWidth = this.profile.haloWidth;
1365
+ ctx.shadowColor = accentA;
1366
+ ctx.shadowBlur = this.profile.haloWidth * 0.72;
1367
+ ctx.stroke();
1368
+ ctx.restore();
1369
+ ctx.save();
1370
+ ctx.globalCompositeOperation = 'screen';
1371
+ ctx.strokeStyle = hexToRgba(accentB, 0.78);
1372
+ ctx.lineWidth = this.profile.glowWidth + 4.2;
1373
+ ctx.shadowColor = accentB;
1374
+ ctx.shadowBlur = 8;
1375
+ ctx.stroke();
1376
+ ctx.restore();
1377
+ ctx.save();
1378
+ ctx.globalCompositeOperation = 'screen';
1379
+ ctx.strokeStyle = hexToRgba(glow, 0.88);
1380
+ ctx.lineWidth = this.profile.glowWidth;
1381
+ ctx.shadowColor = glow;
1382
+ ctx.shadowBlur = 5;
1383
+ ctx.stroke();
1384
+ ctx.restore();
1385
+ ctx.restore();
1386
+ ctx.save();
1387
+ ctx.globalCompositeOperation = 'screen';
1388
+ ctx.strokeStyle = hexToRgba(glow, 0.84);
1389
+ ctx.lineWidth = 2.15;
1390
+ ctx.shadowColor = glow;
1391
+ ctx.shadowBlur = 2.5;
1392
+ this.createEdgePath(ctx, shoreline, time, 0, 1);
1393
+ ctx.stroke();
1394
+ ctx.restore();
1395
+ if (this.profile.whiteAlpha > 0.05) {
1396
+ ctx.save();
1397
+ ctx.globalCompositeOperation = 'screen';
1398
+ ctx.strokeStyle = "rgba(255,255,245,".concat(this.profile.whiteAlpha, ")");
1399
+ ctx.lineWidth = this.profile.whiteWidth;
1400
+ this.createEdgePath(ctx, shoreline, time, 0, 1);
1401
+ ctx.stroke();
1402
+ ctx.restore();
1403
+ }
1404
+ }
1405
+ }, {
1406
+ key: "updateFromPointer",
1407
+ value: function updateFromPointer(event) {
1408
+ var bounds = this.root.getBoundingClientRect();
1409
+ var ratio = bounds.width > 0 ? (event.clientX - bounds.left) / bounds.width : 0;
1410
+ this.setProgress(ratio * 100, 'drag');
1411
+ }
1412
+ }, {
1413
+ key: "beginDrag",
1414
+ value: function beginDrag(event) {
1415
+ if (event.button !== undefined && event.button !== 0) return;
1416
+ event.preventDefault();
1417
+ this.dragging = true;
1418
+ this.root.classList.add('is-dragging');
1419
+ try {
1420
+ var _this$root$setPointer, _this$root;
1421
+ (_this$root$setPointer = (_this$root = this.root).setPointerCapture) === null || _this$root$setPointer === void 0 || _this$root$setPointer.call(_this$root, event.pointerId);
1422
+ } catch (_unused) {}
1423
+ this.emitter.emit('dragstart', {
1424
+ value: this.value
1425
+ });
1426
+ this.updateFromPointer(event);
1427
+ }
1428
+ }, {
1429
+ key: "moveDrag",
1430
+ value: function moveDrag(event) {
1431
+ if (!this.dragging) return;
1432
+ event.preventDefault();
1433
+ this.updateFromPointer(event);
1434
+ }
1435
+ }, {
1436
+ key: "endDrag",
1437
+ value: function endDrag(event) {
1438
+ if (!this.dragging) return;
1439
+ this.dragging = false;
1440
+ this.root.classList.remove('is-dragging');
1441
+ try {
1442
+ var _this$root$hasPointer, _this$root2;
1443
+ if ((event === null || event === void 0 ? void 0 : event.pointerId) !== undefined && (_this$root$hasPointer = (_this$root2 = this.root).hasPointerCapture) !== null && _this$root$hasPointer !== void 0 && _this$root$hasPointer.call(_this$root2, event.pointerId)) {
1444
+ this.root.releasePointerCapture(event.pointerId);
1445
+ }
1446
+ } catch (_unused2) {}
1447
+ this.emitter.emit('dragend', {
1448
+ value: this.value
1449
+ });
1450
+ }
1451
+ }, {
1452
+ key: "bindEvents",
1453
+ value: function bindEvents() {
1454
+ var _this2 = this;
1455
+ if (this.options.draggable !== false) {
1456
+ this.handlers.pointerdown = function (event) {
1457
+ return _this2.beginDrag(event);
1458
+ };
1459
+ this.handlers.pointermove = function (event) {
1460
+ return _this2.moveDrag(event);
1461
+ };
1462
+ this.handlers.pointerup = function (event) {
1463
+ return _this2.endDrag(event);
1464
+ };
1465
+ this.handlers.pointercancel = function (event) {
1466
+ return _this2.endDrag(event);
1467
+ };
1468
+ this.root.addEventListener('pointerdown', this.handlers.pointerdown);
1469
+ this.root.addEventListener('pointermove', this.handlers.pointermove);
1470
+ this.root.addEventListener('pointerup', this.handlers.pointerup);
1471
+ this.root.addEventListener('pointercancel', this.handlers.pointercancel);
1472
+ }
1473
+ if (this.options.keyboard !== false) {
1474
+ this.handlers.keydown = function (event) {
1475
+ var actions = {
1476
+ ArrowLeft: -2,
1477
+ ArrowDown: -2,
1478
+ ArrowRight: 2,
1479
+ ArrowUp: 2,
1480
+ PageDown: -10,
1481
+ PageUp: 10
1482
+ };
1483
+ if (event.key === 'Home') {
1484
+ event.preventDefault();
1485
+ _this2.setProgress(_this2.min, 'keyboard');
1486
+ } else if (event.key === 'End') {
1487
+ event.preventDefault();
1488
+ _this2.setProgress(_this2.max, 'keyboard');
1489
+ } else if (actions[event.key]) {
1490
+ event.preventDefault();
1491
+ _this2.setProgress(_this2.value + actions[event.key], 'keyboard');
1492
+ } else {
1493
+ return;
1494
+ }
1495
+ };
1496
+ this.root.addEventListener('keydown', this.handlers.keydown);
1497
+ }
1498
+ }
1499
+ }, {
1500
+ key: "update",
1501
+ value: function update(delta, paused) {
1502
+ if (!paused) this.flowTime += delta;
1503
+ }
1504
+ }, {
1505
+ key: "draw",
1506
+ value: function draw() {
1507
+ // Performance fix: when the WebGL overlay is active the 2D layer is
1508
+ // hidden behind it, so drawing it every frame would be wasted CPU.
1509
+ if (this.webglActive) return;
1510
+ this.drawReferenceFlow();
1511
+ }
1512
+ }, {
1513
+ key: "randomize",
1514
+ value: function randomize() {
1515
+ this.flowTime = this.random() * 40;
1516
+ }
1517
+ }, {
1518
+ key: "setColors",
1519
+ value: function setColors(colors) {
1520
+ if (!Array.isArray(colors) || colors.length !== 4) return;
1521
+ this.preset = _objectSpread2(_objectSpread2({}, this.preset), {}, {
1522
+ colors: colors
1523
+ });
1524
+ }
1525
+ }, {
1526
+ key: "dispose",
1527
+ value: function dispose() {
1528
+ if (this.resizeObserver) this.resizeObserver.disconnect();else window.removeEventListener('resize', this.resizeCanvas);
1529
+ for (var _i = 0, _Object$keys = Object.keys(this.handlers); _i < _Object$keys.length; _i++) {
1530
+ var name = _Object$keys[_i];
1531
+ var handler = this.handlers[name];
1532
+ this.root.removeEventListener(name, handler);
1533
+ }
1534
+ this.handlers = {};
1535
+ }
1536
+ }]);
1537
+ }();
1538
+
1539
+ /**
1540
+ * Mount a fluid progress capsule into `container`.
1541
+ *
1542
+ * Options: preset (id/code/name or object), width, height, value, min, max,
1543
+ * draggable, keyboard, colors, edgeStyle, quality,
1544
+ * respectReducedMotion, copy, cssVars.
1545
+ */
1546
+ function createProgressCapsule(container) {
1547
+ var _options$preset, _merged$min, _merged$max;
1548
+ var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1549
+ if (!container || typeof container.appendChild !== 'function') {
1550
+ throw new Error('createProgressCapsule: container element is required');
1551
+ }
1552
+ var preset = _objectSpread2({}, getPreset('progress', (_options$preset = options.preset) !== null && _options$preset !== void 0 ? _options$preset : 'NC-10'));
1553
+ var merged = normalizeOptions(DEFAULTS.progress, preset, options);
1554
+ var copy = _objectSpread2(_objectSpread2({}, COPY), merged.copy || {});
1555
+ var root = document.createElement('div');
1556
+ root.className = 'hj-capsule-root hj-progress-root';
1557
+ root.setAttribute('role', 'slider');
1558
+ root.setAttribute('tabindex', '0');
1559
+ root.setAttribute('data-draggable', String(merged.draggable !== false));
1560
+ root.setAttribute('aria-valuemin', String((_merged$min = merged.min) !== null && _merged$min !== void 0 ? _merged$min : 0));
1561
+ root.setAttribute('aria-valuemax', String((_merged$max = merged.max) !== null && _merged$max !== void 0 ? _merged$max : 100));
1562
+ root.setAttribute('aria-valuenow', String(preset.initialProgress));
1563
+ root.setAttribute('aria-label', interpolate(copy.progressAria, {
1564
+ brand: copy.brandName,
1565
+ code: preset.code,
1566
+ name: preset.name
1567
+ }));
1568
+ if (merged.keyboard === false) root.setAttribute('tabindex', '-1');
1569
+ var canvas = document.createElement('canvas');
1570
+ canvas.className = 'hj-progress-canvas';
1571
+ canvas.setAttribute('aria-hidden', 'true');
1572
+ var copyEnabled = copy.enabled !== false && merged.showCopy !== false;
1573
+ var copyText = function copyText(key, fallback) {
1574
+ var value = copy[key];
1575
+ return value === undefined ? fallback : value;
1576
+ };
1577
+ function buildCopyHtml() {
1578
+ var html = '';
1579
+ var brandText = copy.brandName || '';
1580
+ var subtitleText = copyText('subtitle', preset.subtitle);
1581
+ if (brandText) html += "<span class=\"hj-progress-name\">".concat(brandText, "</span>");
1582
+ if (subtitleText) html += "<span class=\"hj-progress-subtitle\">".concat(subtitleText, "</span>");
1583
+ return html;
1584
+ }
1585
+ var copyLayer = document.createElement('div');
1586
+ copyLayer.className = 'hj-progress-copy';
1587
+ var renderCopy = function renderCopy() {
1588
+ if (copyEnabled) copyLayer.innerHTML = buildCopyHtml();
1589
+ };
1590
+ renderCopy();
1591
+ if (copy.background) {
1592
+ root.style.setProperty('--hj-progress-copy-bg', copy.background);
1593
+ root.style.setProperty('--hj-progress-copy-pad', '6px 12px');
1594
+ }
1595
+ if (copy.color) root.style.setProperty('--hj-progress-copy-color', copy.color);
1596
+ var valueElement = document.createElement('div');
1597
+ valueElement.className = 'hj-progress-value';
1598
+ valueElement.setAttribute('aria-hidden', 'true');
1599
+ var dragLabel = document.createElement('span');
1600
+ dragLabel.className = 'hj-progress-drag-label';
1601
+ dragLabel.setAttribute('aria-hidden', 'true');
1602
+ dragLabel.textContent = copy.dragLabel;
1603
+ root.appendChild(canvas);
1604
+ if (copyEnabled) root.appendChild(copyLayer);
1605
+ root.appendChild(valueElement);
1606
+ root.appendChild(dragLabel);
1607
+ container.appendChild(root);
1608
+ var emitter = createEmitter();
1609
+ var paused = merged.respectReducedMotion && prefersReducedMotion();
1610
+ var applySize = function applySize() {
1611
+ root.style.width = parseSize(merged.width);
1612
+ root.style.height = parseSize(merged.height);
1613
+ var vars = merged.cssVars || {};
1614
+ for (var _i2 = 0, _Object$keys2 = Object.keys(vars); _i2 < _Object$keys2.length; _i2++) {
1615
+ var name = _Object$keys2[_i2];
1616
+ root.style.setProperty(name, vars[name]);
1617
+ }
1618
+ };
1619
+ applySize();
1620
+ var controller = new ProgressCapsuleController({
1621
+ root: root,
1622
+ canvas: canvas,
1623
+ valueElement: valueElement,
1624
+ preset: preset,
1625
+ emitter: emitter,
1626
+ options: merged,
1627
+ copy: copy
1628
+ });
1629
+ var overlay = null;
1630
+ if (merged.renderer !== 'canvas2d') {
1631
+ overlay = attachProgressFlowOverlay({
1632
+ root: root,
1633
+ canvas: canvas,
1634
+ preset: preset,
1635
+ getProgress: function getProgress() {
1636
+ return controller.value;
1637
+ }
1638
+ });
1639
+ }
1640
+ if (overlay) controller.webglActive = true;
1641
+ var visibility = createVisibilityGuard(root);
1642
+ var flowTime = 0;
1643
+ var unsubscribe = subscribeScheduler(function (delta, now) {
1644
+ flowTime += delta;
1645
+ controller.update(delta, false);
1646
+ if (visibility.isVisible()) {
1647
+ controller.draw();
1648
+ if (overlay) overlay.update(flowTime);
1649
+ }
1650
+ }, function () {
1651
+ return paused;
1652
+ });
1653
+ emitter.emit('ready', {
1654
+ preset: _objectSpread2({}, preset)
1655
+ });
1656
+ var syncDom = function syncDom() {
1657
+ root.setAttribute('aria-label', interpolate(copy.progressAria, {
1658
+ brand: copy.brandName,
1659
+ code: preset.code,
1660
+ name: preset.name
1661
+ }));
1662
+ renderCopy();
1663
+ };
1664
+ return {
1665
+ element: root,
1666
+ canvas: canvas,
1667
+ preset: preset,
1668
+ on: emitter.on,
1669
+ off: emitter.off,
1670
+ setValue: function setValue(value) {
1671
+ var source = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'prop';
1672
+ controller.setProgress(value, source);
1673
+ return this;
1674
+ },
1675
+ getValue: function getValue() {
1676
+ return controller.value;
1677
+ },
1678
+ setRange: function setRange(min, max) {
1679
+ controller.setRange(min, max);
1680
+ return this;
1681
+ },
1682
+ setPreset: function setPreset(ref) {
1683
+ var next = getPreset('progress', ref);
1684
+ Object.assign(preset, next);
1685
+ controller.preset = next;
1686
+ controller.profile = next.edgeStyle === 'tide' ? FLOW_PROFILES.tide : FLOW_PROFILES[next.id] || FLOW_PROFILES['visual-training'];
1687
+ controller.flowTime = stringSeed(next.id) * 31;
1688
+ controller.seed = stringSeed("".concat(next.id, "-reference")) * Math.PI * 2;
1689
+ syncDom();
1690
+ if (overlay) {
1691
+ overlay.dispose();
1692
+ overlay = attachProgressFlowOverlay({
1693
+ root: root,
1694
+ canvas: canvas,
1695
+ preset: next,
1696
+ getProgress: function getProgress() {
1697
+ return controller.value;
1698
+ }
1699
+ });
1700
+ }
1701
+ controller.webglActive = Boolean(overlay);
1702
+ controller.resizeCanvas();
1703
+ emitter.emit('presetchange', {
1704
+ preset: _objectSpread2({}, next)
1705
+ });
1706
+ return this;
1707
+ },
1708
+ setColors: function setColors(colors) {
1709
+ if (!Array.isArray(colors) || colors.length !== 4) return this;
1710
+ controller.setColors(colors);
1711
+ if (overlay) overlay.setColors(colors);
1712
+ controller.resizeCanvas();
1713
+ return this;
1714
+ },
1715
+ setSize: function setSize(width, height) {
1716
+ if (width !== undefined) merged.width = width;
1717
+ if (height !== undefined) merged.height = height;
1718
+ applySize();
1719
+ controller.resizeCanvas();
1720
+ return this;
1721
+ },
1722
+ randomize: function randomize() {
1723
+ controller.randomize();
1724
+ return this;
1725
+ },
1726
+ pause: function pause() {
1727
+ paused = true;
1728
+ return this;
1729
+ },
1730
+ resume: function resume() {
1731
+ paused = false;
1732
+ return this;
1733
+ },
1734
+ setQuality: function setQuality(quality) {
1735
+ merged.quality = quality;
1736
+ controller.dprCap = dprCapFor(quality);
1737
+ controller.resizeCanvas();
1738
+ return this;
1739
+ },
1740
+ dispose: function dispose() {
1741
+ unsubscribe();
1742
+ visibility.dispose();
1743
+ if (overlay) overlay.dispose();
1744
+ controller.dispose();
1745
+ root.remove();
1746
+ }
1747
+ };
1748
+ }
1749
+
1750
+ exports.ProgressCapsuleController = ProgressCapsuleController;
1751
+ exports.createProgressCapsule = createProgressCapsule;