fireworks-engine 1.0.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.
- package/LICENSE +24 -0
- package/README.md +297 -0
- package/index.d.ts +691 -0
- package/package.json +49 -0
- package/src/burstConfigBuilder.js +262 -0
- package/src/burstSpawn.js +764 -0
- package/src/colorUtils.js +80 -0
- package/src/configBuilder.js +300 -0
- package/src/defaults.js +87 -0
- package/src/index.js +13 -0
- package/src/mathResolvers.js +77 -0
- package/src/presets.js +811 -0
- package/src/renderer.js +863 -0
- package/src/rocketLaunch.js +791 -0
- package/src/runtime.js +796 -0
- package/src/runtimeCapabilities.js +7 -0
- package/src/runtimeLifecycle.js +330 -0
- package/src/update.js +307 -0
- package/src/valueNormalizers.js +160 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { clamp } from './mathResolvers.js';
|
|
2
|
+
|
|
3
|
+
export function parseHexColor(color) {
|
|
4
|
+
if (typeof color !== 'string') {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const match = color.trim().match(/^#([\da-f]{3}|[\da-f]{6})$/i);
|
|
9
|
+
if (!match) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const normalized = match[1].length === 3
|
|
14
|
+
? match[1].split('').map((channel) => `${channel}${channel}`).join('')
|
|
15
|
+
: match[1];
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
r: Number.parseInt(normalized.slice(0, 2), 16),
|
|
19
|
+
g: Number.parseInt(normalized.slice(2, 4), 16),
|
|
20
|
+
b: Number.parseInt(normalized.slice(4, 6), 16),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function toHexChannel(value) {
|
|
25
|
+
return clamp(Math.round(value), 0, 255).toString(16).padStart(2, '0');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
export function normalizeHexColor(color, fallback = '#ffd166') {
|
|
30
|
+
const rgb = parseHexColor(color);
|
|
31
|
+
if (!rgb) {
|
|
32
|
+
return fallback;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return `#${toHexChannel(rgb.r)}${toHexChannel(rgb.g)}${toHexChannel(rgb.b)}`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function mixHexColor(color, targetColor, amount) {
|
|
39
|
+
const sourceRgb = parseHexColor(color);
|
|
40
|
+
const targetRgb = parseHexColor(targetColor);
|
|
41
|
+
if (!sourceRgb || !targetRgb) {
|
|
42
|
+
return color;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const safeAmount = clamp(amount, 0, 1);
|
|
46
|
+
const inverseAmount = 1 - safeAmount;
|
|
47
|
+
return `#${toHexChannel((sourceRgb.r * inverseAmount) + (targetRgb.r * safeAmount))}${
|
|
48
|
+
toHexChannel((sourceRgb.g * inverseAmount) + (targetRgb.g * safeAmount))
|
|
49
|
+
}${toHexChannel((sourceRgb.b * inverseAmount) + (targetRgb.b * safeAmount))}`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function boostHexColor(color, brightnessBoost, saturationBoost = 0) {
|
|
53
|
+
const rgb = parseHexColor(color);
|
|
54
|
+
if (!rgb) {
|
|
55
|
+
return color;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const safeSaturationBoost = Math.max(0, saturationBoost);
|
|
59
|
+
const gray = (rgb.r * 0.299) + (rgb.g * 0.587) + (rgb.b * 0.114);
|
|
60
|
+
const saturationScale = 1 + safeSaturationBoost;
|
|
61
|
+
const saturated = {
|
|
62
|
+
r: gray + ((rgb.r - gray) * saturationScale),
|
|
63
|
+
g: gray + ((rgb.g - gray) * saturationScale),
|
|
64
|
+
b: gray + ((rgb.b - gray) * saturationScale),
|
|
65
|
+
};
|
|
66
|
+
const brightnessScale = 1 + Math.max(0, brightnessBoost);
|
|
67
|
+
|
|
68
|
+
return `#${toHexChannel(saturated.r * brightnessScale)}${
|
|
69
|
+
toHexChannel(saturated.g * brightnessScale)
|
|
70
|
+
}${toHexChannel(saturated.b * brightnessScale)}`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function toAlphaColor(color, alpha) {
|
|
74
|
+
const rgb = parseHexColor(color);
|
|
75
|
+
if (!rgb) {
|
|
76
|
+
return color;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${clamp(alpha, 0, 1)})`;
|
|
80
|
+
}
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_ENABLE_BURST_QUEUE_THROTTLING,
|
|
3
|
+
DEFAULT_TIME_SCALE,
|
|
4
|
+
DEFAULT_ROCKET_ENABLED,
|
|
5
|
+
DEFAULT_ROCKET_STREAK_LENGTH,
|
|
6
|
+
DEFAULT_ROCKET_FINAL_STREAK_LENGTH,
|
|
7
|
+
DEFAULT_ROCKET_THICKNESS,
|
|
8
|
+
DEFAULT_ROCKET_SPEED,
|
|
9
|
+
DEFAULT_ROCKET_TAIL_EMBERS_ENABLED,
|
|
10
|
+
DEFAULT_ROCKET_TAIL_EMBERS_COUNT,
|
|
11
|
+
DEFAULT_ROCKET_TAIL_EMBERS_BRIGHTNESS,
|
|
12
|
+
DEFAULT_ROCKET_TAIL_EMBERS_FADE,
|
|
13
|
+
DEFAULT_ROCKET_TAIL_EMBERS_SPREAD_X,
|
|
14
|
+
DEFAULT_ROCKET_TAIL_EMBERS_SPREAD_Y,
|
|
15
|
+
DEFAULT_ROCKET_TAIL_EMBERS_SPEED,
|
|
16
|
+
DEFAULT_ROCKET_TAIL_EMBERS_SIZE,
|
|
17
|
+
DEFAULT_BURST_COLOR_MODE,
|
|
18
|
+
DEFAULT_BURST_FORMS_ENABLED,
|
|
19
|
+
DEFAULT_BURST_FORMS_COUNT,
|
|
20
|
+
DEFAULT_BURST_FORMS_SPEED_MIN,
|
|
21
|
+
DEFAULT_BURST_FORMS_SPEED_MAX,
|
|
22
|
+
DEFAULT_BURST_FORMS_GRAVITY,
|
|
23
|
+
DEFAULT_BURST_FORMS_LIFE_MIN,
|
|
24
|
+
DEFAULT_BURST_FORMS_LIFE_MAX,
|
|
25
|
+
DEFAULT_BURST_FORMS_SIZE_MIN,
|
|
26
|
+
DEFAULT_BURST_FORMS_SIZE_MAX,
|
|
27
|
+
DEFAULT_BURST_FORMS_SPIN,
|
|
28
|
+
DEFAULT_BURST_FORMS_SPIN_COVERAGE,
|
|
29
|
+
DEFAULT_BURST_FORMS_SPIN_DURATION,
|
|
30
|
+
DEFAULT_BURST_FORMS_SPIN_PAUSE,
|
|
31
|
+
DEFAULT_BURST_FORMS_HIGHLIGHT,
|
|
32
|
+
DEFAULT_BURST_FORMS_HIGHLIGHT_ANGLE_DEG,
|
|
33
|
+
DEFAULT_BURST_FORMS_HIGHLIGHT_WIDTH,
|
|
34
|
+
DEFAULT_BURST_FORMS_WOBBLE,
|
|
35
|
+
DEFAULT_BURST_FORMS_DIRECTION_DEG,
|
|
36
|
+
DEFAULT_BURST_FORMS_CONE_DEG,
|
|
37
|
+
DEFAULT_BURST_FORMS_SHAPE,
|
|
38
|
+
DEFAULT_BURST_FORMS_GLYPH,
|
|
39
|
+
DEFAULT_BURST_SPARKS_ENABLED,
|
|
40
|
+
BURST_SPARK_COUNT_BASE,
|
|
41
|
+
DEFAULT_BURST_SPARK_LENGTH,
|
|
42
|
+
DEFAULT_BURST_SPARK_DIRECTION_DEG,
|
|
43
|
+
DEFAULT_BURST_SPARK_CONE_DEG,
|
|
44
|
+
DEFAULT_BURST_SPARK_TAIL_SCALE,
|
|
45
|
+
DEFAULT_BURST_SPARK_THICKNESS,
|
|
46
|
+
DEFAULT_BURST_SPARK_SHAPE,
|
|
47
|
+
BURST_SPARK_SPEED_MIN_BASE,
|
|
48
|
+
BURST_SPARK_SPEED_MAX_BASE,
|
|
49
|
+
DEFAULT_BURST_SPARK_GRAVITY,
|
|
50
|
+
BURST_SPARK_LIFE_MIN_BASE,
|
|
51
|
+
BURST_SPARK_LIFE_MAX_BASE,
|
|
52
|
+
DEFAULT_BURST_CENTER_FLASH_ENABLED,
|
|
53
|
+
DEFAULT_BURST_CENTER_FLASH_START_SIZE,
|
|
54
|
+
DEFAULT_BURST_CENTER_FLASH_END_SIZE,
|
|
55
|
+
DEFAULT_BURST_CENTER_FLASH_PEAK_ALPHA,
|
|
56
|
+
DEFAULT_BURST_CENTER_FLASH_ATTACK,
|
|
57
|
+
DEFAULT_BURST_CENTER_FLASH_FADE,
|
|
58
|
+
DEFAULT_BURST_CENTER_FLASH_COLOR_MODE,
|
|
59
|
+
DEFAULT_BURST_CENTER_FLASH_COLOR,
|
|
60
|
+
DEFAULT_BURST_CENTER_FLASH_INNER_STOP,
|
|
61
|
+
DEFAULT_BURST_TWINKLE_CLOUD_ENABLED,
|
|
62
|
+
DEFAULT_BURST_TWINKLE_CLOUD_COUNT,
|
|
63
|
+
DEFAULT_BURST_TWINKLE_CLOUD_RADIUS,
|
|
64
|
+
DEFAULT_BURST_TWINKLE_CLOUD_START_DELAY,
|
|
65
|
+
DEFAULT_BURST_TWINKLE_CLOUD_DURATION,
|
|
66
|
+
DEFAULT_BURST_TWINKLE_CLOUD_TWINKLE_LIFE,
|
|
67
|
+
DEFAULT_BURST_TWINKLE_CLOUD_BRIGHTNESS,
|
|
68
|
+
DEFAULT_BURST_TWINKLE_CLOUD_SIZE,
|
|
69
|
+
DEFAULT_BURST_TWINKLE_CLOUD_SPAWN_SPREAD,
|
|
70
|
+
DEFAULT_BURST_PALETTE,
|
|
71
|
+
DEFAULT_BURST_SINGLE_COLOR,
|
|
72
|
+
} from './defaults.js';
|
|
73
|
+
import {
|
|
74
|
+
resolveSizeScale,
|
|
75
|
+
resolveTimeScale,
|
|
76
|
+
resolveOptionalPositiveInteger,
|
|
77
|
+
} from './mathResolvers.js';
|
|
78
|
+
import {
|
|
79
|
+
resolveBurstFormShape,
|
|
80
|
+
normalizeBurstFormGlyph,
|
|
81
|
+
resolveBurstColorMode,
|
|
82
|
+
resolveBurstFlashColorMode,
|
|
83
|
+
resolveBurstSparkShape,
|
|
84
|
+
} from './valueNormalizers.js';
|
|
85
|
+
import { normalizeHexColor } from './colorUtils.js';
|
|
86
|
+
|
|
87
|
+
const MIN_COUNT = 1;
|
|
88
|
+
const MIN_MAX_BURST_PARTICLES_PER_FRAME = 1;
|
|
89
|
+
const MIN_PARTICLE_PRESSURE_THRESHOLD = 1;
|
|
90
|
+
|
|
91
|
+
function resolveBoolean(value, fallback) {
|
|
92
|
+
if (typeof value === 'boolean') {
|
|
93
|
+
return value;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return fallback;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function resolvePositiveIntegerOrDefault(value, minValue, fallback) {
|
|
100
|
+
return resolveOptionalPositiveInteger(value, minValue) ?? fallback;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function resolveRocketConfig(rocket = {}) {
|
|
104
|
+
return {
|
|
105
|
+
enabled: resolveBoolean(rocket.enabled, DEFAULT_ROCKET_ENABLED),
|
|
106
|
+
colorMode: resolveBurstColorMode(rocket.colorMode ?? DEFAULT_BURST_COLOR_MODE),
|
|
107
|
+
singleColor: normalizeHexColor(
|
|
108
|
+
rocket.singleColor ?? rocket.color,
|
|
109
|
+
DEFAULT_BURST_SINGLE_COLOR,
|
|
110
|
+
),
|
|
111
|
+
palette: Array.isArray(rocket.palette) && rocket.palette.length > 0
|
|
112
|
+
? rocket.palette
|
|
113
|
+
: null,
|
|
114
|
+
streakLength: rocket.streakLength ?? DEFAULT_ROCKET_STREAK_LENGTH,
|
|
115
|
+
finalStreakLength: rocket.finalStreakLength ?? DEFAULT_ROCKET_FINAL_STREAK_LENGTH,
|
|
116
|
+
thickness: rocket.thickness ?? DEFAULT_ROCKET_THICKNESS,
|
|
117
|
+
speed: rocket.speed ?? DEFAULT_ROCKET_SPEED,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function resolveRocketTailEmbersConfig(rocketTailEmbers = {}) {
|
|
122
|
+
return {
|
|
123
|
+
enabled: resolveBoolean(rocketTailEmbers.enabled, DEFAULT_ROCKET_TAIL_EMBERS_ENABLED),
|
|
124
|
+
count: resolvePositiveIntegerOrDefault(rocketTailEmbers.count, MIN_COUNT, DEFAULT_ROCKET_TAIL_EMBERS_COUNT),
|
|
125
|
+
brightness: rocketTailEmbers.brightness ?? DEFAULT_ROCKET_TAIL_EMBERS_BRIGHTNESS,
|
|
126
|
+
fade: rocketTailEmbers.fade ?? DEFAULT_ROCKET_TAIL_EMBERS_FADE,
|
|
127
|
+
spreadX: rocketTailEmbers.spreadX ?? DEFAULT_ROCKET_TAIL_EMBERS_SPREAD_X,
|
|
128
|
+
spreadY: rocketTailEmbers.spreadY ?? DEFAULT_ROCKET_TAIL_EMBERS_SPREAD_Y,
|
|
129
|
+
speed: rocketTailEmbers.speed ?? DEFAULT_ROCKET_TAIL_EMBERS_SPEED,
|
|
130
|
+
size: rocketTailEmbers.size ?? DEFAULT_ROCKET_TAIL_EMBERS_SIZE,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function resolveBurstFormsConfig(burstForms = {}) {
|
|
135
|
+
return {
|
|
136
|
+
enabled: resolveBoolean(burstForms.enabled, DEFAULT_BURST_FORMS_ENABLED),
|
|
137
|
+
count: resolvePositiveIntegerOrDefault(burstForms.count, MIN_COUNT, DEFAULT_BURST_FORMS_COUNT),
|
|
138
|
+
speedMin: burstForms.speedMin ?? DEFAULT_BURST_FORMS_SPEED_MIN,
|
|
139
|
+
speedMax: burstForms.speedMax ?? DEFAULT_BURST_FORMS_SPEED_MAX,
|
|
140
|
+
gravity: burstForms.gravity ?? DEFAULT_BURST_FORMS_GRAVITY,
|
|
141
|
+
lifeMin: burstForms.lifeMin ?? DEFAULT_BURST_FORMS_LIFE_MIN,
|
|
142
|
+
lifeMax: burstForms.lifeMax ?? DEFAULT_BURST_FORMS_LIFE_MAX,
|
|
143
|
+
sizeMin: burstForms.sizeMin ?? DEFAULT_BURST_FORMS_SIZE_MIN,
|
|
144
|
+
sizeMax: burstForms.sizeMax ?? DEFAULT_BURST_FORMS_SIZE_MAX,
|
|
145
|
+
spin: burstForms.spin ?? DEFAULT_BURST_FORMS_SPIN,
|
|
146
|
+
spinCoverage: burstForms.spinCoverage ?? DEFAULT_BURST_FORMS_SPIN_COVERAGE,
|
|
147
|
+
spinDuration: burstForms.spinDuration ?? DEFAULT_BURST_FORMS_SPIN_DURATION,
|
|
148
|
+
spinPause: burstForms.spinPause ?? DEFAULT_BURST_FORMS_SPIN_PAUSE,
|
|
149
|
+
highlight: burstForms.highlight ?? DEFAULT_BURST_FORMS_HIGHLIGHT,
|
|
150
|
+
highlightAngleDeg: burstForms.highlightAngleDeg ?? DEFAULT_BURST_FORMS_HIGHLIGHT_ANGLE_DEG,
|
|
151
|
+
highlightWidth: burstForms.highlightWidth ?? DEFAULT_BURST_FORMS_HIGHLIGHT_WIDTH,
|
|
152
|
+
wobble: burstForms.wobble ?? DEFAULT_BURST_FORMS_WOBBLE,
|
|
153
|
+
directionDeg: burstForms.directionDeg ?? DEFAULT_BURST_FORMS_DIRECTION_DEG,
|
|
154
|
+
coneDeg: burstForms.coneDeg ?? DEFAULT_BURST_FORMS_CONE_DEG,
|
|
155
|
+
colorMode: resolveBurstColorMode(burstForms.colorMode ?? DEFAULT_BURST_COLOR_MODE),
|
|
156
|
+
singleColor: normalizeHexColor(burstForms.singleColor, DEFAULT_BURST_SINGLE_COLOR),
|
|
157
|
+
shape: resolveBurstFormShape(burstForms.shape ?? DEFAULT_BURST_FORMS_SHAPE),
|
|
158
|
+
glyph: normalizeBurstFormGlyph(burstForms.glyph, DEFAULT_BURST_FORMS_GLYPH),
|
|
159
|
+
palette: Array.isArray(burstForms.palette) && burstForms.palette.length > 0
|
|
160
|
+
? burstForms.palette
|
|
161
|
+
: DEFAULT_BURST_PALETTE,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function resolveBurstSparksConfig(burstSparks = {}) {
|
|
166
|
+
const burstSparksConfig = {
|
|
167
|
+
enabled: resolveBoolean(burstSparks.enabled, DEFAULT_BURST_SPARKS_ENABLED),
|
|
168
|
+
count: resolvePositiveIntegerOrDefault(burstSparks.count, MIN_COUNT, BURST_SPARK_COUNT_BASE),
|
|
169
|
+
length: burstSparks.length ?? DEFAULT_BURST_SPARK_LENGTH,
|
|
170
|
+
tailScale: burstSparks.tailScale ?? DEFAULT_BURST_SPARK_TAIL_SCALE,
|
|
171
|
+
thickness: burstSparks.thickness ?? DEFAULT_BURST_SPARK_THICKNESS,
|
|
172
|
+
speedMin: burstSparks.speedMin ?? BURST_SPARK_SPEED_MIN_BASE,
|
|
173
|
+
speedMax: burstSparks.speedMax ?? BURST_SPARK_SPEED_MAX_BASE,
|
|
174
|
+
gravity: burstSparks.gravity ?? DEFAULT_BURST_SPARK_GRAVITY,
|
|
175
|
+
lifeMin: burstSparks.lifeMin ?? BURST_SPARK_LIFE_MIN_BASE,
|
|
176
|
+
lifeMax: burstSparks.lifeMax ?? BURST_SPARK_LIFE_MAX_BASE,
|
|
177
|
+
directionDeg: burstSparks.directionDeg ?? DEFAULT_BURST_SPARK_DIRECTION_DEG,
|
|
178
|
+
coneDeg: burstSparks.coneDeg ?? DEFAULT_BURST_SPARK_CONE_DEG,
|
|
179
|
+
shape: resolveBurstSparkShape(burstSparks.shape ?? DEFAULT_BURST_SPARK_SHAPE),
|
|
180
|
+
colorMode: resolveBurstColorMode(burstSparks.colorMode ?? DEFAULT_BURST_COLOR_MODE),
|
|
181
|
+
singleColor: normalizeHexColor(burstSparks.singleColor, DEFAULT_BURST_SINGLE_COLOR),
|
|
182
|
+
palette: Array.isArray(burstSparks.palette) && burstSparks.palette.length > 0
|
|
183
|
+
? burstSparks.palette
|
|
184
|
+
: null,
|
|
185
|
+
};
|
|
186
|
+
burstSparksConfig.speedMax = Math.max(burstSparksConfig.speedMin, burstSparksConfig.speedMax);
|
|
187
|
+
burstSparksConfig.lifeMax = Math.max(burstSparksConfig.lifeMin, burstSparksConfig.lifeMax);
|
|
188
|
+
return burstSparksConfig;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function resolveBurstCenterFlashConfig(burstCenterFlash = {}) {
|
|
192
|
+
return {
|
|
193
|
+
enabled: resolveBoolean(burstCenterFlash.enabled, DEFAULT_BURST_CENTER_FLASH_ENABLED),
|
|
194
|
+
startSize: burstCenterFlash.startSize ?? DEFAULT_BURST_CENTER_FLASH_START_SIZE,
|
|
195
|
+
endSize: burstCenterFlash.endSize ?? DEFAULT_BURST_CENTER_FLASH_END_SIZE,
|
|
196
|
+
peakAlpha: burstCenterFlash.peakAlpha ?? DEFAULT_BURST_CENTER_FLASH_PEAK_ALPHA,
|
|
197
|
+
attack: burstCenterFlash.attack ?? DEFAULT_BURST_CENTER_FLASH_ATTACK,
|
|
198
|
+
fade: burstCenterFlash.fade ?? DEFAULT_BURST_CENTER_FLASH_FADE,
|
|
199
|
+
colorMode: resolveBurstFlashColorMode(
|
|
200
|
+
burstCenterFlash.colorMode ?? DEFAULT_BURST_CENTER_FLASH_COLOR_MODE,
|
|
201
|
+
),
|
|
202
|
+
color: normalizeHexColor(burstCenterFlash.color, DEFAULT_BURST_CENTER_FLASH_COLOR),
|
|
203
|
+
innerStop: burstCenterFlash.innerStop ?? DEFAULT_BURST_CENTER_FLASH_INNER_STOP,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function resolveBurstTwinkleCloudConfig(burstTwinkleCloud = {}) {
|
|
208
|
+
return {
|
|
209
|
+
enabled: resolveBoolean(burstTwinkleCloud.enabled, DEFAULT_BURST_TWINKLE_CLOUD_ENABLED),
|
|
210
|
+
count: resolvePositiveIntegerOrDefault(burstTwinkleCloud.count, MIN_COUNT, DEFAULT_BURST_TWINKLE_CLOUD_COUNT),
|
|
211
|
+
radius: burstTwinkleCloud.radius ?? DEFAULT_BURST_TWINKLE_CLOUD_RADIUS,
|
|
212
|
+
startDelay: burstTwinkleCloud.startDelay ?? DEFAULT_BURST_TWINKLE_CLOUD_START_DELAY,
|
|
213
|
+
duration: burstTwinkleCloud.duration ?? DEFAULT_BURST_TWINKLE_CLOUD_DURATION,
|
|
214
|
+
twinkleLife: burstTwinkleCloud.twinkleLife ?? DEFAULT_BURST_TWINKLE_CLOUD_TWINKLE_LIFE,
|
|
215
|
+
brightness: burstTwinkleCloud.brightness ?? DEFAULT_BURST_TWINKLE_CLOUD_BRIGHTNESS,
|
|
216
|
+
size: burstTwinkleCloud.size ?? DEFAULT_BURST_TWINKLE_CLOUD_SIZE,
|
|
217
|
+
spawnSpread: burstTwinkleCloud.spawnSpread ?? DEFAULT_BURST_TWINKLE_CLOUD_SPAWN_SPREAD,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function resolvePerformanceConfig(
|
|
222
|
+
performance = {},
|
|
223
|
+
enableBurstQueueThrottling,
|
|
224
|
+
) {
|
|
225
|
+
return {
|
|
226
|
+
enableBurstQueueThrottling,
|
|
227
|
+
maxBurstParticlesPerFrame: resolvePositiveIntegerOrDefault(performance.maxBurstParticlesPerFrame, MIN_MAX_BURST_PARTICLES_PER_FRAME, 12),
|
|
228
|
+
particlePressureThreshold: resolvePositiveIntegerOrDefault(performance.particlePressureThreshold, MIN_PARTICLE_PRESSURE_THRESHOLD, 18),
|
|
229
|
+
fastRectRadiusThreshold: performance.fastRectRadiusThreshold ?? 1.45,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function resolveRefs(runtime = {}, canvas = {}) {
|
|
234
|
+
return {
|
|
235
|
+
documentRef: runtime.document,
|
|
236
|
+
windowRef: runtime.window,
|
|
237
|
+
rootRef: canvas.appendTarget ?? runtime.root,
|
|
238
|
+
prefersReducedMotionRef: runtime.prefersReducedMotion,
|
|
239
|
+
requestAnimationFrameRef: runtime.requestAnimationFrame,
|
|
240
|
+
cancelAnimationFrameRef: runtime.cancelAnimationFrame,
|
|
241
|
+
setTimeoutRef: runtime.setTimeout,
|
|
242
|
+
clearTimeoutRef: runtime.clearTimeout,
|
|
243
|
+
nowRef: runtime.now,
|
|
244
|
+
maxDevicePixelRatio: canvas.maxDevicePixelRatio ?? 2,
|
|
245
|
+
canvasZIndex: canvas.zIndex ?? 9999,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export function buildEngineConfig(normalizedOptions = {}) {
|
|
250
|
+
const safeOptions = normalizedOptions ?? {};
|
|
251
|
+
const {
|
|
252
|
+
canvas = {},
|
|
253
|
+
runtime = {},
|
|
254
|
+
performance = {},
|
|
255
|
+
rocket = {},
|
|
256
|
+
rocketTailEmbers = {},
|
|
257
|
+
burstForms = {},
|
|
258
|
+
burstSparks = {},
|
|
259
|
+
burstCenterFlash = {},
|
|
260
|
+
burstTwinkleCloud = {},
|
|
261
|
+
} = safeOptions;
|
|
262
|
+
|
|
263
|
+
const enableBurstQueueThrottling = resolveBoolean(
|
|
264
|
+
performance.enableBurstQueueThrottling,
|
|
265
|
+
DEFAULT_ENABLE_BURST_QUEUE_THROTTLING,
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
const sizeScale = resolveSizeScale(safeOptions.sizeScale, 1);
|
|
269
|
+
const timeScale = resolveTimeScale(safeOptions.timeScale, DEFAULT_TIME_SCALE);
|
|
270
|
+
|
|
271
|
+
const rocketConfig = resolveRocketConfig(rocket);
|
|
272
|
+
const rocketTailEmbersConfig = resolveRocketTailEmbersConfig(rocketTailEmbers);
|
|
273
|
+
const burstFormsConfig = resolveBurstFormsConfig(burstForms);
|
|
274
|
+
const burstSparksConfig = resolveBurstSparksConfig(burstSparks);
|
|
275
|
+
const burstCenterFlashConfig = resolveBurstCenterFlashConfig(burstCenterFlash);
|
|
276
|
+
const burstTwinkleCloudConfig = resolveBurstTwinkleCloudConfig(burstTwinkleCloud);
|
|
277
|
+
const performanceConfig = resolvePerformanceConfig(
|
|
278
|
+
performance,
|
|
279
|
+
enableBurstQueueThrottling,
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
const refs = resolveRefs(runtime, canvas);
|
|
283
|
+
const toggles = {
|
|
284
|
+
enableBurstQueueThrottling,
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
return {
|
|
288
|
+
refs,
|
|
289
|
+
toggles,
|
|
290
|
+
timeScale,
|
|
291
|
+
sizeScale,
|
|
292
|
+
rocket: rocketConfig,
|
|
293
|
+
rocketTailEmbers: rocketTailEmbersConfig,
|
|
294
|
+
burstForms: burstFormsConfig,
|
|
295
|
+
burstSparks: burstSparksConfig,
|
|
296
|
+
burstCenterFlash: burstCenterFlashConfig,
|
|
297
|
+
burstTwinkleCloud: burstTwinkleCloudConfig,
|
|
298
|
+
performance: performanceConfig,
|
|
299
|
+
};
|
|
300
|
+
}
|
package/src/defaults.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
export const DEFAULT_ENABLE_BURST_QUEUE_THROTTLING = false;
|
|
2
|
+
export const DEFAULT_TIME_SCALE = 1;
|
|
3
|
+
|
|
4
|
+
export const DEFAULT_ROCKET_STREAK_LENGTH = 5;
|
|
5
|
+
export const DEFAULT_ROCKET_FINAL_STREAK_LENGTH = 48;
|
|
6
|
+
export const DEFAULT_ROCKET_THICKNESS = 1.35;
|
|
7
|
+
export const DEFAULT_ROCKET_SPEED = 0;
|
|
8
|
+
export const DEFAULT_ROCKET_ENABLED = true;
|
|
9
|
+
|
|
10
|
+
export const DEFAULT_ROCKET_TAIL_EMBERS_ENABLED = true;
|
|
11
|
+
export const DEFAULT_ROCKET_TAIL_EMBERS_COUNT = 6;
|
|
12
|
+
export const DEFAULT_ROCKET_TAIL_EMBERS_BRIGHTNESS = 2;
|
|
13
|
+
export const DEFAULT_ROCKET_TAIL_EMBERS_FADE = 1;
|
|
14
|
+
export const DEFAULT_ROCKET_TAIL_EMBERS_SPREAD_X = 1.5;
|
|
15
|
+
export const DEFAULT_ROCKET_TAIL_EMBERS_SPREAD_Y = 40;
|
|
16
|
+
export const DEFAULT_ROCKET_TAIL_EMBERS_SPEED = 2;
|
|
17
|
+
export const DEFAULT_ROCKET_TAIL_EMBERS_SIZE = 0.6;
|
|
18
|
+
|
|
19
|
+
export const DEFAULT_BURST_COLOR_MODE = 'palette';
|
|
20
|
+
|
|
21
|
+
export const DEFAULT_BURST_FORMS_ENABLED = true;
|
|
22
|
+
export const DEFAULT_BURST_FORMS_COUNT = 27;
|
|
23
|
+
export const DEFAULT_BURST_FORMS_SPEED_MIN = 100;
|
|
24
|
+
export const DEFAULT_BURST_FORMS_SPEED_MAX = 250;
|
|
25
|
+
export const DEFAULT_BURST_FORMS_DIRECTION_DEG = 90;
|
|
26
|
+
export const DEFAULT_BURST_FORMS_CONE_DEG = 360;
|
|
27
|
+
export const DEFAULT_BURST_FORMS_GRAVITY = 90;
|
|
28
|
+
export const DEFAULT_BURST_FORMS_LIFE_MIN = 0.6;
|
|
29
|
+
export const DEFAULT_BURST_FORMS_LIFE_MAX = 1.5;
|
|
30
|
+
export const DEFAULT_BURST_FORMS_SIZE_MIN = 1.5;
|
|
31
|
+
export const DEFAULT_BURST_FORMS_SIZE_MAX = 2.5;
|
|
32
|
+
export const DEFAULT_BURST_FORMS_SPIN = 0;
|
|
33
|
+
export const DEFAULT_BURST_FORMS_SPIN_COVERAGE = 1;
|
|
34
|
+
export const DEFAULT_BURST_FORMS_SPIN_DURATION = 2;
|
|
35
|
+
export const DEFAULT_BURST_FORMS_SPIN_PAUSE = 2;
|
|
36
|
+
export const DEFAULT_BURST_FORMS_HIGHLIGHT = 0;
|
|
37
|
+
export const DEFAULT_BURST_FORMS_HIGHLIGHT_ANGLE_DEG = 0;
|
|
38
|
+
export const DEFAULT_BURST_FORMS_HIGHLIGHT_WIDTH = 0.18;
|
|
39
|
+
export const DEFAULT_BURST_FORMS_WOBBLE = 0;
|
|
40
|
+
export const DEFAULT_BURST_FORMS_SHAPE = 'circle';
|
|
41
|
+
export const DEFAULT_BURST_FORMS_GLYPH = '★';
|
|
42
|
+
|
|
43
|
+
export const DEFAULT_BURST_SPARKS_ENABLED = true;
|
|
44
|
+
export const DEFAULT_BURST_SPARK_COUNT_RATIO = 1;
|
|
45
|
+
export const BURST_SPARK_COUNT_BASE = 80;
|
|
46
|
+
export const DEFAULT_BURST_SPARK_LENGTH = 27;
|
|
47
|
+
export const DEFAULT_BURST_SPARK_TAIL_SCALE = 1.5;
|
|
48
|
+
export const DEFAULT_BURST_SPARK_THICKNESS = 1.3;
|
|
49
|
+
export const BURST_SPARK_SPEED_MIN_BASE = 0;
|
|
50
|
+
export const BURST_SPARK_SPEED_MAX_BASE = 320;
|
|
51
|
+
export const DEFAULT_BURST_SPARK_DIRECTION_DEG = 90;
|
|
52
|
+
export const DEFAULT_BURST_SPARK_CONE_DEG = 360;
|
|
53
|
+
export const DEFAULT_BURST_SPARK_GRAVITY = 50;
|
|
54
|
+
export const BURST_SPARK_LIFE_MIN_BASE = 0.5;
|
|
55
|
+
export const BURST_SPARK_LIFE_MAX_BASE = 1.6;
|
|
56
|
+
export const DEFAULT_BURST_SPARK_SHAPE = 'fade';
|
|
57
|
+
export const BURST_SPARK_LENGTH_BASE = DEFAULT_BURST_SPARK_LENGTH;
|
|
58
|
+
export const BURST_SPARK_THICKNESS_BASE = DEFAULT_BURST_SPARK_THICKNESS;
|
|
59
|
+
|
|
60
|
+
export const DEFAULT_BURST_CENTER_FLASH_ENABLED = true;
|
|
61
|
+
export const DEFAULT_BURST_CENTER_FLASH_START_SIZE = 35;
|
|
62
|
+
export const DEFAULT_BURST_CENTER_FLASH_END_SIZE = 85;
|
|
63
|
+
export const DEFAULT_BURST_CENTER_FLASH_PEAK_ALPHA = 0.3;
|
|
64
|
+
export const DEFAULT_BURST_CENTER_FLASH_ATTACK = 0.1;
|
|
65
|
+
export const DEFAULT_BURST_CENTER_FLASH_FADE = 0.1;
|
|
66
|
+
export const DEFAULT_BURST_CENTER_FLASH_COLOR_MODE = 'rgb';
|
|
67
|
+
export const DEFAULT_BURST_CENTER_FLASH_COLOR = '#00ffee';
|
|
68
|
+
export const DEFAULT_BURST_CENTER_FLASH_INNER_STOP = 0.3;
|
|
69
|
+
|
|
70
|
+
export const DEFAULT_BURST_TWINKLE_CLOUD_ENABLED = true;
|
|
71
|
+
export const DEFAULT_BURST_TWINKLE_CLOUD_COUNT = 240;
|
|
72
|
+
export const DEFAULT_BURST_TWINKLE_CLOUD_RADIUS = 110;
|
|
73
|
+
export const DEFAULT_BURST_TWINKLE_CLOUD_START_DELAY = 0.4;
|
|
74
|
+
export const DEFAULT_BURST_TWINKLE_CLOUD_DURATION = 0.5;
|
|
75
|
+
export const DEFAULT_BURST_TWINKLE_CLOUD_TWINKLE_LIFE = 0.2;
|
|
76
|
+
export const DEFAULT_BURST_TWINKLE_CLOUD_BRIGHTNESS = 2;
|
|
77
|
+
export const DEFAULT_BURST_TWINKLE_CLOUD_SIZE = 1.2;
|
|
78
|
+
export const DEFAULT_BURST_TWINKLE_CLOUD_SPAWN_SPREAD = 1;
|
|
79
|
+
export const WHITE_BRIGHTNESS_REFERENCE = 2;
|
|
80
|
+
|
|
81
|
+
export const DEFAULT_BURST_PALETTE = ['#ffd166', '#ff6b6b', '#4ecdc4', '#74c0fc', '#c77dff', '#ffffff'];
|
|
82
|
+
export const DEFAULT_ROCKET_PALETTE = ['#ffd166', '#ff6b6b', '#74c0fc', '#ffffff'];
|
|
83
|
+
export const DEFAULT_BURST_SINGLE_COLOR = '#ffd166';
|
|
84
|
+
|
|
85
|
+
export const BURST_FLASH_ATTACK_UNIT = 0.01;
|
|
86
|
+
export const GLYPH_SPRITE_SIZE_MIN = 8;
|
|
87
|
+
export const GLYPH_SPRITE_RADIUS_SCALE = 3.2;
|
package/src/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import FireworksEngineDefault, {
|
|
2
|
+
FireworksEngine,
|
|
3
|
+
createFireworksEngine,
|
|
4
|
+
} from './runtime.js';
|
|
5
|
+
import { resolveFireworksEnginePreset } from './presets.js';
|
|
6
|
+
|
|
7
|
+
export {
|
|
8
|
+
FireworksEngine,
|
|
9
|
+
createFireworksEngine,
|
|
10
|
+
resolveFireworksEnginePreset,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default FireworksEngineDefault;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
const MIN_SCALE_EPSILON = 0.0001;
|
|
2
|
+
const SIZE_SCALE_MIN = MIN_SCALE_EPSILON;
|
|
3
|
+
const TIME_SCALE_MIN = 0.05;
|
|
4
|
+
|
|
5
|
+
export function resolveFinite(value, fallback) {
|
|
6
|
+
if (Number.isFinite(value)) {
|
|
7
|
+
return value;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (Number.isFinite(fallback)) {
|
|
11
|
+
return fallback;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return 0;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function clamp(value, min, max) {
|
|
18
|
+
return Math.min(Math.max(value, min), max);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function randomRange(min, max) {
|
|
22
|
+
return Math.random() * (max - min) + min;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function resolveScaledOverride(value, fallback, scale = 1) {
|
|
26
|
+
const base = resolveFinite(value, fallback);
|
|
27
|
+
const safeScale = Number.isFinite(scale) ? scale : 1;
|
|
28
|
+
const scaled = base * safeScale;
|
|
29
|
+
return Number.isFinite(scaled) ? scaled : resolveFinite(fallback, base);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function resolveScaledInverseOverride(value, fallback, scale = 1) {
|
|
33
|
+
const numericScale = Number.isFinite(scale) ? scale : 1;
|
|
34
|
+
const safeScaleMagnitude = Math.max(Math.abs(numericScale), MIN_SCALE_EPSILON);
|
|
35
|
+
const safeScale = numericScale < 0 ? -safeScaleMagnitude : safeScaleMagnitude;
|
|
36
|
+
const base = resolveFinite(value, fallback);
|
|
37
|
+
const scaled = base / safeScale;
|
|
38
|
+
return Number.isFinite(scaled) ? scaled : resolveFinite(fallback, base);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function resolveScaledInteger(value, fallback, min = 1, scale = 1) {
|
|
42
|
+
const safeMin = Number.isFinite(min) ? min : 1;
|
|
43
|
+
const base = resolveFinite(value, fallback);
|
|
44
|
+
const safeScale = Number.isFinite(scale) ? scale : 1;
|
|
45
|
+
const scaled = Math.floor(base * safeScale);
|
|
46
|
+
if (!Number.isFinite(scaled)) {
|
|
47
|
+
return Math.max(safeMin, Math.floor(resolveFinite(fallback, safeMin)));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return Math.max(safeMin, scaled);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
export function resolveSizeScale(value, fallback = 1) {
|
|
55
|
+
return Math.max(SIZE_SCALE_MIN, resolveFinite(value, fallback));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function resolveTimeScale(value, fallback = 1) {
|
|
59
|
+
return Math.max(TIME_SCALE_MIN, resolveFinite(value, fallback));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function resolveEnvelopeTimeScale(sizeScale) {
|
|
63
|
+
return Math.sqrt(resolveSizeScale(sizeScale, 1));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function resolveOptionalPositiveInteger(value, min = 1) {
|
|
67
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const normalized = Math.floor(value);
|
|
72
|
+
if (!Number.isFinite(normalized)) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return Math.max(min, normalized);
|
|
77
|
+
}
|