@basmilius/sparkle 2.1.0 → 2.2.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.
Files changed (107) hide show
  1. package/dist/index.d.mts +306 -459
  2. package/dist/index.d.mts.map +1 -1
  3. package/dist/index.mjs +1106 -848
  4. package/dist/index.mjs.map +1 -1
  5. package/package.json +6 -2
  6. package/src/aurora/index.ts +9 -3
  7. package/src/aurora/layer.ts +57 -29
  8. package/src/balloons/index.ts +9 -3
  9. package/src/balloons/layer.ts +50 -19
  10. package/src/bubbles/index.ts +9 -3
  11. package/src/bubbles/layer.ts +30 -17
  12. package/src/canvas.ts +12 -0
  13. package/src/color.ts +11 -2
  14. package/src/confetti/index.ts +15 -3
  15. package/src/confetti/layer.ts +8 -5
  16. package/src/confetti/particle.ts +12 -11
  17. package/src/donuts/consts.ts +2 -2
  18. package/src/donuts/index.ts +9 -3
  19. package/src/donuts/layer.ts +43 -12
  20. package/src/effect.ts +107 -0
  21. package/src/fade.ts +87 -0
  22. package/src/fireflies/index.ts +9 -3
  23. package/src/fireflies/layer.ts +26 -9
  24. package/src/fireflies/particle.ts +2 -2
  25. package/src/firepit/index.ts +9 -3
  26. package/src/firepit/layer.ts +26 -7
  27. package/src/fireworks/create-explosion.ts +237 -0
  28. package/src/fireworks/explosion.ts +1 -1
  29. package/src/fireworks/index.ts +15 -3
  30. package/src/fireworks/layer.ts +55 -304
  31. package/src/fireworks/spark.ts +2 -2
  32. package/src/fireworks/types.ts +2 -2
  33. package/src/glitter/index.ts +9 -4
  34. package/src/glitter/layer.ts +15 -7
  35. package/src/glitter/types.ts +10 -0
  36. package/src/index.ts +3 -4
  37. package/src/lanterns/index.ts +9 -4
  38. package/src/lanterns/layer.ts +22 -10
  39. package/src/lanterns/types.ts +8 -0
  40. package/src/layer.ts +13 -11
  41. package/src/leaves/index.ts +9 -4
  42. package/src/leaves/layer.ts +21 -14
  43. package/src/leaves/types.ts +9 -0
  44. package/src/lightning/index.ts +9 -4
  45. package/src/lightning/layer.ts +4 -4
  46. package/src/lightning/system.ts +3 -3
  47. package/src/lightning/types.ts +10 -2
  48. package/src/matrix/index.ts +9 -4
  49. package/src/matrix/layer.ts +15 -7
  50. package/src/matrix/types.ts +9 -0
  51. package/src/orbits/index.ts +9 -4
  52. package/src/orbits/layer.ts +51 -21
  53. package/src/orbits/types.ts +12 -1
  54. package/src/particles/index.ts +9 -3
  55. package/src/particles/layer.ts +55 -12
  56. package/src/petals/index.ts +9 -3
  57. package/src/petals/layer.ts +29 -13
  58. package/src/plasma/index.ts +9 -3
  59. package/src/plasma/layer.ts +21 -6
  60. package/src/rain/index.ts +9 -3
  61. package/src/rain/layer.ts +30 -8
  62. package/src/sandstorm/index.ts +9 -3
  63. package/src/sandstorm/layer.ts +26 -9
  64. package/src/scene.ts +201 -0
  65. package/src/shooting-stars/system.ts +26 -24
  66. package/src/shooting-stars/types.ts +2 -1
  67. package/src/simulation-canvas.ts +40 -4
  68. package/src/snow/index.ts +9 -3
  69. package/src/snow/layer.ts +24 -11
  70. package/src/sparklers/index.ts +13 -3
  71. package/src/sparklers/layer.ts +61 -15
  72. package/src/stars/index.ts +9 -3
  73. package/src/stars/layer.ts +28 -22
  74. package/src/streamers/index.ts +9 -3
  75. package/src/streamers/layer.ts +18 -6
  76. package/src/streamers/types.ts +1 -1
  77. package/src/waves/index.ts +9 -3
  78. package/src/waves/layer.ts +42 -45
  79. package/src/waves/types.ts +1 -0
  80. package/src/wormhole/index.ts +9 -3
  81. package/src/wormhole/layer.ts +22 -6
  82. package/src/aurora/simulation.ts +0 -19
  83. package/src/balloons/simulation.ts +0 -19
  84. package/src/bubbles/simulation.ts +0 -20
  85. package/src/confetti/simulation.ts +0 -27
  86. package/src/donuts/simulation.ts +0 -25
  87. package/src/fireflies/simulation.ts +0 -18
  88. package/src/firepit/simulation.ts +0 -17
  89. package/src/fireworks/simulation.ts +0 -18
  90. package/src/glitter/simulation.ts +0 -19
  91. package/src/lanterns/simulation.ts +0 -17
  92. package/src/layered.ts +0 -185
  93. package/src/leaves/simulation.ts +0 -18
  94. package/src/lightning/simulation.ts +0 -17
  95. package/src/matrix/simulation.ts +0 -18
  96. package/src/orbits/simulation.ts +0 -19
  97. package/src/particles/simulation.ts +0 -26
  98. package/src/petals/simulation.ts +0 -18
  99. package/src/plasma/simulation.ts +0 -17
  100. package/src/rain/simulation.ts +0 -21
  101. package/src/sandstorm/simulation.ts +0 -18
  102. package/src/snow/simulation.ts +0 -17
  103. package/src/sparklers/simulation.ts +0 -30
  104. package/src/stars/simulation.ts +0 -22
  105. package/src/streamers/simulation.ts +0 -16
  106. package/src/waves/simulation.ts +0 -18
  107. package/src/wormhole/simulation.ts +0 -17
@@ -1,18 +1,33 @@
1
- import { SimulationLayer } from '../layer';
1
+ import { Effect } from '../effect';
2
2
  import { DEFAULT_CONFIG, MULBERRY } from './consts';
3
3
  import type { Donut } from './donut';
4
- import type { DonutSimulationConfig } from './simulation';
5
4
 
6
- export class DonutLayer extends SimulationLayer {
5
+ export interface DonutsConfig {
6
+ readonly background?: string;
7
+ readonly collisionPadding?: number;
8
+ readonly colors?: string[];
9
+ readonly count?: number;
10
+ readonly mouseAvoidance?: boolean;
11
+ readonly mouseAvoidanceRadius?: number;
12
+ readonly mouseAvoidanceStrength?: number;
13
+ readonly radiusRange?: [number, number];
14
+ readonly repulsionStrength?: number;
15
+ readonly rotationSpeedRange?: [number, number];
16
+ readonly scale?: number;
17
+ readonly speedRange?: [number, number];
18
+ readonly thickness?: number;
19
+ }
20
+
21
+ export class Donuts extends Effect<DonutsConfig> {
7
22
  readonly #background: string;
8
23
  readonly #collisionPadding: number;
9
24
  readonly #colors: string[];
10
25
  readonly #count: number;
11
- readonly #mouseAvoidance: boolean;
12
- readonly #mouseAvoidanceRadius: number;
13
- readonly #mouseAvoidanceStrength: number;
26
+ #mouseAvoidance: boolean;
27
+ #mouseAvoidanceRadius: number;
28
+ #mouseAvoidanceStrength: number;
14
29
  readonly #radiusRange: [number, number];
15
- readonly #repulsionStrength: number;
30
+ #repulsionStrength: number;
16
31
  readonly #rotationSpeedRange: [number, number];
17
32
  readonly #scale: number;
18
33
  readonly #speedRange: [number, number];
@@ -27,7 +42,7 @@ export class DonutLayer extends SimulationLayer {
27
42
  #height: number = 540;
28
43
  #initialized: boolean = false;
29
44
 
30
- constructor(config: DonutSimulationConfig = {}) {
45
+ constructor(config: DonutsConfig = {}) {
31
46
  super();
32
47
 
33
48
  const scale = config.scale ?? 1;
@@ -82,6 +97,21 @@ export class DonutLayer extends SimulationLayer {
82
97
  canvas.removeEventListener('mouseleave', this.#onMouseLeaveBound);
83
98
  }
84
99
 
100
+ configure(config: Partial<DonutsConfig>): void {
101
+ if (config.mouseAvoidance !== undefined) {
102
+ this.#mouseAvoidance = config.mouseAvoidance;
103
+ }
104
+ if (config.mouseAvoidanceRadius !== undefined) {
105
+ this.#mouseAvoidanceRadius = config.mouseAvoidanceRadius;
106
+ }
107
+ if (config.mouseAvoidanceStrength !== undefined) {
108
+ this.#mouseAvoidanceStrength = config.mouseAvoidanceStrength;
109
+ }
110
+ if (config.repulsionStrength !== undefined) {
111
+ this.#repulsionStrength = config.repulsionStrength;
112
+ }
113
+ }
114
+
85
115
  tick(dt: number, width: number, height: number): void {
86
116
  this.#width = width;
87
117
  this.#height = height;
@@ -103,9 +133,9 @@ export class DonutLayer extends SimulationLayer {
103
133
  ctx.fillRect(0, 0, width, height);
104
134
 
105
135
  for (const donut of this.#donuts) {
106
- ctx.save();
107
- ctx.translate(donut.x, donut.y);
108
- ctx.rotate(donut.angle);
136
+ const cos = Math.cos(donut.angle);
137
+ const sin = Math.sin(donut.angle);
138
+ ctx.setTransform(cos, sin, -sin, cos, donut.x, donut.y);
109
139
 
110
140
  ctx.beginPath();
111
141
  ctx.arc(0, 0, donut.outerRadius, 0, Math.PI * 2);
@@ -114,8 +144,9 @@ export class DonutLayer extends SimulationLayer {
114
144
 
115
145
  ctx.fillStyle = donut.color;
116
146
  ctx.fill();
117
- ctx.restore();
118
147
  }
148
+
149
+ ctx.resetTransform();
119
150
  }
120
151
 
121
152
  #updateDonut(donut: Donut, dt: number): void {
package/src/effect.ts ADDED
@@ -0,0 +1,107 @@
1
+ import { SimulationCanvas } from './simulation-canvas';
2
+ import type { EdgeFade, EdgeFadeSide, SimulationLayer } from './layer';
3
+
4
+ export type { EdgeFade, EdgeFadeSide };
5
+
6
+ /**
7
+ * Base class for all visual effects. Implements the internal SimulationLayer interface
8
+ * so that effects can be used both standalone (via mount()) and composed in a Scene.
9
+ *
10
+ * @example Standalone usage
11
+ * const snow = new Snow({ particles: 200 });
12
+ * snow.mount(canvas).start();
13
+ *
14
+ * @example Scene composition
15
+ * const scene = new Scene()
16
+ * .mount(canvas)
17
+ * .layer(new Aurora())
18
+ * .layer(new Snow())
19
+ * .start();
20
+ */
21
+ export abstract class Effect<TConfig = Record<string, unknown>> implements SimulationLayer {
22
+ #canvas: SimulationCanvas | null = null;
23
+ fade: EdgeFade | null = null;
24
+
25
+ abstract tick(dt: number, width: number, height: number): void;
26
+
27
+ abstract draw(ctx: CanvasRenderingContext2D, width: number, height: number): void;
28
+
29
+ configure(_config: Partial<TConfig>): void {
30
+ }
31
+
32
+ onResize(_width: number, _height: number): void {
33
+ }
34
+
35
+ onMount(_canvas: HTMLCanvasElement): void {
36
+ }
37
+
38
+ onUnmount(_canvas: HTMLCanvasElement): void {
39
+ }
40
+
41
+ /**
42
+ * Apply an edge fade mask when rendering this effect standalone or in a Scene.
43
+ */
44
+ withFade(fade: EdgeFade): this {
45
+ this.fade = fade;
46
+ return this;
47
+ }
48
+
49
+ /**
50
+ * Mount this effect to a canvas element or CSS selector, creating the render loop.
51
+ * Must be called before start().
52
+ */
53
+ mount(canvas: HTMLCanvasElement | string, options: CanvasRenderingContext2DSettings = {colorSpace: 'display-p3'}): this {
54
+ if (typeof canvas === 'string') {
55
+ const el = document.querySelector<HTMLCanvasElement>(canvas);
56
+
57
+ if (!el) {
58
+ throw new Error(`Effect.mount(): no element found for selector "${canvas}".`);
59
+ }
60
+
61
+ canvas = el;
62
+ }
63
+
64
+ this.#canvas = new SimulationCanvas(canvas, this as unknown as SimulationLayer, 60, options);
65
+ return this;
66
+ }
67
+
68
+ /**
69
+ * Remove this effect from its canvas and clean up the render loop.
70
+ */
71
+ unmount(): this {
72
+ this.#canvas?.destroy();
73
+ this.#canvas = null;
74
+ return this;
75
+ }
76
+
77
+ /**
78
+ * Start the render loop. Call mount() first.
79
+ */
80
+ start(): this {
81
+ this.#canvas?.start();
82
+ return this;
83
+ }
84
+
85
+ /**
86
+ * Pause rendering without destroying state. Use resume() to continue.
87
+ */
88
+ pause(): this {
89
+ this.#canvas?.pause();
90
+ return this;
91
+ }
92
+
93
+ /**
94
+ * Resume rendering after a pause().
95
+ */
96
+ resume(): this {
97
+ this.#canvas?.resume();
98
+ return this;
99
+ }
100
+
101
+ /**
102
+ * Stop rendering and call onUnmount(). Safe to call multiple times.
103
+ */
104
+ destroy(): void {
105
+ this.unmount();
106
+ }
107
+ }
package/src/fade.ts ADDED
@@ -0,0 +1,87 @@
1
+ import type { EdgeFade, EdgeFadeSide } from './layer';
2
+
3
+ function parseSide(side: EdgeFadeSide): [number, number] {
4
+ return typeof side === 'number' ? [0, side] : side;
5
+ }
6
+
7
+ export function applyEdgeFade(ctx: CanvasRenderingContext2D, width: number, height: number, fade: EdgeFade): void {
8
+ ctx.globalCompositeOperation = 'destination-out';
9
+
10
+ if (fade.top !== undefined) {
11
+ const [near, far] = parseSide(fade.top);
12
+ const nearPx = near * height;
13
+ const farPx = far * height;
14
+
15
+ if (nearPx > 0) {
16
+ ctx.fillStyle = 'rgba(0,0,0,1)';
17
+ ctx.fillRect(0, 0, width, nearPx);
18
+ }
19
+
20
+ if (farPx > nearPx) {
21
+ const gradient = ctx.createLinearGradient(0, nearPx, 0, farPx);
22
+ gradient.addColorStop(0, 'rgba(0,0,0,1)');
23
+ gradient.addColorStop(1, 'rgba(0,0,0,0)');
24
+ ctx.fillStyle = gradient;
25
+ ctx.fillRect(0, nearPx, width, farPx - nearPx);
26
+ }
27
+ }
28
+
29
+ if (fade.bottom !== undefined) {
30
+ const [near, far] = parseSide(fade.bottom);
31
+ const nearPx = near * height;
32
+ const farPx = far * height;
33
+
34
+ if (nearPx > 0) {
35
+ ctx.fillStyle = 'rgba(0,0,0,1)';
36
+ ctx.fillRect(0, height - nearPx, width, nearPx);
37
+ }
38
+
39
+ if (farPx > nearPx) {
40
+ const gradient = ctx.createLinearGradient(0, height - farPx, 0, height - nearPx);
41
+ gradient.addColorStop(0, 'rgba(0,0,0,0)');
42
+ gradient.addColorStop(1, 'rgba(0,0,0,1)');
43
+ ctx.fillStyle = gradient;
44
+ ctx.fillRect(0, height - farPx, width, farPx - nearPx);
45
+ }
46
+ }
47
+
48
+ if (fade.left !== undefined) {
49
+ const [near, far] = parseSide(fade.left);
50
+ const nearPx = near * width;
51
+ const farPx = far * width;
52
+
53
+ if (nearPx > 0) {
54
+ ctx.fillStyle = 'rgba(0,0,0,1)';
55
+ ctx.fillRect(0, 0, nearPx, height);
56
+ }
57
+
58
+ if (farPx > nearPx) {
59
+ const gradient = ctx.createLinearGradient(nearPx, 0, farPx, 0);
60
+ gradient.addColorStop(0, 'rgba(0,0,0,1)');
61
+ gradient.addColorStop(1, 'rgba(0,0,0,0)');
62
+ ctx.fillStyle = gradient;
63
+ ctx.fillRect(nearPx, 0, farPx - nearPx, height);
64
+ }
65
+ }
66
+
67
+ if (fade.right !== undefined) {
68
+ const [near, far] = parseSide(fade.right);
69
+ const nearPx = near * width;
70
+ const farPx = far * width;
71
+
72
+ if (nearPx > 0) {
73
+ ctx.fillStyle = 'rgba(0,0,0,1)';
74
+ ctx.fillRect(width - nearPx, 0, nearPx, height);
75
+ }
76
+
77
+ if (farPx > nearPx) {
78
+ const gradient = ctx.createLinearGradient(width - farPx, 0, width - nearPx, 0);
79
+ gradient.addColorStop(0, 'rgba(0,0,0,0)');
80
+ gradient.addColorStop(1, 'rgba(0,0,0,1)');
81
+ ctx.fillStyle = gradient;
82
+ ctx.fillRect(width - farPx, 0, farPx - nearPx, height);
83
+ }
84
+ }
85
+
86
+ ctx.globalCompositeOperation = 'source-over';
87
+ }
@@ -1,6 +1,12 @@
1
- export { FireflyLayer } from './layer';
1
+ import { Fireflies } from './layer';
2
+ import type { FirefliesConfig } from './layer';
3
+ import type { Effect } from '../effect';
4
+
5
+ export function createFireflies(config?: FirefliesConfig): Effect<FirefliesConfig> {
6
+ return new Fireflies(config);
7
+ }
8
+
2
9
  export { FireflyParticle, createFireflySprite } from './particle';
3
- export { FireflySimulation } from './simulation';
10
+ export type { FirefliesConfig };
4
11
  export type { FireflyParticleConfig } from './particle';
5
- export type { FireflySimulationConfig } from './simulation';
6
12
  export type { Firefly } from './types';
@@ -1,23 +1,31 @@
1
- import { SimulationLayer } from '../layer';
1
+ import { Effect } from '../effect';
2
2
  import { MULBERRY } from './consts';
3
- import type { FireflySimulationConfig } from './simulation';
4
3
  import type { Firefly } from './types';
5
4
 
6
5
  const SPRITE_SIZE = 64;
7
6
  const SPRITE_CENTER = SPRITE_SIZE / 2;
8
7
  const SPRITE_RADIUS = SPRITE_SIZE / 2;
9
8
 
10
- export class FireflyLayer extends SimulationLayer {
9
+ export interface FirefliesConfig {
10
+ readonly count?: number;
11
+ readonly color?: string;
12
+ readonly size?: number;
13
+ readonly speed?: number;
14
+ readonly glowSpeed?: number;
15
+ readonly scale?: number;
16
+ }
17
+
18
+ export class Fireflies extends Effect<FirefliesConfig> {
11
19
  readonly #scale: number;
12
20
  readonly #size: number;
13
- readonly #speed: number;
14
- readonly #glowSpeed: number;
21
+ #speed: number;
22
+ #glowSpeed: number;
15
23
  #maxCount: number;
16
24
  #time: number = 0;
17
25
  #fireflies: Firefly[] = [];
18
26
  #sprite: HTMLCanvasElement;
19
27
 
20
- constructor(config: FireflySimulationConfig = {}) {
28
+ constructor(config: FirefliesConfig = {}) {
21
29
  super();
22
30
 
23
31
  this.#scale = config.scale ?? 1;
@@ -39,15 +47,24 @@ export class FireflyLayer extends SimulationLayer {
39
47
  }
40
48
  }
41
49
 
50
+ configure(config: Partial<FirefliesConfig>): void {
51
+ if (config.speed !== undefined) {
52
+ this.#speed = config.speed;
53
+ }
54
+ if (config.glowSpeed !== undefined) {
55
+ this.#glowSpeed = config.glowSpeed;
56
+ }
57
+ }
58
+
42
59
  tick(dt: number, _width: number, _height: number): void {
43
60
  this.#time += 0.02 * dt * this.#speed;
44
61
 
45
62
  for (const firefly of this.#fireflies) {
46
63
  const moveX = Math.sin(this.#time * firefly.freqX1 + firefly.phaseX1) * firefly.amplitudeX
47
- + Math.sin(this.#time * firefly.freqX2 + firefly.phaseX2) * firefly.amplitudeX * 0.5;
64
+ + Math.sin(this.#time * firefly.freqX2 + firefly.phaseX2) * firefly.amplitudeX * 0.5;
48
65
 
49
66
  const moveY = Math.sin(this.#time * firefly.freqY1 + firefly.phaseY1) * firefly.amplitudeY
50
- + Math.sin(this.#time * firefly.freqY2 + firefly.phaseY2) * firefly.amplitudeY * 0.5;
67
+ + Math.sin(this.#time * firefly.freqY2 + firefly.phaseY2) * firefly.amplitudeY * 0.5;
51
68
 
52
69
  firefly.x += moveX * dt / (3000 * (1 / this.#speed));
53
70
  firefly.y += moveY * dt / (3000 * (1 / this.#speed));
@@ -94,7 +111,7 @@ export class FireflyLayer extends SimulationLayer {
94
111
  ctx.globalAlpha = 1;
95
112
  }
96
113
 
97
- #parseColor(color: string): {r: number; g: number; b: number} {
114
+ #parseColor(color: string): { r: number; g: number; b: number } {
98
115
  const canvas = document.createElement('canvas');
99
116
  canvas.width = 1;
100
117
  canvas.height = 1;
@@ -101,10 +101,10 @@ export class FireflyParticle {
101
101
  this.#time += 0.02 * dt * this.#speed;
102
102
 
103
103
  const moveX = Math.sin(this.#time * this.#freqX1 + this.#phaseX1) * this.#amplitudeX * this.#bounds.width
104
- + Math.sin(this.#time * this.#freqX2 + this.#phaseX2) * this.#amplitudeX * this.#bounds.width * 0.5;
104
+ + Math.sin(this.#time * this.#freqX2 + this.#phaseX2) * this.#amplitudeX * this.#bounds.width * 0.5;
105
105
 
106
106
  const moveY = Math.sin(this.#time * this.#freqY1 + this.#phaseY1) * this.#amplitudeY * this.#bounds.height
107
- + Math.sin(this.#time * this.#freqY2 + this.#phaseY2) * this.#amplitudeY * this.#bounds.height * 0.5;
107
+ + Math.sin(this.#time * this.#freqY2 + this.#phaseY2) * this.#amplitudeY * this.#bounds.height * 0.5;
108
108
 
109
109
  this.#x += (moveX / 3000) * dt;
110
110
  this.#y += (moveY / 3000) * dt;
@@ -1,4 +1,10 @@
1
- export { FirepitLayer } from './layer';
2
- export { FirepitSimulation } from './simulation';
3
- export type { FirepitSimulationConfig } from './simulation';
1
+ import { Firepit } from './layer';
2
+ import type { FirepitConfig } from './layer';
3
+ import type { Effect } from '../effect';
4
+
5
+ export function createFirepit(config?: FirepitConfig): Effect<FirepitConfig> {
6
+ return new Firepit(config);
7
+ }
8
+
9
+ export type { FirepitConfig };
4
10
  export type { Ember, FlameLayer } from './types';
@@ -1,19 +1,26 @@
1
- import { SimulationLayer } from '../layer';
1
+ import { Effect } from '../effect';
2
2
  import { MULBERRY } from './consts';
3
- import type { FirepitSimulationConfig } from './simulation';
4
3
  import type { Ember, FlameLayer } from './types';
5
4
 
6
- export class FirepitLayer extends SimulationLayer {
5
+ export interface FirepitConfig {
6
+ readonly embers?: number;
7
+ readonly flameWidth?: number;
8
+ readonly flameHeight?: number;
9
+ readonly intensity?: number;
10
+ readonly scale?: number;
11
+ }
12
+
13
+ export class Firepit extends Effect<FirepitConfig> {
7
14
  readonly #scale: number;
8
- readonly #flameWidth: number;
9
- readonly #flameHeight: number;
10
- readonly #intensity: number;
15
+ #flameWidth: number;
16
+ #flameHeight: number;
17
+ #intensity: number;
11
18
  #maxEmbers: number;
12
19
  #time: number = 0;
13
20
  #embers: Ember[] = [];
14
21
  #flameLayers: FlameLayer[] = [];
15
22
 
16
- constructor(config: FirepitSimulationConfig = {}) {
23
+ constructor(config: FirepitConfig = {}) {
17
24
  super();
18
25
 
19
26
  this.#scale = config.scale ?? 1;
@@ -38,6 +45,18 @@ export class FirepitLayer extends SimulationLayer {
38
45
  }
39
46
  }
40
47
 
48
+ configure(config: Partial<FirepitConfig>): void {
49
+ if (config.intensity !== undefined) {
50
+ this.#intensity = config.intensity;
51
+ }
52
+ if (config.flameWidth !== undefined) {
53
+ this.#flameWidth = config.flameWidth;
54
+ }
55
+ if (config.flameHeight !== undefined) {
56
+ this.#flameHeight = config.flameHeight;
57
+ }
58
+ }
59
+
41
60
  tick(dt: number, _width: number, _height: number): void {
42
61
  this.#time += 0.03 * dt * this.#intensity;
43
62