Interactive WebGL Goldberg polyhedron viewer and painter with PBR shading, adjustable environment lighting, paint tools (pen, brush, circle, fill, line, pick), undo/redo, colour palettes, and mesh relaxation. Added to the standalone experiments index. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
81 lines
2.0 KiB
JavaScript
81 lines
2.0 KiB
JavaScript
import { desaturate } from './render_geo.mjs';
|
|
|
|
function t_from_ratio(ratio) {
|
|
return Math.min(Math.max((ratio - 1) / 0.4, 0), 1);
|
|
}
|
|
|
|
// Hue-wheel position (0-1) → RGB at full saturation and value.
|
|
function hue_to_rgb(h) {
|
|
const s = 6 * (h % 1);
|
|
const i = Math.floor(s);
|
|
const f = s - i;
|
|
const q = 1 - f;
|
|
if (i === 0) { return [1, f, 0]; }
|
|
if (i === 1) { return [q, 1, 0]; }
|
|
if (i === 2) { return [0, 1, f]; }
|
|
if (i === 3) { return [0, q, 1]; }
|
|
if (i === 4) { return [f, 0, 1]; }
|
|
return [1, 0, q];
|
|
}
|
|
|
|
export const PALETTES = [
|
|
{
|
|
id: 'classic',
|
|
name: 'Classic',
|
|
face_color(ratio, is_pentagon) {
|
|
if (is_pentagon) { return desaturate([1.0, 0.85, 0.23], 0.45); }
|
|
const t = t_from_ratio(ratio);
|
|
return desaturate([Math.min(1, 2*t), t < 0.5 ? t*1.4 : 0.7-(t-0.5)*1.4, Math.max(0, 1-2*t)], 0.45);
|
|
},
|
|
},
|
|
{
|
|
id: 'vibrant',
|
|
name: 'Vibrant',
|
|
face_color(ratio, is_pentagon) {
|
|
if (is_pentagon) { return [1.0, 0.82, 0.10]; }
|
|
const t = t_from_ratio(ratio);
|
|
return [Math.min(1, 2*t), t < 0.5 ? t*1.4 : 0.7-(t-0.5)*1.4, Math.max(0, 1-2*t)];
|
|
},
|
|
},
|
|
{
|
|
id: 'arctic',
|
|
name: 'Arctic',
|
|
// Low distortion = pale ice blue, high = deep indigo.
|
|
face_color(ratio, is_pentagon) {
|
|
if (is_pentagon) { return [0.95, 0.75, 0.20]; }
|
|
const t = t_from_ratio(ratio);
|
|
return desaturate([
|
|
0.55 - t * 0.45,
|
|
0.80 - t * 0.50,
|
|
1.0 - t * 0.15,
|
|
], 0.7 + t * 0.3);
|
|
},
|
|
},
|
|
{
|
|
id: 'ember',
|
|
name: 'Ember',
|
|
// Low distortion = dark red, high = bright yellow-white.
|
|
face_color(ratio, is_pentagon) {
|
|
if (is_pentagon) { return desaturate([0.25, 0.55, 0.85], 0.6); }
|
|
const t = t_from_ratio(ratio);
|
|
return [
|
|
0.35 + t * 0.65,
|
|
t * t * 0.85,
|
|
t * t * t * 0.25,
|
|
];
|
|
},
|
|
},
|
|
{
|
|
id: 'rainbow',
|
|
name: 'Rainbow',
|
|
// Full hue sweep: low distortion = blue (240°), high = red (0°).
|
|
face_color(ratio, is_pentagon) {
|
|
if (is_pentagon) { return [1.0, 1.0, 1.0]; }
|
|
const t = t_from_ratio(ratio);
|
|
return desaturate(hue_to_rgb(0.67 - t * 0.67), 0.85);
|
|
},
|
|
},
|
|
];
|
|
|
|
export const DEFAULT_PALETTE = PALETTES[0];
|