2 * Web Worker for computing multiplication table bitmap
3 * Computes (prime-1) x (prime-1) ImageData and transfers it back to main thread
4 */
6// Inline color computation function (copied from colorUtils.ts)
7function valueToColor(value: number, max: number): { r: number; g: number; b: number } {
8 const t = value / max;
10 // Smooth gradient from dark purple-blue to bright yellow-orange
11 let r: number, g: number, b: number;
13 // Red channel: smooth increase
14 r = Math.floor(13 + 242 * Math.pow(t, 0.5));
16 // Green channel: gentle S-curve for smoothness
17 g = Math.floor(8 + 247 * Math.pow(t, 1.5));
19 // Blue channel: decrease from purple to yellow
20 b = Math.floor(135 * Math.pow(1 - t, 2));
22 // Clamp values to valid range
23 r = Math.min(255, Math.max(0, r));
24 g = Math.min(255, Math.max(0, g));
25 b = Math.min(255, Math.max(0, b));
27 return { r, g, b };
28}
30self.onmessage = (e: MessageEvent<{ prime: number }>) => {
31 const { prime } = e.data;
33 // Create ImageData for (prime-1) x (prime-1) grid
34 const size = prime - 1;
35 const imageData = new ImageData(size, size);
36 const data = imageData.data;
38 // Compute multiplication table and fill ImageData
39 for (let i = 1; i < prime; i++) {
40 for (let j = 1; j < prime; j++) {
41 const value = (i * j) % prime;
42 const color = valueToColor(value, prime - 1);
44 // Calculate pixel index (RGBA format)
45 const pixelIndex = ((i - 1) * size + (j - 1)) * 4;
47 data[pixelIndex] = color.r; // Red
48 data[pixelIndex + 1] = color.g; // Green
49 data[pixelIndex + 2] = color.b; // Blue
50 data[pixelIndex + 3] = 255; // Alpha (fully opaque)
51 }
52 }
54 // Transfer ImageData back to main thread using transferable objects
55 self.postMessage(
56 { type: 'complete', imageData },
57 // @ts-expect-error - TypeScript doesn't recognize this overload but it's valid
58 [imageData.data.buffer]
59 );
60};