clone

an offline map explorer where each world, from a game map to a city's open data, ships as one .atlas file

feat/atlas-next-horizon
atlas / analysis / cellsystems / tokens.ts
tokens.ts 2.8K
1// The grid's one visual vocabulary, as pure tokens.2//3// Issue #5 §5.4: outputs are renderer-neutral artifacts — plans and pure style4// tokens. These numbers live in the analysis lane because both projections5// must render from the same ones or they drift apart: line weight encodes the6// hierarchy the way an MGRS grid weighs its own, the chosen path draws white7// over per-cell palette accents, and the label is a small chip spelling the8// address with its prefix faint and its final character bright.9//10// Nothing here is a colour a renderer chose. The chart adapts these into11// ol/style and the globe into materials and sprites; neither holds a width or12// a colour of its own.1314/**15 * The accent wheel. Grid cells, zones, and categories without an archive16 * colour draw from it: mid-tone hues anchored on the identity's cerulean and17 * earths, bright enough to read over world tiles and muted enough not to shout18 * over the neutral chrome.19 */20export const palette: readonly string[] = [21 "#4fb3d5", "#c9924b", "#82b56a", "#c96a6a", "#9581cc",22 "#4bc9a9", "#d4b04a", "#6a92c9", "#b08a5a", "#8fb3a2",23];2425/** The role a cell plays in one plan. */26export type CellRole = "neighbor" | "scope" | "child" | "leaf";2728/** Every weight, alpha and chip the grid draws with. */29export interface GridTheme {30 readonly labelSizePx: number;31 readonly neighborLabelSizePx: number;32 readonly labelInsetPx: number;33 readonly labelFont: string;34 readonly prefixAlpha: number;35 readonly chip: string;36 readonly neighborChip: string;37 readonly lineWhite: string;38 readonly widths: Readonly<Record<CellRole | "scopeBare", number>>;39 readonly childLineAlpha: number;40 readonly neighborLineAlpha: number;41 readonly leafFillAlpha: number;42 readonly childFillAlpha: number;43 readonly neighborTextAlpha: number;44 readonly dimColor: string;45 readonly dimBase: number;46 readonly dimStep: number;47 readonly dimCap: number;48}4950export const gridTheme: GridTheme = {51 labelSizePx: 11,52 neighborLabelSizePx: 10,53 labelInsetPx: 5,54 labelFont: "ui-monospace, SFMono-Regular, Menlo, monospace",55 prefixAlpha: 0.55,56 chip: "rgba(12, 15, 22, 0.76)",57 neighborChip: "rgba(8, 11, 18, 0.88)",58 lineWhite: "#ffffff",59 widths: { leaf: 2.5, scope: 2.5, scopeBare: 1.8, child: 1.4, neighbor: 1 },60 childLineAlpha: 0.82,61 neighborLineAlpha: 0.44,62 leafFillAlpha: 0.14,63 childFillAlpha: 0.055,64 neighborTextAlpha: 0.72,65 dimColor: "#050810",66 dimBase: 0.3,67 dimStep: 0.06,68 dimCap: 0.52,69};7071/** The accent a cell wears everywhere it is drawn. */72export function paletteColor(index: number): string {73 const color = palette[((index % palette.length) + palette.length) % palette.length];74 // The wheel is a non-empty constant, so this is unreachable; the fallback75 // exists because `noUncheckedIndexedAccess` is right to insist.76 return color ?? gridTheme.lineWhite;77}