reze-engine 0.3.12 → 0.3.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/audio.js DELETED
@@ -1,116 +0,0 @@
1
- /**
2
- * Audio system for generating procedural explosion sounds
3
- * Based on Web Audio API synthesis
4
- */
5
- export class AudioSystem {
6
- constructor() {
7
- this.ctx = null;
8
- this.enabled = false;
9
- this.volume = 1;
10
- this.limiter = null;
11
- }
12
- /**
13
- * Initialize audio context and compressor
14
- * Must be called after user interaction (browser requirement)
15
- */
16
- init() {
17
- if (!this.ctx) {
18
- this.ctx = new (window.AudioContext || window.webkitAudioContext)();
19
- this.limiter = this.ctx.createDynamicsCompressor();
20
- this.limiter.threshold.value = -10;
21
- this.limiter.knee.value = 40;
22
- this.limiter.ratio.value = 12;
23
- this.limiter.connect(this.ctx.destination);
24
- this.enabled = true;
25
- }
26
- // Resume if suspended (iOS/Safari requirement)
27
- if (this.ctx.state === "suspended") {
28
- this.ctx.resume();
29
- }
30
- }
31
- /**
32
- * Play deep bass explosion sound (firework burst)
33
- * Combines sub-bass, noise, and crack sounds for realistic explosion
34
- */
35
- playExplosion() {
36
- if (!this.enabled || !this.ctx || !this.limiter)
37
- return;
38
- const t = this.ctx.currentTime;
39
- // --- 1. SUB-BASS KICK (deep rumble) ---
40
- const osc = this.ctx.createOscillator();
41
- const oscGain = this.ctx.createGain();
42
- osc.type = "sine";
43
- osc.frequency.setValueAtTime(50, t); // Start at 50Hz
44
- osc.frequency.exponentialRampToValueAtTime(20, t + 2.5); // Drop to 20Hz
45
- oscGain.gain.setValueAtTime(this.volume * 1.5, t);
46
- oscGain.gain.exponentialRampToValueAtTime(0.01, t + 5.0); // Long decay
47
- osc.connect(oscGain);
48
- oscGain.connect(this.limiter);
49
- osc.start(t);
50
- osc.stop(t + 5.0);
51
- // --- 2. NOISE (crackling/rumble texture) ---
52
- const bufferSize = this.ctx.sampleRate * 5.0;
53
- const buffer = this.ctx.createBuffer(1, bufferSize, this.ctx.sampleRate);
54
- const data = buffer.getChannelData(0);
55
- for (let i = 0; i < bufferSize; i++) {
56
- data[i] = Math.random() * 2 - 1;
57
- }
58
- const noise = this.ctx.createBufferSource();
59
- noise.buffer = buffer;
60
- const noiseFilter = this.ctx.createBiquadFilter();
61
- noiseFilter.type = "lowpass";
62
- noiseFilter.frequency.setValueAtTime(150, t);
63
- noiseFilter.frequency.exponentialRampToValueAtTime(30, t + 4.0);
64
- const noiseGain = this.ctx.createGain();
65
- noiseGain.gain.setValueAtTime(this.volume * 1.0, t);
66
- noiseGain.gain.exponentialRampToValueAtTime(0.01, t + 4.5);
67
- noise.connect(noiseFilter);
68
- noiseFilter.connect(noiseGain);
69
- noiseGain.connect(this.limiter);
70
- noise.start(t);
71
- // --- 3. CRACK (sharp attack) ---
72
- const crack = this.ctx.createOscillator();
73
- crack.type = "triangle";
74
- const crackGain = this.ctx.createGain();
75
- crack.frequency.setValueAtTime(200, t);
76
- crack.frequency.exponentialRampToValueAtTime(50, t + 0.1);
77
- crackGain.gain.setValueAtTime(this.volume * 0.3, t);
78
- crackGain.gain.exponentialRampToValueAtTime(0.01, t + 0.1);
79
- crack.connect(crackGain);
80
- crackGain.connect(this.limiter);
81
- crack.start(t);
82
- crack.stop(t + 0.1);
83
- }
84
- /**
85
- * Play lighter "whoosh" sound for rocket launch
86
- */
87
- playRocketLaunch() {
88
- if (!this.enabled || !this.ctx || !this.limiter)
89
- return;
90
- const t = this.ctx.currentTime;
91
- // Rising tone
92
- const osc = this.ctx.createOscillator();
93
- const oscGain = this.ctx.createGain();
94
- osc.type = "sawtooth";
95
- osc.frequency.setValueAtTime(100, t);
96
- osc.frequency.exponentialRampToValueAtTime(400, t + 0.5);
97
- oscGain.gain.setValueAtTime(this.volume * 0.3, t);
98
- oscGain.gain.exponentialRampToValueAtTime(0.01, t + 0.5);
99
- osc.connect(oscGain);
100
- oscGain.connect(this.limiter);
101
- osc.start(t);
102
- osc.stop(t + 0.5);
103
- }
104
- setVolume(volume) {
105
- this.volume = Math.max(0, Math.min(1, volume));
106
- }
107
- getVolume() {
108
- return this.volume;
109
- }
110
- isEnabled() {
111
- return this.enabled;
112
- }
113
- setEnabled(enabled) {
114
- this.enabled = enabled;
115
- }
116
- }
@@ -1,67 +0,0 @@
1
- import { Vec3 } from "./math";
2
- export interface ParticleSystemConfig {
3
- particleCount: number;
4
- particleSize: number;
5
- fadeSpeed: number;
6
- explosionForce: number;
7
- hoverDuration: number;
8
- gravity: number;
9
- friction: number;
10
- rocketSpeed: number;
11
- rocketSize: number;
12
- }
13
- export declare const DEFAULT_PARTICLE_CONFIG: ParticleSystemConfig;
14
- interface ParticleData {
15
- positions: Float32Array;
16
- velocities: Float32Array;
17
- colors: Float32Array;
18
- lifetimes: Float32Array;
19
- count: number;
20
- }
21
- export declare class Firework {
22
- private startX;
23
- private config;
24
- private phase;
25
- private timer;
26
- private pos;
27
- private vel;
28
- private targetY;
29
- private colors;
30
- private rocketAlive;
31
- private rocketLifetime;
32
- private justExploded;
33
- private particles;
34
- private baseColors;
35
- constructor(startX: number, config: ParticleSystemConfig);
36
- private hslToRgb;
37
- update(deltaTime: number): void;
38
- private smoothstep;
39
- private explode;
40
- isDead(): boolean;
41
- isRocket(): boolean;
42
- getRocketPosition(): Vec3;
43
- getRocketColor(): Vec3;
44
- getParticleData(): ParticleData | null;
45
- hasJustExploded(): boolean;
46
- clearExplosionFlag(): void;
47
- }
48
- export declare class ParticleSystem {
49
- private fireworks;
50
- private config;
51
- private maxConcurrentFireworks;
52
- private autoLaunch;
53
- private launchInterval;
54
- private lastLaunchTime;
55
- private nextLaunchDelay;
56
- constructor(config?: Partial<ParticleSystemConfig>);
57
- update(deltaTime: number): void;
58
- spawnFirework(x?: number): void;
59
- getFireworks(): Firework[];
60
- setAutoLaunch(enabled: boolean): void;
61
- setConfig(config: Partial<ParticleSystemConfig>): void;
62
- getConfig(): ParticleSystemConfig;
63
- setMaxConcurrentFireworks(max: number): void;
64
- getMaxConcurrentFireworks(): number;
65
- }
66
- export {};
67
- //# sourceMappingURL=particles.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"particles.d.ts","sourceRoot":"","sources":["../src/particles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAI7B,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,EAAE,MAAM,CAAA;IACtB,aAAa,EAAE,MAAM,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,eAAO,MAAM,uBAAuB,EAAE,oBAUrC,CAAA;AAED,UAAU,YAAY;IACpB,SAAS,EAAE,YAAY,CAAA;IACvB,UAAU,EAAE,YAAY,CAAA;IACxB,MAAM,EAAE,YAAY,CAAA;IACpB,SAAS,EAAE,YAAY,CAAA;IACvB,KAAK,EAAE,MAAM,CAAA;CACd;AAED,qBAAa,QAAQ;IAeP,OAAO,CAAC,MAAM;IAAU,OAAO,CAAC,MAAM;IAdlD,OAAO,CAAC,KAAK,CAA0C;IACvD,OAAO,CAAC,KAAK,CAAY;IACzB,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,YAAY,CAAiB;IAGrC,OAAO,CAAC,SAAS,CAA4B;IAC7C,OAAO,CAAC,UAAU,CAA4B;gBAE1B,MAAM,EAAE,MAAM,EAAU,MAAM,EAAE,oBAAoB;IA4BxE,OAAO,CAAC,QAAQ;IAsBhB,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAgE/B,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,OAAO;IAwDf,MAAM,IAAI,OAAO;IAIjB,QAAQ,IAAI,OAAO;IAInB,iBAAiB,IAAI,IAAI;IAIzB,cAAc,IAAI,IAAI;IAItB,eAAe,IAAI,YAAY,GAAG,IAAI;IAItC,eAAe,IAAI,OAAO;IAI1B,kBAAkB,IAAI,IAAI;CAG3B;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,MAAM,CAAuD;IACrE,OAAO,CAAC,sBAAsB,CAAY;IAG1C,OAAO,CAAC,UAAU,CAAiB;IACnC,OAAO,CAAC,cAAc,CAAe;IACrC,OAAO,CAAC,cAAc,CAAY;IAClC,OAAO,CAAC,eAAe,CAAY;gBAEvB,MAAM,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC;IAMlD,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAoB/B,aAAa,CAAC,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAS/B,YAAY,IAAI,QAAQ,EAAE;IAI1B,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAQrC,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,oBAAoB,CAAC,GAAG,IAAI;IAItD,SAAS,IAAI,oBAAoB;IAIjC,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAI5C,yBAAyB,IAAI,MAAM;CAGpC"}
package/dist/particles.js DELETED
@@ -1,266 +0,0 @@
1
- import { Vec3 } from "./math";
2
- const MAX_PARTICLES = 30000;
3
- export const DEFAULT_PARTICLE_CONFIG = {
4
- particleCount: 5000, // Reduced from 23000 for better performance
5
- particleSize: 0.1, // Smaller particles
6
- fadeSpeed: 0.008, // Faster fade = particles die sooner
7
- explosionForce: 0.6, // Smaller explosion radius
8
- hoverDuration: 1.2, // Shorter hover
9
- gravity: 0.00265,
10
- friction: 0.95494,
11
- rocketSpeed: 1.0,
12
- rocketSize: 0.4, // Smaller rocket trail
13
- };
14
- export class Firework {
15
- constructor(startX, config) {
16
- this.startX = startX;
17
- this.config = config;
18
- this.phase = "rocket";
19
- this.timer = 0;
20
- this.colors = [];
21
- this.rocketAlive = true;
22
- this.rocketLifetime = 1.0;
23
- this.justExploded = false; // Flag for triggering audio
24
- // Explosion particle data
25
- this.particles = null;
26
- this.baseColors = null;
27
- // Generate color palette (mono, dual, or tri-color)
28
- const rand = Math.random();
29
- const baseHue = Math.random();
30
- if (rand < 0.33) {
31
- // MONO (1 Color)
32
- this.colors.push(this.hslToRgb(baseHue, 1.0, 0.6));
33
- }
34
- else if (rand < 0.66) {
35
- // DUAL (2 Colors - Complementary)
36
- this.colors.push(this.hslToRgb(baseHue, 1.0, 0.6));
37
- this.colors.push(this.hslToRgb((baseHue + 0.5) % 1.0, 1.0, 0.5));
38
- }
39
- else {
40
- // TRI (3 Colors - Triad)
41
- this.colors.push(this.hslToRgb(baseHue, 1.0, 0.6));
42
- this.colors.push(this.hslToRgb((baseHue + 0.33) % 1.0, 1.0, 0.6));
43
- this.colors.push(this.hslToRgb((baseHue + 0.66) % 1.0, 1.0, 0.6));
44
- }
45
- this.pos = new Vec3(startX, -50, (Math.random() - 0.5) * 30);
46
- this.vel = new Vec3((Math.random() - 0.5) * 0.5, config.rocketSpeed * (0.9 + Math.random() * 0.3), (Math.random() - 0.5) * 0.5);
47
- this.targetY = 10 + Math.random() * 20; // Higher explosion point
48
- }
49
- hslToRgb(h, s, l) {
50
- let r, g, b;
51
- if (s === 0) {
52
- r = g = b = l;
53
- }
54
- else {
55
- const hue2rgb = (p, q, t) => {
56
- if (t < 0)
57
- t += 1;
58
- if (t > 1)
59
- t -= 1;
60
- if (t < 1 / 6)
61
- return p + (q - p) * 6 * t;
62
- if (t < 1 / 2)
63
- return q;
64
- if (t < 2 / 3)
65
- return p + (q - p) * (2 / 3 - t) * 6;
66
- return p;
67
- };
68
- const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
69
- const p = 2 * l - q;
70
- r = hue2rgb(p, q, h + 1 / 3);
71
- g = hue2rgb(p, q, h);
72
- b = hue2rgb(p, q, h - 1 / 3);
73
- }
74
- return new Vec3(r, g, b);
75
- }
76
- update(deltaTime) {
77
- if (this.phase === "rocket") {
78
- this.pos.x += this.vel.x;
79
- this.pos.y += this.vel.y;
80
- this.pos.z += this.vel.z;
81
- this.vel.y *= 0.99;
82
- this.rocketLifetime -= deltaTime * 0.5;
83
- if (this.vel.y < 0.2 || this.pos.y >= this.targetY || this.rocketLifetime <= 0) {
84
- this.explode();
85
- }
86
- }
87
- else if (this.phase === "explode") {
88
- this.timer += deltaTime;
89
- if (!this.particles)
90
- return;
91
- const isHovering = this.timer < this.config.hoverDuration;
92
- const gravityFactor = this.smoothstep(this.timer, this.config.hoverDuration, this.config.hoverDuration + 0.5);
93
- let aliveCount = 0;
94
- const positions = this.particles.positions;
95
- const velocities = this.particles.velocities;
96
- const colors = this.particles.colors;
97
- const lifetimes = this.particles.lifetimes;
98
- for (let i = 0; i < this.particles.count; i++) {
99
- if (lifetimes[i] > 0) {
100
- aliveCount++;
101
- const i3 = i * 3;
102
- // Update position
103
- positions[i3] += velocities[i3];
104
- positions[i3 + 1] += velocities[i3 + 1];
105
- positions[i3 + 2] += velocities[i3 + 2];
106
- if (isHovering) {
107
- // Hovering phase - apply friction
108
- velocities[i3] *= this.config.friction;
109
- velocities[i3 + 1] *= this.config.friction;
110
- velocities[i3 + 2] *= this.config.friction;
111
- }
112
- else {
113
- // Falling phase - apply gravity and fade
114
- velocities[i3 + 1] -= this.config.gravity * gravityFactor;
115
- velocities[i3] *= 0.98;
116
- velocities[i3 + 1] *= 0.98;
117
- velocities[i3 + 2] *= 0.98;
118
- lifetimes[i] -= this.config.fadeSpeed;
119
- }
120
- // Update color alpha
121
- const alpha = Math.max(0, lifetimes[i]);
122
- if (this.baseColors) {
123
- colors[i3] = this.baseColors[i3] * alpha * 1.5;
124
- colors[i3 + 1] = this.baseColors[i3 + 1] * alpha * 1.5;
125
- colors[i3 + 2] = this.baseColors[i3 + 2] * alpha * 1.5;
126
- }
127
- }
128
- }
129
- if (aliveCount === 0) {
130
- this.phase = "dead";
131
- }
132
- }
133
- }
134
- smoothstep(x, edge0, edge1) {
135
- const t = Math.max(0, Math.min(1, (x - edge0) / (edge1 - edge0)));
136
- return t * t * (3 - 2 * t);
137
- }
138
- explode() {
139
- this.phase = "explode";
140
- this.timer = 0;
141
- this.rocketAlive = false;
142
- this.justExploded = true; // Mark for audio trigger
143
- const particleCount = Math.min(this.config.particleCount, MAX_PARTICLES);
144
- const positions = new Float32Array(particleCount * 3);
145
- const velocities = new Float32Array(particleCount * 3);
146
- const colors = new Float32Array(particleCount * 3);
147
- const lifetimes = new Float32Array(particleCount);
148
- this.baseColors = new Float32Array(particleCount * 3);
149
- const baseSpeed = this.config.explosionForce * (0.8 + Math.random() * 0.4);
150
- for (let i = 0; i < particleCount; i++) {
151
- const i3 = i * 3;
152
- // Set initial position to explosion center
153
- positions[i3] = this.pos.x;
154
- positions[i3 + 1] = this.pos.y;
155
- positions[i3 + 2] = this.pos.z;
156
- // Generate spherical velocity distribution
157
- const theta = Math.random() * Math.PI * 2;
158
- const phi = Math.acos(2 * Math.random() - 1);
159
- const speed = baseSpeed * (0.8 + Math.random() * 0.4);
160
- velocities[i3] = speed * Math.sin(phi) * Math.cos(theta);
161
- velocities[i3 + 1] = speed * Math.sin(phi) * Math.sin(theta);
162
- velocities[i3 + 2] = speed * Math.cos(phi);
163
- // Pick color from palette and vary brightness
164
- const targetColor = this.colors[Math.floor(Math.random() * this.colors.length)];
165
- const brightness = 0.5 + Math.random() * 0.8;
166
- this.baseColors[i3] = targetColor.x * brightness;
167
- this.baseColors[i3 + 1] = targetColor.y * brightness;
168
- this.baseColors[i3 + 2] = targetColor.z * brightness;
169
- colors[i3] = this.baseColors[i3];
170
- colors[i3 + 1] = this.baseColors[i3 + 1];
171
- colors[i3 + 2] = this.baseColors[i3 + 2];
172
- lifetimes[i] = 1.0;
173
- }
174
- this.particles = {
175
- positions,
176
- velocities,
177
- colors,
178
- lifetimes,
179
- count: particleCount,
180
- };
181
- }
182
- isDead() {
183
- return this.phase === "dead";
184
- }
185
- isRocket() {
186
- return this.phase === "rocket" && this.rocketAlive;
187
- }
188
- getRocketPosition() {
189
- return this.pos;
190
- }
191
- getRocketColor() {
192
- return this.colors[0];
193
- }
194
- getParticleData() {
195
- return this.particles;
196
- }
197
- hasJustExploded() {
198
- return this.justExploded;
199
- }
200
- clearExplosionFlag() {
201
- this.justExploded = false;
202
- }
203
- }
204
- export class ParticleSystem {
205
- constructor(config) {
206
- this.fireworks = [];
207
- this.config = { ...DEFAULT_PARTICLE_CONFIG };
208
- this.maxConcurrentFireworks = 5; // Limit concurrent fireworks for performance
209
- // Auto-launch settings
210
- this.autoLaunch = false;
211
- this.launchInterval = 3000; // ms
212
- this.lastLaunchTime = 0;
213
- this.nextLaunchDelay = 0;
214
- if (config) {
215
- this.config = { ...this.config, ...config };
216
- }
217
- }
218
- update(deltaTime) {
219
- // Update existing fireworks
220
- for (let i = this.fireworks.length - 1; i >= 0; i--) {
221
- this.fireworks[i].update(deltaTime);
222
- if (this.fireworks[i].isDead()) {
223
- this.fireworks.splice(i, 1);
224
- }
225
- }
226
- // Auto-launch
227
- if (this.autoLaunch) {
228
- const now = performance.now();
229
- if (now - this.lastLaunchTime > this.nextLaunchDelay) {
230
- this.lastLaunchTime = now;
231
- this.nextLaunchDelay = this.launchInterval + Math.random() * 1000;
232
- this.spawnFirework();
233
- }
234
- }
235
- }
236
- spawnFirework(x) {
237
- // Don't spawn if we're at the limit (for performance)
238
- if (this.fireworks.length >= this.maxConcurrentFireworks) {
239
- return;
240
- }
241
- const startX = x !== undefined ? x : (Math.random() - 0.5) * 5;
242
- this.fireworks.push(new Firework(startX, this.config));
243
- }
244
- getFireworks() {
245
- return this.fireworks;
246
- }
247
- setAutoLaunch(enabled) {
248
- this.autoLaunch = enabled;
249
- if (enabled) {
250
- this.lastLaunchTime = performance.now();
251
- this.nextLaunchDelay = 0;
252
- }
253
- }
254
- setConfig(config) {
255
- this.config = { ...this.config, ...config };
256
- }
257
- getConfig() {
258
- return { ...this.config };
259
- }
260
- setMaxConcurrentFireworks(max) {
261
- this.maxConcurrentFireworks = Math.max(1, max);
262
- }
263
- getMaxConcurrentFireworks() {
264
- return this.maxConcurrentFireworks;
265
- }
266
- }