diff --git a/frontend/src/lib/components/pyramid/PyramidCanvas.svelte b/frontend/src/lib/components/pyramid/PyramidCanvas.svelte index 7955f26..2836d3e 100644 --- a/frontend/src/lib/components/pyramid/PyramidCanvas.svelte +++ b/frontend/src/lib/components/pyramid/PyramidCanvas.svelte @@ -96,31 +96,49 @@ function createDataTexture(faceData) { const size = FACE_SIZE; - const data = new Uint8Array(size * size * 4); + // Use larger texture for grid lines (each pixel is 4x4 with 1px grid) + const texSize = size * 4; + const data = new Uint8Array(texSize * texSize * 4); - // Fill with default color (dark gray) - for (let i = 0; i < size * size; i++) { - data[i * 4] = 34; // R - data[i * 4 + 1] = 34; // G - data[i * 4 + 2] = 34; // B - data[i * 4 + 3] = 255; // A - } + // Fill with grid pattern + for (let py = 0; py < size; py++) { + for (let px = 0; px < size; px++) { + // Get pixel color (default dark gray or from faceData) + let r = 40, g = 40, b = 40; - // Apply pixel data from the face map - if (faceData) { - faceData.forEach((color, key) => { - const [x, y] = key.split(',').map(Number); - const idx = (y * size + x) * 4; - const rgb = hexToRgb(color); - if (rgb) { - data[idx] = rgb.r; - data[idx + 1] = rgb.g; - data[idx + 2] = rgb.b; + if (faceData) { + const key = `${px},${py}`; + const color = faceData.get(key); + if (color) { + const rgb = hexToRgb(color); + if (rgb) { r = rgb.r; g = rgb.g; b = rgb.b; } + } } - }); + + // Draw 4x4 pixel block with 1px grid border + for (let dy = 0; dy < 4; dy++) { + for (let dx = 0; dx < 4; dx++) { + const tx = px * 4 + dx; + const ty = py * 4 + dy; + const idx = (ty * texSize + tx) * 4; + + // Grid lines on edges (darker) + if (dx === 0 || dy === 0) { + data[idx] = 20; + data[idx + 1] = 20; + data[idx + 2] = 20; + } else { + data[idx] = r; + data[idx + 1] = g; + data[idx + 2] = b; + } + data[idx + 3] = 255; + } + } + } } - const texture = new THREE.DataTexture(data, size, size, THREE.RGBAFormat); + const texture = new THREE.DataTexture(data, texSize, texSize, THREE.RGBAFormat); texture.needsUpdate = true; texture.magFilter = THREE.NearestFilter; texture.minFilter = THREE.NearestFilter; @@ -225,7 +243,8 @@ controls.screenSpacePanning = false; controls.minDistance = 100; controls.maxDistance = 500; - controls.maxPolarAngle = Math.PI / 2 - 0.1; + // Allow full rotation to view base from below + controls.maxPolarAngle = Math.PI; controls.target.set(0, 50, 0); controls.update(); } @@ -291,26 +310,41 @@ const texture = faceTextures[faceId]; const size = FACE_SIZE; + const texSize = size * 4; - // Reset to default color - for (let i = 0; i < size * size; i++) { - texture.image.data[i * 4] = 34; - texture.image.data[i * 4 + 1] = 34; - texture.image.data[i * 4 + 2] = 34; - } - - // Apply pixel data - if (faceData) { - faceData.forEach((color, key) => { - const [x, y] = key.split(',').map(Number); - const idx = (y * size + x) * 4; - const rgb = hexToRgb(color); - if (rgb) { - texture.image.data[idx] = rgb.r; - texture.image.data[idx + 1] = rgb.g; - texture.image.data[idx + 2] = rgb.b; + // Reset with grid pattern + for (let py = 0; py < size; py++) { + for (let px = 0; px < size; px++) { + // Get pixel color + let r = 40, g = 40, b = 40; + if (faceData) { + const key = `${px},${py}`; + const color = faceData.get(key); + if (color) { + const rgb = hexToRgb(color); + if (rgb) { r = rgb.r; g = rgb.g; b = rgb.b; } + } } - }); + + // Draw 4x4 block with grid + for (let dy = 0; dy < 4; dy++) { + for (let dx = 0; dx < 4; dx++) { + const tx = px * 4 + dx; + const ty = py * 4 + dy; + const idx = (ty * texSize + tx) * 4; + + if (dx === 0 || dy === 0) { + texture.image.data[idx] = 20; + texture.image.data[idx + 1] = 20; + texture.image.data[idx + 2] = 20; + } else { + texture.image.data[idx] = r; + texture.image.data[idx + 1] = g; + texture.image.data[idx + 2] = b; + } + } + } + } } texture.needsUpdate = true; @@ -321,13 +355,21 @@ if (!faceTextures[faceId]) return; const texture = faceTextures[faceId]; - const idx = (y * FACE_SIZE + x) * 4; + const texSize = FACE_SIZE * 4; const rgb = hexToRgb(color); if (rgb) { - texture.image.data[idx] = rgb.r; - texture.image.data[idx + 1] = rgb.g; - texture.image.data[idx + 2] = rgb.b; + // Update 4x4 block (skip grid lines at dx=0, dy=0) + for (let dy = 1; dy < 4; dy++) { + for (let dx = 1; dx < 4; dx++) { + const tx = x * 4 + dx; + const ty = y * 4 + dy; + const idx = (ty * texSize + tx) * 4; + texture.image.data[idx] = rgb.r; + texture.image.data[idx + 1] = rgb.g; + texture.image.data[idx + 2] = rgb.b; + } + } texture.needsUpdate = true; } }