@5even7/dlc-ui 0.2.18 → 0.2.20
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/CHANGELOG.md +158 -144
- package/EXTENDING.md +114 -0
- package/LICENSE +21 -21
- package/README.md +389 -338
- package/THIRD_PARTY_NOTICES.md +221 -0
- package/dist/avatar-creator/styles/humation.mjs +26 -0
- package/dist/avatar-creator/styles.mjs +76 -0
- package/dist/avatar-creator.cjs +7831 -0
- package/dist/avatar-creator.mjs +74 -0
- package/dist/capsule.cjs +185 -66
- package/dist/capsule.mjs +364 -1340
- package/dist/chunks/avatar-creator-DiAmhpRa.mjs +687 -0
- package/dist/chunks/color-DnmNceaf.mjs +350 -0
- package/dist/chunks/controls-B5_ctvvA.mjs +160 -0
- package/dist/chunks/copy-7J0XIj_0.mjs +13 -0
- package/dist/chunks/cosmic-fallback-v8G5_ibh.mjs +408 -0
- package/dist/chunks/emitter-CxLYMSbw.mjs +38 -0
- package/dist/chunks/emo-Dvahy5Qr.mjs +1140 -0
- package/dist/chunks/hash-BiO02UNb.mjs +38 -0
- package/dist/chunks/humation-B9OPUGL7.mjs +2987 -0
- package/dist/chunks/identicon-BUdMd-yf.mjs +3063 -0
- package/dist/chunks/index-BchW1tWE.mjs +478 -0
- package/dist/chunks/index-BtH8Lbra.mjs +296 -0
- package/dist/chunks/index-C02dvGLD.mjs +263 -0
- package/dist/chunks/index-CFybYBA1.mjs +278 -0
- package/dist/chunks/index-DgI872-7.mjs +241 -0
- package/dist/chunks/index-_sf_14Zu.mjs +455 -0
- package/dist/chunks/index-w5Pzdwhv.mjs +305 -0
- package/dist/chunks/motion-a8_f8_Ui.mjs +177 -0
- package/dist/chunks/number-BqWLX0iQ.mjs +231 -0
- package/dist/chunks/progress-KweS4Rx0.mjs +1836 -0
- package/dist/chunks/size-Bztk2ryJ.mjs +22 -0
- package/dist/chunks/wrapper-DXhy1E7Z.mjs +514 -0
- package/dist/color.cjs +186 -67
- package/dist/color.mjs +341 -1280
- package/dist/emo/miao/angry.mjs +4 -0
- package/dist/emo/miao/asleep.mjs +4 -0
- package/dist/emo/miao/badminton.mjs +4 -0
- package/dist/emo/miao/confident.mjs +4 -0
- package/dist/emo/miao/cry.mjs +4 -0
- package/dist/emo/miao/investigate.mjs +4 -0
- package/dist/emo/miao/laugh.mjs +4 -0
- package/dist/emo/miao/leisure.mjs +4 -0
- package/dist/emo/miao/mock.mjs +4 -0
- package/dist/emo/miao/music.mjs +4 -0
- package/dist/emo/miao/mute.mjs +4 -0
- package/dist/emo/miao/panic.mjs +4 -0
- package/dist/emo/miao/ponder.mjs +4 -0
- package/dist/emo/miao/question.mjs +4 -0
- package/dist/emo/miao/sad.mjs +4 -0
- package/dist/emo/miao/shocked.mjs +4 -0
- package/dist/emo/miao/shy.mjs +4 -0
- package/dist/emo/miao/sigh.mjs +4 -0
- package/dist/emo/miao/smile.mjs +4 -0
- package/dist/emo/miao/snigger.mjs +4 -0
- package/dist/emo/miao/static.mjs +4 -0
- package/dist/emo/miao/yawn.mjs +4 -0
- package/dist/emo/miao/yummy.mjs +4 -0
- package/dist/emo.cjs +27161 -25964
- package/dist/emo.mjs +8 -1421
- package/dist/index.cjs +32729 -24466
- package/dist/index.mjs +16 -4757
- package/dist/index.umd.js +33115 -24852
- package/dist/index.umd.min.js +3 -1
- package/dist/progress.cjs +195 -76
- package/dist/progress.mjs +7 -2448
- package/dist/vue2.cjs +33282 -25002
- package/dist/vue2.mjs +63 -5131
- package/dist/vue3.cjs +33282 -25002
- package/dist/vue3.mjs +53 -5122
- package/package.json +161 -136
- package/styles/avatar-creator.css +38 -0
- package/styles/base.css +32 -32
- package/styles/color.css +18 -18
- package/styles/emo.css +110 -89
- package/styles/progress.css +96 -96
- package/styles/theme.css +1 -0
- package/types/avatar-creator-styles.d.ts +10 -0
- package/types/avatar-creator.d.ts +143 -0
- package/types/capsule.d.ts +15 -15
- package/types/color.d.ts +15 -15
- package/types/emo-miao.d.ts +9 -0
- package/types/emo.d.ts +38 -37
- package/types/index.d.ts +593 -554
- package/types/progress.d.ts +16 -16
- package/types/vue2.d.ts +11 -10
- package/types/vue3.d.ts +169 -146
package/dist/color.mjs
CHANGED
|
@@ -1,1305 +1,366 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
// Plain object storage (no Map/Set) so the legacy build has no API
|
|
7
|
-
// dependencies beyond what IE11 provides.
|
|
8
|
-
const listeners = Object.create(null);
|
|
9
|
-
|
|
10
|
-
return {
|
|
11
|
-
on(event, fn) {
|
|
12
|
-
if (!listeners[event]) listeners[event] = [];
|
|
13
|
-
listeners[event].push(fn);
|
|
14
|
-
return () => {
|
|
15
|
-
const current = listeners[event];
|
|
16
|
-
if (current) {
|
|
17
|
-
const index = current.indexOf(fn);
|
|
18
|
-
if (index !== -1) current.splice(index, 1);
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
},
|
|
22
|
-
off(event, fn) {
|
|
23
|
-
const current = listeners[event];
|
|
24
|
-
if (!current) return false;
|
|
25
|
-
const index = current.indexOf(fn);
|
|
26
|
-
if (index === -1) return false;
|
|
27
|
-
current.splice(index, 1);
|
|
28
|
-
return true;
|
|
29
|
-
},
|
|
30
|
-
emit(event, ...args) {
|
|
31
|
-
const current = listeners[event];
|
|
32
|
-
if (!current) return;
|
|
33
|
-
for (const fn of current.slice()) fn(...args);
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
}
|
|
1
|
+
import { c as createEmitter } from './chunks/emitter-CxLYMSbw.mjs';
|
|
2
|
+
import { g as getPreset, n as normalizeOptions, D as DEFAULTS, t as toFiniteNumber, e as effectiveDprCap, b as nextTick } from './chunks/number-BqWLX0iQ.mjs';
|
|
3
|
+
import { C as CosmicRenderer, F as FallbackRenderer } from './chunks/cosmic-fallback-v8G5_ibh.mjs';
|
|
4
|
+
import { w as wakeScheduler, c as createFrameGate, a as createVisibilityGuard, b as createReducedMotionPreference, s as subscribeScheduler } from './chunks/motion-a8_f8_Ui.mjs';
|
|
5
|
+
import { n as normalizeColor } from './chunks/color-DnmNceaf.mjs';
|
|
37
6
|
|
|
38
|
-
const
|
|
39
|
-
low: { dpr: 1 },
|
|
40
|
-
medium: { dpr: 1.5 },
|
|
41
|
-
high: { dpr: 2 }
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
function autoDprCap() {
|
|
45
|
-
const nav = typeof navigator !== 'undefined' ? navigator : null;
|
|
46
|
-
const memory = nav && typeof nav.deviceMemory === 'number' ? nav.deviceMemory : 8;
|
|
47
|
-
const cores = nav && typeof nav.hardwareConcurrency === 'number' ? nav.hardwareConcurrency : 8;
|
|
48
|
-
return memory <= 4 || cores <= 4 ? 1.5 : 2;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function dprCapFor(quality) {
|
|
52
|
-
if (quality === 'auto') return autoDprCap();
|
|
53
|
-
const tier = QUALITY_TIERS[quality] || QUALITY_TIERS.medium;
|
|
54
|
-
return tier.dpr;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function effectiveDprCap(quality, renderScale = 1) {
|
|
58
|
-
const scale = Number(renderScale);
|
|
59
|
-
const normalizedScale = Number.isFinite(scale) ? Math.min(1, Math.max(0.25, scale)) : 1;
|
|
60
|
-
return Math.max(0.5, dprCapFor(quality) * normalizedScale);
|
|
61
|
-
}
|
|
7
|
+
const HOST_STYLES = new WeakMap();
|
|
62
8
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const presetOptions = omitUndefined(preset && typeof preset === 'object' ? preset : {});
|
|
79
|
-
const userOptions = omitUndefined(user && typeof user === 'object' ? user : {});
|
|
80
|
-
return { ...defaults, ...presetOptions, ...userOptions };
|
|
9
|
+
function acquireHostStyles(host) {
|
|
10
|
+
const active = HOST_STYLES.get(host);
|
|
11
|
+
if (active) {
|
|
12
|
+
active.count += 1;
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const state = {
|
|
16
|
+
count: 1,
|
|
17
|
+
position: host.style.position,
|
|
18
|
+
isolation: host.style.isolation
|
|
19
|
+
};
|
|
20
|
+
const computed = getComputedStyle(host);
|
|
21
|
+
if (computed.position === 'static' || computed.position === '') host.style.position = 'relative';
|
|
22
|
+
host.style.isolation = 'isolate';
|
|
23
|
+
HOST_STYLES.set(host, state);
|
|
81
24
|
}
|
|
82
25
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
chrome: ['#F5F6F8', '#B9C0CC', '#7F8793', '#4A4F59'],
|
|
93
|
-
plus: ['#FFF0E6', '#F6C26B', '#F98A64', '#E86D74']
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Capsule 预置:仅星云材质 NC-01~NC-06(NC-07~09 aurora 已移除)。
|
|
98
|
-
* 颜色引用公共色板,seed/speed 决定形态与流速。
|
|
99
|
-
*/
|
|
100
|
-
const CAPSULE_PRESETS = [
|
|
101
|
-
{ id: 'original', code: 'NC-01', name: '初光', group: 'warm', seed: 1.7, speed: 0.5, colors: [...PALETTES.original] },
|
|
102
|
-
{ id: 'ocean', code: 'NC-02', name: '沧溟', group: 'cold', seed: 8.2, speed: 0.48, colors: [...PALETTES.ocean] },
|
|
103
|
-
{ id: 'klein', code: 'NC-03', name: '玄夜', group: 'cold', seed: 14.1, speed: 0.49, colors: [...PALETTES.klein] },
|
|
104
|
-
{ id: 'ultraviolet', code: 'NC-04', name: '紫霄', group: 'cold', seed: 23.4, speed: 0.47, colors: [...PALETTES.ultraviolet] },
|
|
105
|
-
{ id: 'chrome', code: 'NC-05', name: '银汉', group: 'cold', seed: 37.8, speed: 0.42, colors: [...PALETTES.chrome] },
|
|
106
|
-
{ id: 'plus', code: 'NC-06', name: '熔金', group: 'warm', seed: 51.3, speed: 0.5, colors: [...PALETTES.plus] }
|
|
107
|
-
];
|
|
26
|
+
function releaseHostStyles(host) {
|
|
27
|
+
const state = HOST_STYLES.get(host);
|
|
28
|
+
if (!state) return;
|
|
29
|
+
state.count -= 1;
|
|
30
|
+
if (state.count > 0) return;
|
|
31
|
+
host.style.position = state.position;
|
|
32
|
+
host.style.isolation = state.isolation;
|
|
33
|
+
HOST_STYLES.delete(host);
|
|
34
|
+
}
|
|
108
35
|
|
|
109
36
|
/**
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
37
|
+
* Mount the cosmic (nebula) material as a background layer inside `host`.
|
|
38
|
+
*
|
|
39
|
+
* The layer is absolutely positioned and defaults to `z-index: -1`, so it
|
|
40
|
+
* paints behind the host's in-flow content: text/buttons/images inside the
|
|
41
|
+
* host sit on top with zero extra CSS. Host gets `position: relative;
|
|
42
|
+
* isolation: isolate` automatically so the layer can never escape its box
|
|
43
|
+
* (or break stacking outside it).
|
|
44
|
+
*
|
|
45
|
+
* Options: preset (literary name), colors, seed, speed, quality,
|
|
46
|
+
* renderer, renderScale, powerPreference, fps, paused/static, mouseColor,
|
|
47
|
+
* respectReducedMotion, opacity (0-1), fallbackColor (true=preset base
|
|
48
|
+
* color, a hex string, or false to disable).
|
|
113
49
|
*/
|
|
114
|
-
function
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const key = String(ref).trim().toLowerCase();
|
|
118
|
-
let found = null;
|
|
119
|
-
for (let index = 0; index < list.length; index += 1) {
|
|
120
|
-
if (list[index].name.toLowerCase() === key) {
|
|
121
|
-
found = list[index];
|
|
122
|
-
break;
|
|
123
|
-
}
|
|
50
|
+
function createColorBackground(host, options = {}) {
|
|
51
|
+
if (!host || typeof host.appendChild !== 'function') {
|
|
52
|
+
throw new Error('createColorBackground: host element is required');
|
|
124
53
|
}
|
|
125
|
-
if (!found) throw new Error(`Unknown ${kind} preset: ${ref}`);
|
|
126
|
-
return found;
|
|
127
|
-
}
|
|
128
54
|
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
55
|
+
const preset = { ...getPreset('capsule', options.preset ?? '初光') };
|
|
56
|
+
const merged = normalizeOptions(
|
|
57
|
+
{
|
|
58
|
+
quality: DEFAULTS.capsule.quality,
|
|
59
|
+
renderer: DEFAULTS.capsule.renderer,
|
|
60
|
+
respectReducedMotion: DEFAULTS.capsule.respectReducedMotion,
|
|
61
|
+
mouseColor: true,
|
|
62
|
+
renderScale: 1,
|
|
63
|
+
powerPreference: 'high-performance',
|
|
64
|
+
fps: DEFAULTS.capsule.fps,
|
|
65
|
+
paused: false,
|
|
66
|
+
static: false,
|
|
67
|
+
opacity: 1,
|
|
68
|
+
fallbackColor: true
|
|
69
|
+
},
|
|
70
|
+
preset,
|
|
71
|
+
options
|
|
72
|
+
);
|
|
73
|
+
merged.opacity = Number.isFinite(Number(merged.opacity))
|
|
74
|
+
? Math.min(1, Math.max(0, Number(merged.opacity)))
|
|
75
|
+
: 1;
|
|
76
|
+
const normalizedColors = Array.isArray(merged.colors) ? merged.colors.map(normalizeColor) : [];
|
|
77
|
+
if (normalizedColors.length === 4 && normalizedColors.every(Boolean)) preset.colors = normalizedColors;
|
|
78
|
+
const initialSeed = toFiniteNumber(merged.seed);
|
|
79
|
+
const initialSpeed = toFiniteNumber(merged.speed);
|
|
80
|
+
if (initialSeed !== null) preset.seed = initialSeed;
|
|
81
|
+
if (initialSpeed !== null) preset.speed = initialSpeed;
|
|
82
|
+
merged.colors = [...preset.colors];
|
|
83
|
+
merged.seed = preset.seed;
|
|
84
|
+
merged.speed = preset.speed;
|
|
85
|
+
const optionColors = Array.isArray(options.colors) ? options.colors.map(normalizeColor) : [];
|
|
86
|
+
let colorOverride = optionColors.length === 4 && optionColors.every(Boolean)
|
|
87
|
+
? [...optionColors]
|
|
88
|
+
: null;
|
|
89
|
+
let seedOverride = options.seed !== undefined ? toFiniteNumber(options.seed) : null;
|
|
90
|
+
let speedOverride = options.speed !== undefined ? toFiniteNumber(options.speed) : null;
|
|
135
91
|
|
|
136
|
-
|
|
137
|
-
* Color helpers. `normalizeColor` converts any supported CSS color
|
|
138
|
-
* (hex / named / rgb() / rgba()) into a 6-digit hex string, so renderers can
|
|
139
|
-
* keep working with #rrggbb only. rgba() alpha is intentionally dropped:
|
|
140
|
-
* the WebGL shader has no per-color alpha channel, and the component is
|
|
141
|
-
* opaque by design — use component-level `opacity` for transparency.
|
|
142
|
-
*/
|
|
92
|
+
acquireHostStyles(host);
|
|
143
93
|
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
antiquewhite: '#faebd7',
|
|
147
|
-
aqua: '#00ffff',
|
|
148
|
-
aquamarine: '#7fffd4',
|
|
149
|
-
azure: '#f0ffff',
|
|
150
|
-
beige: '#f5f5dc',
|
|
151
|
-
bisque: '#ffe4c4',
|
|
152
|
-
black: '#000000',
|
|
153
|
-
blanchedalmond: '#ffebcd',
|
|
154
|
-
blue: '#0000ff',
|
|
155
|
-
blueviolet: '#8a2be2',
|
|
156
|
-
brown: '#a52a2a',
|
|
157
|
-
burlywood: '#deb887',
|
|
158
|
-
cadetblue: '#5f9ea0',
|
|
159
|
-
chartreuse: '#7fff00',
|
|
160
|
-
chocolate: '#d2691e',
|
|
161
|
-
coral: '#ff7f50',
|
|
162
|
-
cornflowerblue: '#6495ed',
|
|
163
|
-
cornsilk: '#fff8dc',
|
|
164
|
-
crimson: '#dc143c',
|
|
165
|
-
cyan: '#00ffff',
|
|
166
|
-
darkblue: '#00008b',
|
|
167
|
-
darkcyan: '#008b8b',
|
|
168
|
-
darkgoldenrod: '#b8860b',
|
|
169
|
-
darkgray: '#a9a9a9',
|
|
170
|
-
darkgreen: '#006400',
|
|
171
|
-
darkgrey: '#a9a9a9',
|
|
172
|
-
darkkhaki: '#bdb76b',
|
|
173
|
-
darkmagenta: '#8b008b',
|
|
174
|
-
darkolivegreen: '#556b2f',
|
|
175
|
-
darkorange: '#ff8c00',
|
|
176
|
-
darkorchid: '#9932cc',
|
|
177
|
-
darkred: '#8b0000',
|
|
178
|
-
darksalmon: '#e9967a',
|
|
179
|
-
darkseagreen: '#8fbc8f',
|
|
180
|
-
darkslateblue: '#483d8b',
|
|
181
|
-
darkslategray: '#2f4f4f',
|
|
182
|
-
darkslategrey: '#2f4f4f',
|
|
183
|
-
darkturquoise: '#00ced1',
|
|
184
|
-
darkviolet: '#9400d3',
|
|
185
|
-
deeppink: '#ff1493',
|
|
186
|
-
deepskyblue: '#00bfff',
|
|
187
|
-
dimgray: '#696969',
|
|
188
|
-
dimgrey: '#696969',
|
|
189
|
-
dodgerblue: '#1e90ff',
|
|
190
|
-
firebrick: '#b22222',
|
|
191
|
-
floralwhite: '#fffaf0',
|
|
192
|
-
forestgreen: '#228b22',
|
|
193
|
-
fuchsia: '#ff00ff',
|
|
194
|
-
gainsboro: '#dcdcdc',
|
|
195
|
-
ghostwhite: '#f8f8ff',
|
|
196
|
-
gold: '#ffd700',
|
|
197
|
-
goldenrod: '#daa520',
|
|
198
|
-
gray: '#808080',
|
|
199
|
-
green: '#008000',
|
|
200
|
-
greenyellow: '#adff2f',
|
|
201
|
-
grey: '#808080',
|
|
202
|
-
honeydew: '#f0fff0',
|
|
203
|
-
hotpink: '#ff69b4',
|
|
204
|
-
indianred: '#cd5c5c',
|
|
205
|
-
indigo: '#4b0082',
|
|
206
|
-
ivory: '#fffff0',
|
|
207
|
-
khaki: '#f0e68c',
|
|
208
|
-
lavender: '#e6e6fa',
|
|
209
|
-
lavenderblush: '#fff0f5',
|
|
210
|
-
lawngreen: '#7cfc00',
|
|
211
|
-
lemonchiffon: '#fffacd',
|
|
212
|
-
lightblue: '#add8e6',
|
|
213
|
-
lightcoral: '#f08080',
|
|
214
|
-
lightcyan: '#e0ffff',
|
|
215
|
-
lightgoldenrodyellow: '#fafad2',
|
|
216
|
-
lightgray: '#d3d3d3',
|
|
217
|
-
lightgreen: '#90ee90',
|
|
218
|
-
lightgrey: '#d3d3d3',
|
|
219
|
-
lightpink: '#ffb6c1',
|
|
220
|
-
lightsalmon: '#ffa07a',
|
|
221
|
-
lightseagreen: '#20b2aa',
|
|
222
|
-
lightskyblue: '#87cefa',
|
|
223
|
-
lightslategray: '#778899',
|
|
224
|
-
lightslategrey: '#778899',
|
|
225
|
-
lightsteelblue: '#b0c4de',
|
|
226
|
-
lightyellow: '#ffffe0',
|
|
227
|
-
lime: '#00ff00',
|
|
228
|
-
limegreen: '#32cd32',
|
|
229
|
-
linen: '#faf0e6',
|
|
230
|
-
magenta: '#ff00ff',
|
|
231
|
-
maroon: '#800000',
|
|
232
|
-
mediumaquamarine: '#66cdaa',
|
|
233
|
-
mediumblue: '#0000cd',
|
|
234
|
-
mediumorchid: '#ba55d3',
|
|
235
|
-
mediumpurple: '#9370db',
|
|
236
|
-
mediumseagreen: '#3cb371',
|
|
237
|
-
mediumslateblue: '#7b68ee',
|
|
238
|
-
mediumspringgreen: '#00fa9a',
|
|
239
|
-
mediumturquoise: '#48d1cc',
|
|
240
|
-
mediumvioletred: '#c71585',
|
|
241
|
-
midnightblue: '#191970',
|
|
242
|
-
mintcream: '#f5fffa',
|
|
243
|
-
mistyrose: '#ffe4e1',
|
|
244
|
-
moccasin: '#ffe4b5',
|
|
245
|
-
navajowhite: '#ffdead',
|
|
246
|
-
navy: '#000080',
|
|
247
|
-
oldlace: '#fdf5e6',
|
|
248
|
-
olive: '#808000',
|
|
249
|
-
olivedrab: '#6b8e23',
|
|
250
|
-
orange: '#ffa500',
|
|
251
|
-
orangered: '#ff4500',
|
|
252
|
-
orchid: '#da70d6',
|
|
253
|
-
palegoldenrod: '#eee8aa',
|
|
254
|
-
palegreen: '#98fb98',
|
|
255
|
-
paleturquoise: '#afeeee',
|
|
256
|
-
palevioletred: '#db7093',
|
|
257
|
-
papayawhip: '#ffefd5',
|
|
258
|
-
peachpuff: '#ffdab9',
|
|
259
|
-
peru: '#cd853f',
|
|
260
|
-
pink: '#ffc0cb',
|
|
261
|
-
plum: '#dda0dd',
|
|
262
|
-
powderblue: '#b0e0e6',
|
|
263
|
-
purple: '#800080',
|
|
264
|
-
rebeccapurple: '#663399',
|
|
265
|
-
red: '#ff0000',
|
|
266
|
-
rosybrown: '#bc8f8f',
|
|
267
|
-
royalblue: '#4169e1',
|
|
268
|
-
saddlebrown: '#8b4513',
|
|
269
|
-
salmon: '#fa8072',
|
|
270
|
-
sandybrown: '#f4a460',
|
|
271
|
-
seagreen: '#2e8b57',
|
|
272
|
-
seashell: '#fff5ee',
|
|
273
|
-
sienna: '#a0522d',
|
|
274
|
-
silver: '#c0c0c0',
|
|
275
|
-
skyblue: '#87ceeb',
|
|
276
|
-
slateblue: '#6a5acd',
|
|
277
|
-
slategray: '#708090',
|
|
278
|
-
slategrey: '#708090',
|
|
279
|
-
snow: '#fffafa',
|
|
280
|
-
springgreen: '#00ff7f',
|
|
281
|
-
steelblue: '#4682b4',
|
|
282
|
-
tan: '#d2b48c',
|
|
283
|
-
teal: '#008080',
|
|
284
|
-
thistle: '#d8bfd8',
|
|
285
|
-
tomato: '#ff6347',
|
|
286
|
-
turquoise: '#40e0d0',
|
|
287
|
-
violet: '#ee82ee',
|
|
288
|
-
wheat: '#f5deb3',
|
|
289
|
-
white: '#ffffff',
|
|
290
|
-
whitesmoke: '#f5f5f5',
|
|
291
|
-
yellow: '#ffff00',
|
|
292
|
-
yellowgreen: '#9acd32'
|
|
293
|
-
};
|
|
94
|
+
const layer = document.createElement('div');
|
|
95
|
+
layer.className = 'dlc-color-layer';
|
|
294
96
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
if (value.charAt(value.length - 1) === '%') return clampChannel((parseFloat(value) / 100) * 255);
|
|
305
|
-
const number = Number(value);
|
|
306
|
-
return Number.isFinite(number) ? clampChannel(number) : null;
|
|
307
|
-
};
|
|
308
|
-
const red = to255(parts[0]);
|
|
309
|
-
const green = to255(parts[1]);
|
|
310
|
-
const blue = to255(parts[2]);
|
|
311
|
-
if (red === null || green === null || blue === null) return null;
|
|
312
|
-
const hex = (n) => {
|
|
313
|
-
const text = n.toString(16);
|
|
314
|
-
return text.length === 1 ? `0${text}` : text;
|
|
97
|
+
const syncLayerVars = () => {
|
|
98
|
+
layer.style.setProperty('--dlc-color-opacity', String(merged.opacity));
|
|
99
|
+
const fallback =
|
|
100
|
+
merged.fallbackColor === false || merged.fallbackColor == null
|
|
101
|
+
? 'transparent'
|
|
102
|
+
: typeof merged.fallbackColor === 'string'
|
|
103
|
+
? merged.fallbackColor
|
|
104
|
+
: preset.colors[0];
|
|
105
|
+
layer.style.setProperty('--dlc-color-bg', fallback);
|
|
315
106
|
};
|
|
316
|
-
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
/**
|
|
320
|
-
* Convert any supported CSS color into `#rrggbb`. Returns null when the
|
|
321
|
-
* value cannot be parsed. Supports: #rgb / #rrggbb (case-insensitive),
|
|
322
|
-
* CSS named colors, rgb() / rgba() with comma or modern space syntax,
|
|
323
|
-
* including percentages. Alpha in rgba() is ignored.
|
|
324
|
-
*/
|
|
325
|
-
function normalizeColor(value) {
|
|
326
|
-
if (typeof value !== 'string') return null;
|
|
327
|
-
const input = value.trim();
|
|
328
|
-
if (!input) return null;
|
|
329
|
-
const lower = input.toLowerCase();
|
|
330
|
-
if (NAMED_COLORS[lower]) return NAMED_COLORS[lower];
|
|
331
|
-
if (/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(input)) {
|
|
332
|
-
const hex = input.slice(1).toLowerCase();
|
|
333
|
-
if (hex.length === 3) return `#${hex.split('').map((c) => c + c).join('')}`;
|
|
334
|
-
return `#${hex}`;
|
|
335
|
-
}
|
|
336
|
-
const match = input.match(/^rgba?\((.*)\)$/i);
|
|
337
|
-
if (match) return normalizeRgbArgs(match[1]);
|
|
338
|
-
return null;
|
|
339
|
-
}
|
|
107
|
+
syncLayerVars();
|
|
340
108
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
((value >> 16) & 255) / 255,
|
|
347
|
-
((value >> 8) & 255) / 255,
|
|
348
|
-
(value & 255) / 255
|
|
349
|
-
];
|
|
350
|
-
}
|
|
109
|
+
const canvas = document.createElement('canvas');
|
|
110
|
+
canvas.className = 'dlc-color-canvas';
|
|
111
|
+
canvas.setAttribute('aria-hidden', 'true');
|
|
112
|
+
layer.appendChild(canvas);
|
|
113
|
+
host.appendChild(layer);
|
|
351
114
|
|
|
352
|
-
const
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
uniform vec3 u_colorC;
|
|
374
|
-
uniform vec3 u_colorD;
|
|
375
|
-
|
|
376
|
-
float hash21(vec2 p) {
|
|
377
|
-
p = fract(p * vec2(123.34, 456.21));
|
|
378
|
-
p += dot(p, p + 45.32 + u_seed);
|
|
379
|
-
return fract(p.x * p.y);
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
float noise(vec2 p) {
|
|
383
|
-
vec2 i = floor(p);
|
|
384
|
-
vec2 f = fract(p);
|
|
385
|
-
f = f * f * (3.0 - 2.0 * f);
|
|
386
|
-
float a = hash21(i);
|
|
387
|
-
float b = hash21(i + vec2(1.0, 0.0));
|
|
388
|
-
float c = hash21(i + vec2(0.0, 1.0));
|
|
389
|
-
float d = hash21(i + vec2(1.0, 1.0));
|
|
390
|
-
return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
float fbm(vec2 p) {
|
|
394
|
-
float value = 0.0;
|
|
395
|
-
float amplitude = 0.52;
|
|
396
|
-
mat2 rotation = mat2(0.80, 0.60, -0.60, 0.80);
|
|
397
|
-
for (int i = 0; i < 6; i++) {
|
|
398
|
-
value += amplitude * noise(p);
|
|
399
|
-
p = rotation * p * 2.03 + 17.7;
|
|
400
|
-
amplitude *= 0.5;
|
|
401
|
-
}
|
|
402
|
-
return value;
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
float gaussian(float value, float center, float width) {
|
|
406
|
-
return exp(-pow(value - center, 2.0) / max(width, 0.0001));
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
vec3 palette(float t) {
|
|
410
|
-
t = clamp(t, 0.0, 1.0);
|
|
411
|
-
vec3 shadow = mix(u_colorA, u_colorB, smoothstep(0.06, 0.62, t));
|
|
412
|
-
vec3 body = mix(u_colorB, u_colorC, smoothstep(0.30, 0.82, t));
|
|
413
|
-
vec3 highlight = mix(u_colorC, u_colorD, smoothstep(0.74, 1.0, t));
|
|
414
|
-
vec3 restrained = mix(shadow, body, smoothstep(0.26, 0.72, t));
|
|
415
|
-
return mix(restrained, highlight, smoothstep(0.78, 0.97, t));
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
vec3 renderNebula(vec2 uv, vec2 p, vec2 pointer, float distanceToPointer, float t) {
|
|
419
|
-
vec2 delta = p - pointer;
|
|
420
|
-
float influence = exp(-distanceToPointer * 4.6) * u_motion;
|
|
421
|
-
float angle = influence * 1.7;
|
|
422
|
-
mat2 swirl = mat2(cos(angle), -sin(angle), sin(angle), cos(angle));
|
|
423
|
-
p = pointer + swirl * delta;
|
|
424
|
-
p += normalize(delta + 0.0001) * influence * 0.08;
|
|
425
|
-
|
|
426
|
-
vec2 drift = vec2(t * 0.22, -t * 0.13);
|
|
427
|
-
vec2 q = vec2(
|
|
428
|
-
fbm(p * 1.35 + drift + u_seed),
|
|
429
|
-
fbm(p * 1.35 + vec2(5.2, 1.3) - drift * 0.85)
|
|
430
|
-
);
|
|
431
|
-
vec2 r = vec2(
|
|
432
|
-
fbm(p * 2.0 + 3.6 * q + vec2(1.7, 9.2) + t * 0.10),
|
|
433
|
-
fbm(p * 2.0 + 3.0 * q + vec2(8.3, 2.8) - t * 0.085)
|
|
434
|
-
);
|
|
435
|
-
|
|
436
|
-
float cloud = fbm(p * 1.7 + 4.2 * r);
|
|
437
|
-
float veins = fbm(p * 4.0 - 2.0 * q + t * 0.065);
|
|
438
|
-
float nebula = smoothstep(0.18, 0.91, cloud * 0.9 + veins * 0.22);
|
|
439
|
-
|
|
440
|
-
vec3 color = palette(nebula);
|
|
441
|
-
color += u_colorD * pow(max(cloud - 0.63, 0.0), 2.0) * 1.05;
|
|
442
|
-
color *= 0.78 + 0.34 * smoothstep(0.15, 0.9, veins);
|
|
443
|
-
|
|
444
|
-
vec2 starGrid = floor((uv + vec2(u_seed * 0.013, 0.0)) * vec2(132.0, 58.0));
|
|
445
|
-
vec2 starCell = fract(uv * vec2(132.0, 58.0)) - 0.5;
|
|
446
|
-
float starRandom = hash21(starGrid);
|
|
447
|
-
float starShape = smoothstep(0.075, 0.0, length(starCell));
|
|
448
|
-
float starMask = step(0.989, starRandom) * starShape;
|
|
449
|
-
float twinkle = 0.35 + 0.65 * sin(t * (1.0 + starRandom * 2.4) + starRandom * 40.0) * 0.5 + 0.5;
|
|
450
|
-
color += starMask * twinkle * mix(u_colorC, u_colorD, starRandom) * 1.05;
|
|
451
|
-
|
|
452
|
-
float pointerGlow = exp(-distanceToPointer * 7.0) * u_motion;
|
|
453
|
-
color += u_colorD * pointerGlow * 0.28;
|
|
454
|
-
return color;
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
void main() {
|
|
458
|
-
vec2 uv = v_uv;
|
|
459
|
-
vec2 p = uv - 0.5;
|
|
460
|
-
p.x *= u_resolution.x / max(u_resolution.y, 1.0);
|
|
461
|
-
|
|
462
|
-
vec2 pointer = u_pointer - 0.5;
|
|
463
|
-
pointer.x *= u_resolution.x / max(u_resolution.y, 1.0);
|
|
464
|
-
float distanceToPointer = length(p - pointer);
|
|
465
|
-
|
|
466
|
-
vec3 color = renderNebula(uv, p, pointer, distanceToPointer, u_time);
|
|
467
|
-
float vignette = smoothstep(0.94, 0.18, length((uv - 0.5) * vec2(1.0, 1.35)));
|
|
468
|
-
color *= 0.70 + vignette * 0.42;
|
|
469
|
-
color = pow(max(color, vec3(0.0)), vec3(0.88));
|
|
470
|
-
|
|
471
|
-
outColor = vec4(color, 1.0);
|
|
472
|
-
}`;
|
|
473
|
-
|
|
474
|
-
function compileShader(gl, type, source) {
|
|
475
|
-
const shader = gl.createShader(type);
|
|
476
|
-
gl.shaderSource(shader, source);
|
|
477
|
-
gl.compileShader(shader);
|
|
478
|
-
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
479
|
-
const message = gl.getShaderInfoLog(shader) || 'Unknown shader compile error';
|
|
480
|
-
gl.deleteShader(shader);
|
|
481
|
-
throw new Error(message);
|
|
482
|
-
}
|
|
483
|
-
return shader;
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
function createProgram(gl) {
|
|
487
|
-
const vertex = compileShader(gl, gl.VERTEX_SHADER, VERTEX_SHADER);
|
|
488
|
-
const fragment = compileShader(gl, gl.FRAGMENT_SHADER, FRAGMENT_SHADER);
|
|
489
|
-
const program = gl.createProgram();
|
|
490
|
-
gl.attachShader(program, vertex);
|
|
491
|
-
gl.attachShader(program, fragment);
|
|
492
|
-
gl.linkProgram(program);
|
|
493
|
-
gl.deleteShader(vertex);
|
|
494
|
-
gl.deleteShader(fragment);
|
|
495
|
-
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
496
|
-
const message = gl.getProgramInfoLog(program) || 'Unknown program link error';
|
|
497
|
-
gl.deleteProgram(program);
|
|
498
|
-
throw new Error(message);
|
|
499
|
-
}
|
|
500
|
-
return program;
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
class CosmicRenderer {
|
|
504
|
-
constructor(canvas, preset, options = {}) {
|
|
505
|
-
this.canvas = canvas;
|
|
506
|
-
this.preset = { ...preset };
|
|
507
|
-
this.options = { dprCap: 1.75, mouseColor: true, ...options };
|
|
508
|
-
this.gl = canvas.getContext('webgl2', {
|
|
509
|
-
alpha: false,
|
|
510
|
-
antialias: false,
|
|
511
|
-
depth: false,
|
|
512
|
-
powerPreference: this.options.powerPreference || 'high-performance',
|
|
513
|
-
preserveDrawingBuffer: false
|
|
514
|
-
});
|
|
515
|
-
if (!this.gl) throw new Error('WebGL2 is not available');
|
|
516
|
-
|
|
517
|
-
this.program = createProgram(this.gl);
|
|
518
|
-
this.locations = this.#getLocations();
|
|
519
|
-
this.pointer = [0.72, 0.45];
|
|
520
|
-
this.pointerTarget = [...this.pointer];
|
|
521
|
-
this.motion = 0;
|
|
522
|
-
this.motionTarget = 0;
|
|
523
|
-
this.timeOffset = preset.seed * 0.73;
|
|
524
|
-
this.colors = preset.colors.map(hexToRgb01);
|
|
525
|
-
this.visible = true;
|
|
526
|
-
this.disposed = false;
|
|
527
|
-
|
|
528
|
-
this.#setupGeometry();
|
|
529
|
-
this.#bindEvents();
|
|
530
|
-
this.#bindContextEvents();
|
|
531
|
-
this.resize();
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
#getLocations() {
|
|
535
|
-
const gl = this.gl;
|
|
536
|
-
const uniform = (name) => gl.getUniformLocation(this.program, name);
|
|
537
|
-
return {
|
|
538
|
-
position: gl.getAttribLocation(this.program, 'a_position'),
|
|
539
|
-
resolution: uniform('u_resolution'),
|
|
540
|
-
time: uniform('u_time'),
|
|
541
|
-
seed: uniform('u_seed'),
|
|
542
|
-
motion: uniform('u_motion'),
|
|
543
|
-
pointer: uniform('u_pointer'),
|
|
544
|
-
colorA: uniform('u_colorA'),
|
|
545
|
-
colorB: uniform('u_colorB'),
|
|
546
|
-
colorC: uniform('u_colorC'),
|
|
547
|
-
colorD: uniform('u_colorD')
|
|
548
|
-
};
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
#setupGeometry() {
|
|
552
|
-
const gl = this.gl;
|
|
553
|
-
const vertices = new Float32Array([-1, -1, 3, -1, -1, 3]);
|
|
554
|
-
this.buffer = gl.createBuffer();
|
|
555
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
|
|
556
|
-
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
#bindEvents() {
|
|
560
|
-
if (this.options.mouseColor === false) return;
|
|
561
|
-
this.eventTarget = this.options.eventTarget || this.canvas.parentElement || this.canvas;
|
|
562
|
-
this.onPointerMove = (event) => {
|
|
563
|
-
const rect = this.canvas.getBoundingClientRect();
|
|
564
|
-
this.pointerTarget[0] = (event.clientX - rect.left) / Math.max(rect.width, 1);
|
|
565
|
-
this.pointerTarget[1] = 1 - (event.clientY - rect.top) / Math.max(rect.height, 1);
|
|
566
|
-
this.motionTarget = 1;
|
|
567
|
-
};
|
|
568
|
-
this.onPointerLeave = () => { this.motionTarget = 0; };
|
|
569
|
-
this.eventTarget.addEventListener('pointermove', this.onPointerMove, { passive: true });
|
|
570
|
-
this.eventTarget.addEventListener('pointerdown', this.onPointerMove, { passive: true });
|
|
571
|
-
this.eventTarget.addEventListener('pointerleave', this.onPointerLeave, { passive: true });
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
#bindContextEvents() {
|
|
575
|
-
this.onContextLost = (event) => {
|
|
576
|
-
event.preventDefault();
|
|
577
|
-
if (this.disposed) return;
|
|
578
|
-
this.visible = false;
|
|
579
|
-
if (typeof this.options.onContextLost === 'function') this.options.onContextLost(event);
|
|
580
|
-
};
|
|
581
|
-
this.onContextRestored = () => {
|
|
582
|
-
if (this.disposed) return;
|
|
583
|
-
this.program = createProgram(this.gl);
|
|
584
|
-
this.locations = this.#getLocations();
|
|
585
|
-
this.#setupGeometry();
|
|
586
|
-
this.visible = true;
|
|
587
|
-
this.resize();
|
|
588
|
-
if (typeof this.options.onContextRestored === 'function') this.options.onContextRestored();
|
|
589
|
-
};
|
|
590
|
-
this.canvas.addEventListener('webglcontextlost', this.onContextLost, false);
|
|
591
|
-
this.canvas.addEventListener('webglcontextrestored', this.onContextRestored, false);
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
setPreset(preset) {
|
|
595
|
-
this.preset = { ...preset };
|
|
596
|
-
this.colors = preset.colors.map(hexToRgb01);
|
|
597
|
-
this.timeOffset = preset.seed * 0.73;
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
setDprCap(cap) {
|
|
601
|
-
this.options.dprCap = cap;
|
|
602
|
-
this.resize();
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
setMouseColor(enabled) {
|
|
606
|
-
this.options.mouseColor = enabled !== false;
|
|
607
|
-
if (this.options.mouseColor) {
|
|
608
|
-
if (this.onPointerMove) return this;
|
|
609
|
-
this.#bindEvents();
|
|
610
|
-
return this;
|
|
611
|
-
}
|
|
612
|
-
if (this.onPointerMove) {
|
|
613
|
-
const target = this.eventTarget;
|
|
614
|
-
target.removeEventListener('pointermove', this.onPointerMove);
|
|
615
|
-
target.removeEventListener('pointerdown', this.onPointerMove);
|
|
616
|
-
target.removeEventListener('pointerleave', this.onPointerLeave);
|
|
617
|
-
this.onPointerMove = null;
|
|
618
|
-
this.onPointerLeave = null;
|
|
619
|
-
}
|
|
620
|
-
this.motionTarget = 0;
|
|
621
|
-
return this;
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
randomize() {
|
|
625
|
-
this.preset.seed = Math.random() * 100;
|
|
626
|
-
this.timeOffset = Math.random() * 40;
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
resize() {
|
|
630
|
-
const dpr = Math.min(window.devicePixelRatio || 1, this.options.dprCap);
|
|
631
|
-
const rect = this.canvas.getBoundingClientRect();
|
|
632
|
-
const width = Math.max(2, Math.round(rect.width * dpr));
|
|
633
|
-
const height = Math.max(2, Math.round(rect.height * dpr));
|
|
634
|
-
if (this.canvas.width !== width || this.canvas.height !== height) {
|
|
635
|
-
this.canvas.width = width;
|
|
636
|
-
this.canvas.height = height;
|
|
637
|
-
}
|
|
638
|
-
this.gl.viewport(0, 0, width, height);
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
draw(elapsedSeconds, paused = false) {
|
|
642
|
-
if (this.disposed || !this.visible) return;
|
|
643
|
-
const gl = this.gl;
|
|
644
|
-
this.pointer[0] += (this.pointerTarget[0] - this.pointer[0]) * 0.08;
|
|
645
|
-
this.pointer[1] += (this.pointerTarget[1] - this.pointer[1]) * 0.08;
|
|
646
|
-
this.motion += (this.motionTarget - this.motion) * 0.07;
|
|
647
|
-
|
|
648
|
-
gl.useProgram(this.program);
|
|
649
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
|
|
650
|
-
gl.enableVertexAttribArray(this.locations.position);
|
|
651
|
-
gl.vertexAttribPointer(this.locations.position, 2, gl.FLOAT, false, 0, 0);
|
|
652
|
-
|
|
653
|
-
gl.uniform2f(this.locations.resolution, this.canvas.width, this.canvas.height);
|
|
654
|
-
gl.uniform1f(this.locations.time, this.timeOffset + (paused ? 0 : elapsedSeconds * this.preset.speed));
|
|
655
|
-
gl.uniform1f(this.locations.seed, this.preset.seed);
|
|
656
|
-
gl.uniform1f(this.locations.motion, this.motion);
|
|
657
|
-
gl.uniform2f(this.locations.pointer, this.pointer[0], this.pointer[1]);
|
|
658
|
-
gl.uniform3fv(this.locations.colorA, this.colors[0]);
|
|
659
|
-
gl.uniform3fv(this.locations.colorB, this.colors[1]);
|
|
660
|
-
gl.uniform3fv(this.locations.colorC, this.colors[2]);
|
|
661
|
-
gl.uniform3fv(this.locations.colorD, this.colors[3]);
|
|
662
|
-
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
dispose() {
|
|
666
|
-
this.disposed = true;
|
|
667
|
-
const target = this.eventTarget || this.canvas;
|
|
668
|
-
target.removeEventListener('pointermove', this.onPointerMove);
|
|
669
|
-
target.removeEventListener('pointerdown', this.onPointerMove);
|
|
670
|
-
target.removeEventListener('pointerleave', this.onPointerLeave);
|
|
671
|
-
this.canvas.removeEventListener('webglcontextlost', this.onContextLost, false);
|
|
672
|
-
this.canvas.removeEventListener('webglcontextrestored', this.onContextRestored, false);
|
|
673
|
-
this.gl.deleteBuffer(this.buffer);
|
|
674
|
-
this.gl.deleteProgram(this.program);
|
|
675
|
-
const lose = this.gl.getExtension('WEBGL_lose_context');
|
|
676
|
-
if (lose) lose.loseContext();
|
|
677
|
-
}
|
|
678
|
-
}
|
|
115
|
+
const emitter = createEmitter();
|
|
116
|
+
let manuallyPaused = merged.paused === true;
|
|
117
|
+
let reducedPaused = false;
|
|
118
|
+
let staticMode = merged.static === true;
|
|
119
|
+
let contextLost = false;
|
|
120
|
+
let disposed = false;
|
|
121
|
+
let renderOnce = () => {};
|
|
122
|
+
const dirty = {
|
|
123
|
+
preset: false,
|
|
124
|
+
seed: false,
|
|
125
|
+
speed: false,
|
|
126
|
+
colors: false,
|
|
127
|
+
opacity: false,
|
|
128
|
+
fallbackColor: false,
|
|
129
|
+
mouseColor: false,
|
|
130
|
+
quality: false,
|
|
131
|
+
renderScale: false,
|
|
132
|
+
paused: false,
|
|
133
|
+
static: false,
|
|
134
|
+
fps: false
|
|
135
|
+
};
|
|
679
136
|
|
|
680
|
-
|
|
681
|
-
const
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
ctx.fillRect(0, 0, width, height);
|
|
718
|
-
|
|
719
|
-
ctx.globalCompositeOperation = 'screen';
|
|
720
|
-
for (let index = 0; index < 6; index += 1) {
|
|
721
|
-
const x = (0.5 + 0.45 * Math.sin(t * 0.32 + index * 1.7 + phase)) * width;
|
|
722
|
-
const y = (0.5 + 0.4 * Math.cos(t * 0.25 + index + phase)) * height;
|
|
723
|
-
const radius = Math.max(width, height) * (0.08 + (index % 3) * 0.04);
|
|
724
|
-
const glow = ctx.createRadialGradient(x, y, 0, x, y, radius);
|
|
725
|
-
glow.addColorStop(0, rgb(this.preset.colors[(index + 1) % 4], 0.24));
|
|
726
|
-
glow.addColorStop(1, rgb(this.preset.colors[index % 4], 0));
|
|
727
|
-
ctx.fillStyle = glow;
|
|
728
|
-
ctx.fillRect(x - radius, y - radius, radius * 2, radius * 2);
|
|
729
|
-
}
|
|
730
|
-
ctx.globalCompositeOperation = 'source-over';
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
draw(time) {
|
|
734
|
-
if (!this.visible) return;
|
|
735
|
-
this.drawNebula(time);
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
setPreset(preset) {
|
|
739
|
-
this.preset = preset;
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
setDprCap(cap) {
|
|
743
|
-
this.dprCap = cap;
|
|
744
|
-
this.resize();
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
randomize() {
|
|
748
|
-
if (this.preset) {
|
|
749
|
-
this.preset.seed = Math.random() * 100;
|
|
750
|
-
this.timePhase = Math.random() * Math.PI * 2;
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
setMouseColor() {}
|
|
754
|
-
dispose() {}
|
|
755
|
-
}
|
|
137
|
+
let renderer;
|
|
138
|
+
const useWebgl = merged.renderer !== 'canvas2d';
|
|
139
|
+
if (useWebgl) {
|
|
140
|
+
try {
|
|
141
|
+
renderer = new CosmicRenderer(canvas, merged, {
|
|
142
|
+
dprCap: effectiveDprCap(merged.quality, merged.renderScale),
|
|
143
|
+
mouseColor: merged.mouseColor !== false,
|
|
144
|
+
eventTarget: host,
|
|
145
|
+
powerPreference: merged.powerPreference,
|
|
146
|
+
onContextLost: () => {
|
|
147
|
+
contextLost = true;
|
|
148
|
+
emitter.emit('contextlost', {});
|
|
149
|
+
},
|
|
150
|
+
onContextRestored: () => {
|
|
151
|
+
contextLost = false;
|
|
152
|
+
emitter.emit('contextrestored', {});
|
|
153
|
+
renderOnce();
|
|
154
|
+
wakeScheduler();
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
} catch (error) {
|
|
158
|
+
renderer = new FallbackRenderer(canvas, merged, {
|
|
159
|
+
dprCap: effectiveDprCap(merged.quality, merged.renderScale)
|
|
160
|
+
});
|
|
161
|
+
nextTick(() => {
|
|
162
|
+
if (disposed) return;
|
|
163
|
+
emitter.emit('error', {
|
|
164
|
+
message: String(error && error.message ? error.message : error)
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
} else {
|
|
169
|
+
renderer = new FallbackRenderer(canvas, merged, {
|
|
170
|
+
dprCap: effectiveDprCap(merged.quality, merged.renderScale)
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
renderer.resize();
|
|
756
174
|
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
* original demo), which avoids jank from many competing rAF loops.
|
|
761
|
-
*/
|
|
762
|
-
const subscribers = [];
|
|
763
|
-
let running = false;
|
|
764
|
-
let rafId = 0;
|
|
765
|
-
let last = 0;
|
|
766
|
-
|
|
767
|
-
function tick(now) {
|
|
768
|
-
if (!running) return;
|
|
769
|
-
const activeItems = [];
|
|
770
|
-
{
|
|
771
|
-
for (const item of subscribers.slice()) {
|
|
772
|
-
try {
|
|
773
|
-
if (!item.isPaused()) activeItems.push(item);
|
|
774
|
-
} catch {}
|
|
775
|
-
}
|
|
776
|
-
}
|
|
777
|
-
if (activeItems.length === 0) {
|
|
778
|
-
running = false;
|
|
779
|
-
rafId = 0;
|
|
780
|
-
last = 0;
|
|
781
|
-
return;
|
|
782
|
-
}
|
|
783
|
-
const delta = last ? Math.min((now - last) / 1000, 0.05) : 0;
|
|
784
|
-
last = now;
|
|
785
|
-
// Schedule the next frame BEFORE running callbacks so one throwing
|
|
786
|
-
// subscriber can never kill the whole animation loop.
|
|
787
|
-
rafId = requestAnimationFrame(tick);
|
|
788
|
-
for (const item of activeItems) {
|
|
789
|
-
try {
|
|
790
|
-
item.onFrame(delta, now);
|
|
791
|
-
} catch (error) {
|
|
792
|
-
console.warn('[dlc-ui] frame error:', error);
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
if (subscribers.length === 0) {
|
|
796
|
-
cancelAnimationFrame(rafId);
|
|
797
|
-
running = false;
|
|
798
|
-
rafId = 0;
|
|
799
|
-
}
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
function start() {
|
|
803
|
-
if (running) return;
|
|
804
|
-
running = true;
|
|
805
|
-
last = 0;
|
|
806
|
-
rafId = requestAnimationFrame(tick);
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
function wakeScheduler() {
|
|
810
|
-
start();
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
function subscribeScheduler(onFrame, isPaused) {
|
|
814
|
-
const item = { onFrame, isPaused };
|
|
815
|
-
subscribers.push(item);
|
|
816
|
-
start();
|
|
817
|
-
return () => {
|
|
818
|
-
const index = subscribers.indexOf(item);
|
|
819
|
-
if (index !== -1) subscribers.splice(index, 1);
|
|
820
|
-
if (subscribers.length === 0 && rafId) {
|
|
821
|
-
cancelAnimationFrame(rafId);
|
|
822
|
-
running = false;
|
|
823
|
-
rafId = 0;
|
|
824
|
-
}
|
|
825
|
-
};
|
|
826
|
-
}
|
|
175
|
+
let animationTime = 0;
|
|
176
|
+
const frameGate = createFrameGate(merged.fps);
|
|
177
|
+
renderOnce = () => renderer.draw(animationTime);
|
|
827
178
|
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
if (typeof IntersectionObserver !== 'undefined') {
|
|
839
|
-
observer = new IntersectionObserver(
|
|
840
|
-
(entries) => {
|
|
841
|
-
intersecting = entries.some((entry) => entry.isIntersecting);
|
|
842
|
-
if (typeof onChange === 'function') onChange();
|
|
843
|
-
},
|
|
844
|
-
{ rootMargin: '180px' }
|
|
845
|
-
);
|
|
846
|
-
observer.observe(element);
|
|
847
|
-
}
|
|
848
|
-
|
|
849
|
-
const onVisibilityChange = () => {
|
|
850
|
-
pageVisible = typeof document !== 'undefined' && !document.hidden;
|
|
851
|
-
if (typeof onChange === 'function') onChange();
|
|
852
|
-
};
|
|
853
|
-
if (typeof document !== 'undefined') {
|
|
854
|
-
document.addEventListener('visibilitychange', onVisibilityChange);
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
return {
|
|
858
|
-
isVisible() {
|
|
859
|
-
return intersecting && pageVisible;
|
|
860
|
-
},
|
|
861
|
-
dispose() {
|
|
862
|
-
if (disposed) return;
|
|
863
|
-
disposed = true;
|
|
864
|
-
if (observer) observer.disconnect();
|
|
865
|
-
if (typeof document !== 'undefined') {
|
|
866
|
-
document.removeEventListener('visibilitychange', onVisibilityChange);
|
|
867
|
-
}
|
|
868
|
-
}
|
|
869
|
-
};
|
|
870
|
-
}
|
|
179
|
+
const resize = () => {
|
|
180
|
+
renderer.resize();
|
|
181
|
+
if (manuallyPaused || reducedPaused || staticMode) renderOnce();
|
|
182
|
+
};
|
|
183
|
+
const resizeObserver =
|
|
184
|
+
typeof ResizeObserver !== 'undefined'
|
|
185
|
+
? new ResizeObserver(resize)
|
|
186
|
+
: null;
|
|
187
|
+
if (resizeObserver) resizeObserver.observe(host);
|
|
188
|
+
else window.addEventListener('resize', resize);
|
|
871
189
|
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
} else {
|
|
884
|
-
setTimeout(fn, 0);
|
|
885
|
-
}
|
|
886
|
-
}
|
|
190
|
+
const visibility = createVisibilityGuard(layer, wakeScheduler);
|
|
191
|
+
const motionPreference = createReducedMotionPreference(
|
|
192
|
+
merged.respectReducedMotion,
|
|
193
|
+
(matches) => {
|
|
194
|
+
reducedPaused = matches;
|
|
195
|
+
if (matches) renderOnce();
|
|
196
|
+
else wakeScheduler();
|
|
197
|
+
}
|
|
198
|
+
);
|
|
199
|
+
reducedPaused = motionPreference.matches();
|
|
200
|
+
const isMotionPaused = () => manuallyPaused || reducedPaused || staticMode || contextLost;
|
|
887
201
|
|
|
888
|
-
|
|
889
|
-
const
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
let elapsed = 0;
|
|
897
|
-
return {
|
|
898
|
-
shouldDraw(delta) {
|
|
899
|
-
elapsed += delta;
|
|
900
|
-
const interval = 1 / fps;
|
|
901
|
-
if (elapsed + 0.0001 < interval) return false;
|
|
902
|
-
elapsed %= interval;
|
|
903
|
-
return true;
|
|
904
|
-
},
|
|
905
|
-
setFps(value) {
|
|
906
|
-
fps = normalizeFps(value, fps);
|
|
907
|
-
elapsed = 0;
|
|
908
|
-
return fps;
|
|
909
|
-
},
|
|
910
|
-
getFps() {
|
|
911
|
-
return fps;
|
|
912
|
-
}
|
|
913
|
-
};
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
function createReducedMotionPreference(enabled, onChange) {
|
|
917
|
-
const query = enabled && typeof matchMedia !== 'undefined'
|
|
918
|
-
? matchMedia('(prefers-reduced-motion: reduce)')
|
|
919
|
-
: null;
|
|
920
|
-
const notify = () => {
|
|
921
|
-
if (typeof onChange === 'function') onChange(Boolean(query && query.matches));
|
|
922
|
-
};
|
|
923
|
-
if (query) {
|
|
924
|
-
if (typeof query.addEventListener === 'function') query.addEventListener('change', notify);
|
|
925
|
-
else if (typeof query.addListener === 'function') query.addListener(notify);
|
|
926
|
-
}
|
|
927
|
-
return {
|
|
928
|
-
matches() {
|
|
929
|
-
return Boolean(query && query.matches);
|
|
930
|
-
},
|
|
931
|
-
dispose() {
|
|
932
|
-
if (!query) return;
|
|
933
|
-
if (typeof query.removeEventListener === 'function') query.removeEventListener('change', notify);
|
|
934
|
-
else if (typeof query.removeListener === 'function') query.removeListener(notify);
|
|
935
|
-
}
|
|
936
|
-
};
|
|
937
|
-
}
|
|
202
|
+
renderOnce();
|
|
203
|
+
const unsubscribe = subscribeScheduler(
|
|
204
|
+
(delta) => {
|
|
205
|
+
animationTime += delta;
|
|
206
|
+
if (frameGate.shouldDraw(delta)) renderer.draw(animationTime);
|
|
207
|
+
},
|
|
208
|
+
() => isMotionPaused() || !visibility.isVisible()
|
|
209
|
+
);
|
|
938
210
|
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
return Number.isFinite(number) ? number : null;
|
|
944
|
-
}
|
|
211
|
+
nextTick(() => {
|
|
212
|
+
if (disposed) return;
|
|
213
|
+
emitter.emit('ready', { preset: { ...preset } });
|
|
214
|
+
});
|
|
945
215
|
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
renderer
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
}
|
|
1095
|
-
});
|
|
1096
|
-
} catch (error) {
|
|
1097
|
-
renderer = new FallbackRenderer(canvas, merged, {
|
|
1098
|
-
dprCap: effectiveDprCap(merged.quality, merged.renderScale)
|
|
1099
|
-
});
|
|
1100
|
-
nextTick(() => {
|
|
1101
|
-
if (disposed) return;
|
|
1102
|
-
emitter.emit('error', {
|
|
1103
|
-
message: String(error && error.message ? error.message : error)
|
|
1104
|
-
});
|
|
1105
|
-
});
|
|
1106
|
-
}
|
|
1107
|
-
} else {
|
|
1108
|
-
renderer = new FallbackRenderer(canvas, merged, {
|
|
1109
|
-
dprCap: effectiveDprCap(merged.quality, merged.renderScale)
|
|
1110
|
-
});
|
|
1111
|
-
}
|
|
1112
|
-
renderer.resize();
|
|
1113
|
-
|
|
1114
|
-
let animationTime = 0;
|
|
1115
|
-
const frameGate = createFrameGate(merged.fps);
|
|
1116
|
-
renderOnce = () => renderer.draw(animationTime);
|
|
1117
|
-
|
|
1118
|
-
const resize = () => {
|
|
1119
|
-
renderer.resize();
|
|
1120
|
-
if (manuallyPaused || reducedPaused || staticMode) renderOnce();
|
|
1121
|
-
};
|
|
1122
|
-
const resizeObserver =
|
|
1123
|
-
typeof ResizeObserver !== 'undefined'
|
|
1124
|
-
? new ResizeObserver(resize)
|
|
1125
|
-
: null;
|
|
1126
|
-
if (resizeObserver) resizeObserver.observe(host);
|
|
1127
|
-
else window.addEventListener('resize', resize);
|
|
1128
|
-
|
|
1129
|
-
const visibility = createVisibilityGuard(layer, wakeScheduler);
|
|
1130
|
-
const motionPreference = createReducedMotionPreference(
|
|
1131
|
-
merged.respectReducedMotion,
|
|
1132
|
-
(matches) => {
|
|
1133
|
-
reducedPaused = matches;
|
|
1134
|
-
if (matches) renderOnce();
|
|
1135
|
-
else wakeScheduler();
|
|
1136
|
-
}
|
|
1137
|
-
);
|
|
1138
|
-
reducedPaused = motionPreference.matches();
|
|
1139
|
-
const isMotionPaused = () => manuallyPaused || reducedPaused || staticMode || contextLost;
|
|
1140
|
-
|
|
1141
|
-
renderOnce();
|
|
1142
|
-
const unsubscribe = subscribeScheduler(
|
|
1143
|
-
(delta) => {
|
|
1144
|
-
animationTime += delta;
|
|
1145
|
-
if (frameGate.shouldDraw(delta)) renderer.draw(animationTime);
|
|
1146
|
-
},
|
|
1147
|
-
() => isMotionPaused() || !visibility.isVisible()
|
|
1148
|
-
);
|
|
1149
|
-
|
|
1150
|
-
nextTick(() => {
|
|
1151
|
-
if (disposed) return;
|
|
1152
|
-
emitter.emit('ready', { preset: { ...preset } });
|
|
1153
|
-
});
|
|
1154
|
-
|
|
1155
|
-
return {
|
|
1156
|
-
element: host,
|
|
1157
|
-
layer,
|
|
1158
|
-
canvas,
|
|
1159
|
-
preset,
|
|
1160
|
-
on: emitter.on,
|
|
1161
|
-
off: emitter.off,
|
|
1162
|
-
setPreset(ref) {
|
|
1163
|
-
const next = getPreset('capsule', ref);
|
|
1164
|
-
dirty.preset = true;
|
|
1165
|
-
Object.assign(preset, next);
|
|
1166
|
-
if (colorOverride) preset.colors = [...colorOverride];
|
|
1167
|
-
if (seedOverride !== null) preset.seed = seedOverride;
|
|
1168
|
-
if (speedOverride !== null) preset.speed = speedOverride;
|
|
1169
|
-
const nextColors = preset.colors.map(normalizeColor);
|
|
1170
|
-
if (nextColors.every(Boolean)) preset.colors = nextColors;
|
|
1171
|
-
renderer.setPreset({ ...preset });
|
|
1172
|
-
renderer.resize();
|
|
1173
|
-
syncLayerVars();
|
|
1174
|
-
if (isMotionPaused()) renderOnce();
|
|
1175
|
-
emitter.emit('presetchange', { preset: { ...preset } });
|
|
1176
|
-
return this;
|
|
1177
|
-
},
|
|
1178
|
-
setColors(colors) {
|
|
1179
|
-
const next = Array.isArray(colors) ? colors.map(normalizeColor) : [];
|
|
1180
|
-
if (next.length !== 4 || next.some((color) => !color)) return this;
|
|
1181
|
-
dirty.colors = true;
|
|
1182
|
-
colorOverride = [...next];
|
|
1183
|
-
preset.colors = next;
|
|
1184
|
-
renderer.setPreset({ ...preset, colors: next });
|
|
1185
|
-
syncLayerVars();
|
|
1186
|
-
if (isMotionPaused()) renderOnce();
|
|
1187
|
-
return this;
|
|
1188
|
-
},
|
|
1189
|
-
setSeed(seed) {
|
|
1190
|
-
const value = toFiniteNumber(seed);
|
|
1191
|
-
if (value === null) return this;
|
|
1192
|
-
dirty.seed = true;
|
|
1193
|
-
seedOverride = value;
|
|
1194
|
-
preset.seed = value;
|
|
1195
|
-
renderer.setPreset({ ...preset });
|
|
1196
|
-
if (isMotionPaused()) renderOnce();
|
|
1197
|
-
return this;
|
|
1198
|
-
},
|
|
1199
|
-
setSpeed(speed) {
|
|
1200
|
-
const value = toFiniteNumber(speed);
|
|
1201
|
-
if (value === null) return this;
|
|
1202
|
-
dirty.speed = true;
|
|
1203
|
-
speedOverride = value;
|
|
1204
|
-
preset.speed = value;
|
|
1205
|
-
renderer.setPreset({ ...preset });
|
|
1206
|
-
if (isMotionPaused()) renderOnce();
|
|
1207
|
-
return this;
|
|
1208
|
-
},
|
|
1209
|
-
setFallbackColor(value) {
|
|
1210
|
-
dirty.fallbackColor = true;
|
|
1211
|
-
merged.fallbackColor = value;
|
|
1212
|
-
syncLayerVars();
|
|
1213
|
-
return this;
|
|
1214
|
-
},
|
|
1215
|
-
setMouseColor(value) {
|
|
1216
|
-
dirty.mouseColor = true;
|
|
1217
|
-
merged.mouseColor = value !== false;
|
|
1218
|
-
if (typeof renderer.setMouseColor === 'function') renderer.setMouseColor(merged.mouseColor);
|
|
1219
|
-
return this;
|
|
1220
|
-
},
|
|
1221
|
-
setQuality(quality) {
|
|
1222
|
-
dirty.quality = true;
|
|
1223
|
-
merged.quality = quality;
|
|
1224
|
-
if (typeof renderer.setDprCap === 'function') {
|
|
1225
|
-
renderer.setDprCap(effectiveDprCap(quality, merged.renderScale));
|
|
1226
|
-
}
|
|
1227
|
-
if (isMotionPaused()) renderOnce();
|
|
1228
|
-
return this;
|
|
1229
|
-
},
|
|
1230
|
-
setRenderScale(renderScale) {
|
|
1231
|
-
const value = Number(renderScale);
|
|
1232
|
-
if (!Number.isFinite(value)) return this;
|
|
1233
|
-
dirty.renderScale = true;
|
|
1234
|
-
merged.renderScale = Math.min(1, Math.max(0.25, value));
|
|
1235
|
-
if (typeof renderer.setDprCap === 'function') {
|
|
1236
|
-
renderer.setDprCap(effectiveDprCap(merged.quality, merged.renderScale));
|
|
1237
|
-
}
|
|
1238
|
-
if (isMotionPaused()) renderOnce();
|
|
1239
|
-
return this;
|
|
1240
|
-
},
|
|
1241
|
-
setOpacity(value) {
|
|
1242
|
-
const opacity = Number(value);
|
|
1243
|
-
if (!Number.isFinite(opacity)) return this;
|
|
1244
|
-
dirty.opacity = true;
|
|
1245
|
-
merged.opacity = Math.min(1, Math.max(0, opacity));
|
|
1246
|
-
layer.style.setProperty('--dlc-color-opacity', String(merged.opacity));
|
|
1247
|
-
return this;
|
|
1248
|
-
},
|
|
1249
|
-
randomize() {
|
|
1250
|
-
this.setSeed(Math.random() * 100);
|
|
1251
|
-
return this;
|
|
1252
|
-
},
|
|
1253
|
-
pause() {
|
|
1254
|
-
dirty.paused = true;
|
|
1255
|
-
manuallyPaused = true;
|
|
1256
|
-
renderOnce();
|
|
1257
|
-
return this;
|
|
1258
|
-
},
|
|
1259
|
-
resume() {
|
|
1260
|
-
dirty.paused = true;
|
|
1261
|
-
manuallyPaused = false;
|
|
1262
|
-
wakeScheduler();
|
|
1263
|
-
return this;
|
|
1264
|
-
},
|
|
1265
|
-
setPaused(value) {
|
|
1266
|
-
return value ? this.pause() : this.resume();
|
|
1267
|
-
},
|
|
1268
|
-
setStatic(value) {
|
|
1269
|
-
dirty.static = true;
|
|
1270
|
-
staticMode = value === true;
|
|
1271
|
-
merged.static = staticMode;
|
|
1272
|
-
if (staticMode) renderOnce();
|
|
1273
|
-
else wakeScheduler();
|
|
1274
|
-
return this;
|
|
1275
|
-
},
|
|
1276
|
-
setFps(fps) {
|
|
1277
|
-
dirty.fps = true;
|
|
1278
|
-
merged.fps = frameGate.setFps(fps);
|
|
1279
|
-
wakeScheduler();
|
|
1280
|
-
return this;
|
|
1281
|
-
},
|
|
1282
|
-
dispose() {
|
|
1283
|
-
disposed = true;
|
|
1284
|
-
unsubscribe();
|
|
1285
|
-
visibility.dispose();
|
|
1286
|
-
motionPreference.dispose();
|
|
1287
|
-
if (resizeObserver) resizeObserver.disconnect();
|
|
1288
|
-
else window.removeEventListener('resize', resize);
|
|
1289
|
-
renderer.dispose();
|
|
1290
|
-
layer.remove();
|
|
1291
|
-
releaseHostStyles(host);
|
|
1292
|
-
},
|
|
1293
|
-
get opacity() { return merged.opacity; },
|
|
1294
|
-
get fallbackColor() { return merged.fallbackColor; },
|
|
1295
|
-
get mouseColor() { return merged.mouseColor; },
|
|
1296
|
-
get quality() { return merged.quality; },
|
|
1297
|
-
get renderScale() { return merged.renderScale; },
|
|
1298
|
-
get paused() { return manuallyPaused; },
|
|
1299
|
-
get static() { return staticMode; },
|
|
1300
|
-
get fps() { return frameGate.getFps(); },
|
|
1301
|
-
dirty
|
|
1302
|
-
};
|
|
216
|
+
return {
|
|
217
|
+
element: host,
|
|
218
|
+
layer,
|
|
219
|
+
canvas,
|
|
220
|
+
preset,
|
|
221
|
+
on: emitter.on,
|
|
222
|
+
off: emitter.off,
|
|
223
|
+
setPreset(ref) {
|
|
224
|
+
const next = getPreset('capsule', ref);
|
|
225
|
+
dirty.preset = true;
|
|
226
|
+
Object.assign(preset, next);
|
|
227
|
+
if (colorOverride) preset.colors = [...colorOverride];
|
|
228
|
+
if (seedOverride !== null) preset.seed = seedOverride;
|
|
229
|
+
if (speedOverride !== null) preset.speed = speedOverride;
|
|
230
|
+
const nextColors = preset.colors.map(normalizeColor);
|
|
231
|
+
if (nextColors.every(Boolean)) preset.colors = nextColors;
|
|
232
|
+
renderer.setPreset({ ...preset });
|
|
233
|
+
renderer.resize();
|
|
234
|
+
syncLayerVars();
|
|
235
|
+
if (isMotionPaused()) renderOnce();
|
|
236
|
+
emitter.emit('presetchange', { preset: { ...preset } });
|
|
237
|
+
return this;
|
|
238
|
+
},
|
|
239
|
+
setColors(colors) {
|
|
240
|
+
const next = Array.isArray(colors) ? colors.map(normalizeColor) : [];
|
|
241
|
+
if (next.length !== 4 || next.some((color) => !color)) return this;
|
|
242
|
+
dirty.colors = true;
|
|
243
|
+
colorOverride = [...next];
|
|
244
|
+
preset.colors = next;
|
|
245
|
+
renderer.setPreset({ ...preset, colors: next });
|
|
246
|
+
syncLayerVars();
|
|
247
|
+
if (isMotionPaused()) renderOnce();
|
|
248
|
+
return this;
|
|
249
|
+
},
|
|
250
|
+
setSeed(seed) {
|
|
251
|
+
const value = toFiniteNumber(seed);
|
|
252
|
+
if (value === null) return this;
|
|
253
|
+
dirty.seed = true;
|
|
254
|
+
seedOverride = value;
|
|
255
|
+
preset.seed = value;
|
|
256
|
+
renderer.setPreset({ ...preset });
|
|
257
|
+
if (isMotionPaused()) renderOnce();
|
|
258
|
+
return this;
|
|
259
|
+
},
|
|
260
|
+
setSpeed(speed) {
|
|
261
|
+
const value = toFiniteNumber(speed);
|
|
262
|
+
if (value === null) return this;
|
|
263
|
+
dirty.speed = true;
|
|
264
|
+
speedOverride = value;
|
|
265
|
+
preset.speed = value;
|
|
266
|
+
renderer.setPreset({ ...preset });
|
|
267
|
+
if (isMotionPaused()) renderOnce();
|
|
268
|
+
return this;
|
|
269
|
+
},
|
|
270
|
+
setFallbackColor(value) {
|
|
271
|
+
dirty.fallbackColor = true;
|
|
272
|
+
merged.fallbackColor = value;
|
|
273
|
+
syncLayerVars();
|
|
274
|
+
return this;
|
|
275
|
+
},
|
|
276
|
+
setMouseColor(value) {
|
|
277
|
+
dirty.mouseColor = true;
|
|
278
|
+
merged.mouseColor = value !== false;
|
|
279
|
+
if (typeof renderer.setMouseColor === 'function') renderer.setMouseColor(merged.mouseColor);
|
|
280
|
+
return this;
|
|
281
|
+
},
|
|
282
|
+
setQuality(quality) {
|
|
283
|
+
dirty.quality = true;
|
|
284
|
+
merged.quality = quality;
|
|
285
|
+
if (typeof renderer.setDprCap === 'function') {
|
|
286
|
+
renderer.setDprCap(effectiveDprCap(quality, merged.renderScale));
|
|
287
|
+
}
|
|
288
|
+
if (isMotionPaused()) renderOnce();
|
|
289
|
+
return this;
|
|
290
|
+
},
|
|
291
|
+
setRenderScale(renderScale) {
|
|
292
|
+
const value = Number(renderScale);
|
|
293
|
+
if (!Number.isFinite(value)) return this;
|
|
294
|
+
dirty.renderScale = true;
|
|
295
|
+
merged.renderScale = Math.min(1, Math.max(0.25, value));
|
|
296
|
+
if (typeof renderer.setDprCap === 'function') {
|
|
297
|
+
renderer.setDprCap(effectiveDprCap(merged.quality, merged.renderScale));
|
|
298
|
+
}
|
|
299
|
+
if (isMotionPaused()) renderOnce();
|
|
300
|
+
return this;
|
|
301
|
+
},
|
|
302
|
+
setOpacity(value) {
|
|
303
|
+
const opacity = Number(value);
|
|
304
|
+
if (!Number.isFinite(opacity)) return this;
|
|
305
|
+
dirty.opacity = true;
|
|
306
|
+
merged.opacity = Math.min(1, Math.max(0, opacity));
|
|
307
|
+
layer.style.setProperty('--dlc-color-opacity', String(merged.opacity));
|
|
308
|
+
return this;
|
|
309
|
+
},
|
|
310
|
+
randomize() {
|
|
311
|
+
this.setSeed(Math.random() * 100);
|
|
312
|
+
return this;
|
|
313
|
+
},
|
|
314
|
+
pause() {
|
|
315
|
+
dirty.paused = true;
|
|
316
|
+
manuallyPaused = true;
|
|
317
|
+
renderOnce();
|
|
318
|
+
return this;
|
|
319
|
+
},
|
|
320
|
+
resume() {
|
|
321
|
+
dirty.paused = true;
|
|
322
|
+
manuallyPaused = false;
|
|
323
|
+
wakeScheduler();
|
|
324
|
+
return this;
|
|
325
|
+
},
|
|
326
|
+
setPaused(value) {
|
|
327
|
+
return value ? this.pause() : this.resume();
|
|
328
|
+
},
|
|
329
|
+
setStatic(value) {
|
|
330
|
+
dirty.static = true;
|
|
331
|
+
staticMode = value === true;
|
|
332
|
+
merged.static = staticMode;
|
|
333
|
+
if (staticMode) renderOnce();
|
|
334
|
+
else wakeScheduler();
|
|
335
|
+
return this;
|
|
336
|
+
},
|
|
337
|
+
setFps(fps) {
|
|
338
|
+
dirty.fps = true;
|
|
339
|
+
merged.fps = frameGate.setFps(fps);
|
|
340
|
+
wakeScheduler();
|
|
341
|
+
return this;
|
|
342
|
+
},
|
|
343
|
+
dispose() {
|
|
344
|
+
disposed = true;
|
|
345
|
+
unsubscribe();
|
|
346
|
+
visibility.dispose();
|
|
347
|
+
motionPreference.dispose();
|
|
348
|
+
if (resizeObserver) resizeObserver.disconnect();
|
|
349
|
+
else window.removeEventListener('resize', resize);
|
|
350
|
+
renderer.dispose();
|
|
351
|
+
layer.remove();
|
|
352
|
+
releaseHostStyles(host);
|
|
353
|
+
},
|
|
354
|
+
get opacity() { return merged.opacity; },
|
|
355
|
+
get fallbackColor() { return merged.fallbackColor; },
|
|
356
|
+
get mouseColor() { return merged.mouseColor; },
|
|
357
|
+
get quality() { return merged.quality; },
|
|
358
|
+
get renderScale() { return merged.renderScale; },
|
|
359
|
+
get paused() { return manuallyPaused; },
|
|
360
|
+
get static() { return staticMode; },
|
|
361
|
+
get fps() { return frameGate.getFps(); },
|
|
362
|
+
dirty
|
|
363
|
+
};
|
|
1303
364
|
}
|
|
1304
365
|
|
|
1305
366
|
export { createColorBackground };
|