137 lines
3.8 KiB
JavaScript
137 lines
3.8 KiB
JavaScript
/**
|
||
* ResearchIcons — procedural tech glyphs for the tree nodes and the detail
|
||
* readout (128×128 canvas textures, neon stroke + soft glow, transparent
|
||
* background). Names come from each node's `icon` key; unknown names fall
|
||
* back to `diamond`. Tintable at use (Phaser tint multiplies).
|
||
*/
|
||
import { toColor } from '../utils/Color.js';
|
||
|
||
export const ICON_NAMES = ['tether', 'anchor', 'signal', 'diamond'];
|
||
|
||
export function iconKey(name, color = 0x00e5ff) {
|
||
const n = ICON_NAMES.includes(name) ? name : 'diamond';
|
||
const c = toColor(color);
|
||
return `__research_icon_${n}_${c.toString(16).padStart(6, '0')}`;
|
||
}
|
||
|
||
export function ensureIcon(scene, name, color = 0x00e5ff) {
|
||
const key = iconKey(name, color);
|
||
if (scene.textures.exists(key)) return key;
|
||
|
||
const S = 128;
|
||
const canvas = document.createElement('canvas');
|
||
canvas.width = S;
|
||
canvas.height = S;
|
||
const ctx = canvas.getContext('2d');
|
||
const hex = `#${toColor(color).toString(16).padStart(6, '0')}`;
|
||
const cx = S / 2;
|
||
const cy = S / 2;
|
||
|
||
ctx.clearRect(0, 0, S, S);
|
||
ctx.strokeStyle = hex;
|
||
ctx.fillStyle = hex;
|
||
ctx.shadowColor = hex;
|
||
ctx.shadowBlur = 9;
|
||
ctx.lineWidth = 5;
|
||
ctx.lineCap = 'round';
|
||
ctx.lineJoin = 'round';
|
||
|
||
const diamond = (x, y, r) => {
|
||
ctx.beginPath();
|
||
ctx.moveTo(x, y - r);
|
||
ctx.lineTo(x + r, y);
|
||
ctx.lineTo(x, y + r);
|
||
ctx.lineTo(x - r, y);
|
||
ctx.closePath();
|
||
ctx.fill();
|
||
};
|
||
|
||
const n = ICON_NAMES.includes(name) ? name : 'diamond';
|
||
if (n === 'tether') {
|
||
// Concentric tether rings + core + tick marks + a satellite on the mid ring.
|
||
const rings = [
|
||
[52, 0.5],
|
||
[38, 0.75],
|
||
[24, 1.0],
|
||
];
|
||
for (const [r, a] of rings) {
|
||
ctx.globalAlpha = a;
|
||
ctx.beginPath();
|
||
ctx.arc(cx, cy, r, 0, Math.PI * 2);
|
||
ctx.stroke();
|
||
}
|
||
ctx.globalAlpha = 1;
|
||
ctx.beginPath();
|
||
ctx.arc(cx, cy, 7, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
for (const a of [0, Math.PI / 2, Math.PI, (3 * Math.PI) / 2]) {
|
||
ctx.beginPath();
|
||
ctx.moveTo(cx + Math.cos(a) * 55, cy + Math.sin(a) * 55);
|
||
ctx.lineTo(cx + Math.cos(a) * 61, cy + Math.sin(a) * 61);
|
||
ctx.stroke();
|
||
}
|
||
diamond(cx + 38, cy, 8);
|
||
} else if (n === 'anchor') {
|
||
// Anchor ring + stock + crossbar + flukes (the relay bolted to a body).
|
||
ctx.globalAlpha = 0.9;
|
||
ctx.beginPath();
|
||
ctx.arc(cx, cy, 46, 0, Math.PI * 2);
|
||
ctx.stroke();
|
||
ctx.globalAlpha = 1;
|
||
ctx.beginPath();
|
||
ctx.moveTo(cx, cy - 24);
|
||
ctx.lineTo(cx, cy + 20);
|
||
ctx.stroke();
|
||
ctx.beginPath();
|
||
ctx.arc(cx, cy - 24, 7, 0, Math.PI * 2);
|
||
ctx.stroke();
|
||
ctx.beginPath();
|
||
ctx.moveTo(cx - 15, cy - 8);
|
||
ctx.lineTo(cx + 15, cy - 8);
|
||
ctx.stroke();
|
||
ctx.beginPath();
|
||
ctx.arc(cx, cy + 4, 20, Math.PI * 0.12, Math.PI * 0.88);
|
||
ctx.stroke();
|
||
diamond(cx - 19, cy + 15, 6);
|
||
diamond(cx + 19, cy + 15, 6);
|
||
} else if (n === 'signal') {
|
||
// Long-range array: source dot + rising arcs.
|
||
ctx.beginPath();
|
||
ctx.arc(cx, cy + 22, 7, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
const arcs = [
|
||
[19, 0.95],
|
||
[33, 0.7],
|
||
[47, 0.45],
|
||
];
|
||
for (const [r, a] of arcs) {
|
||
ctx.globalAlpha = a;
|
||
ctx.beginPath();
|
||
ctx.arc(cx, cy + 22, r, -Math.PI * 0.82, -Math.PI * 0.18);
|
||
ctx.stroke();
|
||
}
|
||
ctx.globalAlpha = 1;
|
||
} else {
|
||
// diamond — the default glyph
|
||
ctx.beginPath();
|
||
ctx.moveTo(cx, cy - 42);
|
||
ctx.lineTo(cx + 42, cy);
|
||
ctx.lineTo(cx, cy + 42);
|
||
ctx.lineTo(cx - 42, cy);
|
||
ctx.closePath();
|
||
ctx.stroke();
|
||
ctx.globalAlpha = 0.55;
|
||
ctx.beginPath();
|
||
ctx.moveTo(cx, cy - 22);
|
||
ctx.lineTo(cx + 22, cy);
|
||
ctx.lineTo(cx, cy + 22);
|
||
ctx.lineTo(cx - 22, cy);
|
||
ctx.closePath();
|
||
ctx.stroke();
|
||
ctx.globalAlpha = 1;
|
||
}
|
||
|
||
scene.textures.addCanvas(key, canvas);
|
||
return key;
|
||
}
|