Fix pyramid canvas: enable full rotation and add pixel grid
All checks were successful
Build and Push / build-all (push) Successful in 2m3s

- Remove maxPolarAngle limit to allow viewing base from below
- Add visible grid lines between pixels (4x4 texture per pixel)
- Update texture functions for new grid format

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
doomtube 2026-01-11 17:42:26 -05:00
parent aa96b78f48
commit 5ab1da2a1f

View file

@ -96,31 +96,49 @@
function createDataTexture(faceData) { function createDataTexture(faceData) {
const size = FACE_SIZE; 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) // Fill with grid pattern
for (let i = 0; i < size * size; i++) { for (let py = 0; py < size; py++) {
data[i * 4] = 34; // R for (let px = 0; px < size; px++) {
data[i * 4 + 1] = 34; // G // Get pixel color (default dark gray or from faceData)
data[i * 4 + 2] = 34; // B let r = 40, g = 40, b = 40;
data[i * 4 + 3] = 255; // A
}
// Apply pixel data from the face map
if (faceData) { if (faceData) {
faceData.forEach((color, key) => { const key = `${px},${py}`;
const [x, y] = key.split(',').map(Number); const color = faceData.get(key);
const idx = (y * size + x) * 4; if (color) {
const rgb = hexToRgb(color); const rgb = hexToRgb(color);
if (rgb) { if (rgb) { r = rgb.r; g = rgb.g; b = rgb.b; }
data[idx] = rgb.r;
data[idx + 1] = rgb.g;
data[idx + 2] = rgb.b;
} }
});
} }
const texture = new THREE.DataTexture(data, size, size, THREE.RGBAFormat); // 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, texSize, texSize, THREE.RGBAFormat);
texture.needsUpdate = true; texture.needsUpdate = true;
texture.magFilter = THREE.NearestFilter; texture.magFilter = THREE.NearestFilter;
texture.minFilter = THREE.NearestFilter; texture.minFilter = THREE.NearestFilter;
@ -225,7 +243,8 @@
controls.screenSpacePanning = false; controls.screenSpacePanning = false;
controls.minDistance = 100; controls.minDistance = 100;
controls.maxDistance = 500; 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.target.set(0, 50, 0);
controls.update(); controls.update();
} }
@ -291,26 +310,41 @@
const texture = faceTextures[faceId]; const texture = faceTextures[faceId];
const size = FACE_SIZE; const size = FACE_SIZE;
const texSize = size * 4;
// Reset to default color // Reset with grid pattern
for (let i = 0; i < size * size; i++) { for (let py = 0; py < size; py++) {
texture.image.data[i * 4] = 34; for (let px = 0; px < size; px++) {
texture.image.data[i * 4 + 1] = 34; // Get pixel color
texture.image.data[i * 4 + 2] = 34; let r = 40, g = 40, b = 40;
}
// Apply pixel data
if (faceData) { if (faceData) {
faceData.forEach((color, key) => { const key = `${px},${py}`;
const [x, y] = key.split(',').map(Number); const color = faceData.get(key);
const idx = (y * size + x) * 4; if (color) {
const rgb = hexToRgb(color); const rgb = hexToRgb(color);
if (rgb) { if (rgb) { r = rgb.r; g = rgb.g; b = rgb.b; }
texture.image.data[idx] = rgb.r; }
texture.image.data[idx + 1] = rgb.g; }
texture.image.data[idx + 2] = 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; texture.needsUpdate = true;
@ -321,13 +355,21 @@
if (!faceTextures[faceId]) return; if (!faceTextures[faceId]) return;
const texture = faceTextures[faceId]; const texture = faceTextures[faceId];
const idx = (y * FACE_SIZE + x) * 4; const texSize = FACE_SIZE * 4;
const rgb = hexToRgb(color); const rgb = hexToRgb(color);
if (rgb) { if (rgb) {
// 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] = rgb.r;
texture.image.data[idx + 1] = rgb.g; texture.image.data[idx + 1] = rgb.g;
texture.image.data[idx + 2] = rgb.b; texture.image.data[idx + 2] = rgb.b;
}
}
texture.needsUpdate = true; texture.needsUpdate = true;
} }
} }