mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
Snow is no longer offered anywhere a style can be chosen: the Visual Presets tray, keyboard shortcut 7, the Cockpit vision carousel, and the set_visual_style voice action. The shader and its labels go with it; weather snowfall and the SNOW weather condition are unaffected. Share links keep working. Snow's enum code (6) stays reserved, so a compact or long-form link that names it opens on Normal and drops the Snow shader parameters without reporting them as unknown. A Scene Director shot saved with Snow plays on Normal too. Snow's frozen share defaults matched Normal's apart from those parameters, so no other setting in an old link changes meaning. The legacy voice-schema pins restore Snow before hashing, so the unchanged pins still prove nothing else moved; the complete Realtime payload digest is re-derived.
121 lines
4.8 KiB
JavaScript
121 lines
4.8 KiB
JavaScript
import { test } from 'node:test';
|
||
import assert from 'node:assert/strict';
|
||
import {
|
||
trafficStyleProfile,
|
||
presetDotRgba,
|
||
presetSizeDelta,
|
||
presetDotOutline,
|
||
trafficBucketTier,
|
||
} from './trafficPresetStyle.js';
|
||
|
||
/** Rec.601 luma of an rgba tuple (rgb 0–255), normalized 0–1. */
|
||
const luma = ([r, g, b]) => (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
||
|
||
const BUCKETS = ['free', 'slow', 'jam'];
|
||
const MONO_STYLES = ['surveillance', 'thermal', 'noir'];
|
||
const NORMAL_STYLES = ['normal', 'anime', 'does-not-exist', '', undefined, null];
|
||
|
||
test('profile mapping: NVG/FLIR/noir are mono, retro is crt, everything else normal', () => {
|
||
for (const s of MONO_STYLES) assert.equal(trafficStyleProfile(s), 'mono', s);
|
||
assert.equal(trafficStyleProfile('retro'), 'crt');
|
||
for (const s of NORMAL_STYLES) assert.equal(trafficStyleProfile(s), 'normal', String(s));
|
||
});
|
||
|
||
test('normal-profile styles never restyle: null rgba, zero size delta', () => {
|
||
for (const s of NORMAL_STYLES) {
|
||
for (const b of BUCKETS) {
|
||
assert.equal(presetDotRgba(s, b), null, `${s}/${b}`);
|
||
assert.equal(presetSizeDelta(s, b), 0, `${s}/${b}`);
|
||
}
|
||
}
|
||
});
|
||
|
||
test('sim/uncovered dots (null bucket) are untouched under EVERY style — keyless path stays byte-identical', () => {
|
||
for (const s of [...MONO_STYLES, 'retro', ...NORMAL_STYLES]) {
|
||
assert.equal(presetDotRgba(s, null), null, String(s));
|
||
assert.equal(presetDotRgba(s, undefined), null, String(s));
|
||
assert.equal(presetDotRgba(s, 'sim'), null, String(s));
|
||
assert.equal(presetSizeDelta(s, null), 0, String(s));
|
||
}
|
||
});
|
||
|
||
test('mono: EVERY colored dot is a bright white core (owner round 2: "just bright dots")', () => {
|
||
for (const s of MONO_STYLES) {
|
||
for (const b of BUCKETS) {
|
||
const rgba = presetDotRgba(s, b);
|
||
assert.ok(rgba, `${s}/${b} returns a tuple`);
|
||
assert.ok(luma(rgba) >= 0.95, `${s}/${b} is near-white (luma ${luma(rgba).toFixed(2)})`);
|
||
assert.ok(rgba[3] >= 0.8, `${s}/${b} stays opaque enough to read (alpha ${rgba[3]})`);
|
||
}
|
||
}
|
||
});
|
||
|
||
test('mono: jam is the biggest, sizes monotonic (queues read as fat beads)', () => {
|
||
for (const s of MONO_STYLES) {
|
||
assert.ok(presetSizeDelta(s, 'jam') >= 2, `${s} jam +2px or more`);
|
||
assert.ok(presetSizeDelta(s, 'jam') > presetSizeDelta(s, 'slow'), s);
|
||
assert.ok(presetSizeDelta(s, 'slow') >= presetSizeDelta(s, 'free'), s);
|
||
}
|
||
});
|
||
|
||
test('crt palette: saturated hues that survive posterization, all buckets upsized, no pulse', () => {
|
||
for (const b of BUCKETS) {
|
||
const rgba = presetDotRgba('retro', b);
|
||
assert.ok(rgba, `retro/${b}`);
|
||
const [r, g, bl] = rgba;
|
||
const sat = (Math.max(r, g, bl) - Math.min(r, g, bl)) / 255;
|
||
assert.ok(sat >= 0.5, `retro/${b} saturation ${sat.toFixed(2)} ≥ 0.5`);
|
||
assert.ok(presetSizeDelta('retro', b) >= 1, `retro/${b} at least +1px vs pixel grid`);
|
||
}
|
||
assert.ok(presetSizeDelta('retro', 'jam') > presetSizeDelta('retro', 'free'), 'jam still dominant');
|
||
});
|
||
|
||
test('outlines: mono buckets ALL get a dark halo (bright core + dark ring is the readable unit)', () => {
|
||
for (const s of MONO_STYLES) {
|
||
for (const b of BUCKETS) {
|
||
const o = presetDotOutline(s, b);
|
||
assert.ok(o && o.width >= 1, `${s}/${b} has an outline`);
|
||
assert.ok(luma(o.rgba) <= 0.2, `${s}/${b} outline is dark (luma ${luma(o.rgba).toFixed(2)})`);
|
||
}
|
||
assert.ok(presetDotOutline(s, 'jam').width >= presetDotOutline(s, 'slow').width,
|
||
`${s} jam outline at least as wide as slow`);
|
||
}
|
||
for (const b of ['jam', 'slow']) {
|
||
assert.ok(presetDotOutline('retro', b)?.width >= 1, `retro/${b} outlined`);
|
||
}
|
||
});
|
||
|
||
test('trafficBucketTier: flow buckets map to veh_* tiers, sim to veh_nodata, keyless (null) to null', () => {
|
||
assert.equal(trafficBucketTier('jam'), 'veh_jam');
|
||
assert.equal(trafficBucketTier('slow'), 'veh_slow');
|
||
assert.equal(trafficBucketTier('free'), 'veh_free');
|
||
assert.equal(trafficBucketTier('sim'), 'veh_nodata');
|
||
assert.equal(trafficBucketTier(null), null);
|
||
assert.equal(trafficBucketTier(undefined), null);
|
||
assert.equal(trafficBucketTier('garbage'), null);
|
||
});
|
||
|
||
test('outlines: never under the normal profile, never for sim dots', () => {
|
||
for (const s of NORMAL_STYLES) {
|
||
for (const b of [...BUCKETS, 'sim', null]) {
|
||
assert.equal(presetDotOutline(s, b), null, `${String(s)}/${String(b)}`);
|
||
}
|
||
}
|
||
for (const s of [...MONO_STYLES, 'retro']) {
|
||
assert.equal(presetDotOutline(s, null), null, String(s));
|
||
assert.equal(presetDotOutline(s, 'sim'), null, String(s));
|
||
}
|
||
});
|
||
|
||
test('all styled tuples are valid rgba: channels 0–255 ints, alpha in (0, 1]', () => {
|
||
for (const s of [...MONO_STYLES, 'retro']) {
|
||
for (const b of BUCKETS) {
|
||
const [r, g, bl, a] = presetDotRgba(s, b);
|
||
for (const c of [r, g, bl]) {
|
||
assert.ok(Number.isInteger(c) && c >= 0 && c <= 255, `${s}/${b} channel ${c}`);
|
||
}
|
||
assert.ok(a > 0 && a <= 1, `${s}/${b} alpha ${a}`);
|
||
}
|
||
}
|
||
});
|