| 201 | } |
| 202 | |
| 203 | private render(): void { |
| 204 | const ctx = this.ctx; |
| 205 | if (!ctx) return; |
| 206 | |
| 207 | const width = window.innerWidth; |
| 208 | const height = window.innerHeight; |
| 209 | |
| 210 | ctx.clearRect(0, 0, width, height); |
| 211 | |
| 212 | ctx.save(); |
| 213 | ctx.globalCompositeOperation = "lighter"; |
| 214 | |
| 215 | for (const p of this.particles) { |
| 216 | const alpha = Math.max(0, Math.min(1, p.lifeMs / p.ttlMs)); |
| 217 | ctx.globalAlpha = alpha; |
| 218 | ctx.fillStyle = p.color; |
| 219 | ctx.fillRect(p.x, p.y, p.size, p.size); |
| 220 | } |
| 221 | |
| 222 | ctx.restore(); |
| 223 | } |
| 224 | |
| 225 | private maybeShake(intensity: number): void { |
| 226 | const el = this.shakeEl; |