Files
gods-eye-view/src/ui/visualPresets.js
T
Said Turksever 3b6111be06 Open views naming the retired Snow style on Normal
createView threw on style 'snow', so an embed host or a
show_in_gods_eye_view call holding a view from before Snow was retired
was refused outright, camera and layers included. viewFromParams read
style=snow as the recipient's own style, while the app opened the same
link on Normal.

Both now read a retired style as Normal; truly unknown names still
throw. The retired list moves to a browser-free module shared by the
view API, the share codec and visual settings.
2026-10-29 11:34:19 +00:00

158 lines
5.7 KiB
JavaScript

import { retroShader } from '../styles/retro.js';
import { animeShader } from '../styles/anime.js';
import { noirShader } from '../styles/noir.js';
import { nightVisionShader } from '../styles/surveillance.js';
import { thermalShader } from '../styles/thermal.js';
import { BLOOM_INTENSITY_DEFAULT } from '../bloom.js';
import { msg } from '../i18n/marker.js';
/** Duration (ms) for shader intensity crossfade between style presets. */
export const TRANSITION_DURATION_MS = 500;
/** Map of style name to its GLSL shader module for post-process stages. */
export const STYLES = {
retro: retroShader,
surveillance: nightVisionShader,
thermal: thermalShader,
anime: animeShader,
noir: noirShader,
};
/**
* The tactical detection look: Dense at 75%.
*
* Owner playtest 2026-08-18: "detection mode… 75% weighted, with the 16% fade
* and 5% outside, whatever we had. I want that as the default. It should just
* happen." Fade and outside opacity live in GLOBAL_POST_DEFAULTS, so "whatever
* we had" still needs nothing here — but they are 7% and 1% now, the outside
* default having moved 5 → 3 → 1 as the owner locked final tuning after field trials (2026-08-24). What the quote asked for is the
* baseline of the day, not the two numbers it happened to name.
*
* ONE object, shared by the first-load baseline below, by every military style,
* AND by the Contacts context mode (which OWNS detection while active and
* restores the prior state on exit — see contactsDetectionPolicy.js). Cockpit
* deliberately does NOT touch detection: entering it with SPARSE selected leaves
* SPARSE. Declared ahead of GLOBAL_POST_DEFAULTS because that baseline now reads
* from it.
*/
export const MILITARY_DETECTION_PRESET = Object.freeze({
mode: 'dense',
densityPct: 75,
});
/** Baseline post-processing settings applied on first load (before share-link restore). */
export const GLOBAL_POST_DEFAULTS = {
bloom: { enabled: false, intensity: BLOOM_INTENSITY_DEFAULT },
sharpen: { enabled: true, intensity: 49 },
hudVariant: 'tactical',
hudVisible: true,
// Detection is ON for EVERY style on a first run, Normal included (owner
// directive 2026-08-22: "detect should also be on by default"). It is the
// same preset object the military styles and Contacts already apply, so there
// is one tactical look, not several that can drift.
//
// This is a first-LOAD baseline, not an override: `_applyGlobalPostDefaults`
// runs before any share-link restore, so a link's `dm`/`dd` still lands on top
// of it. It also deliberately leaves `_detectionUserOverridden` alone — the
// flag means the OPERATOR hand-edited detection, and a factory default is not
// that. Turning detection off by hand therefore still sets the flag and still
// suppresses the military-style auto-enable for the rest of the session.
detectionMode: MILITARY_DETECTION_PRESET.mode.toUpperCase(),
detectionDensity: MILITARY_DETECTION_PRESET.densityPct,
detectionAllocation: 'ELASTIC',
detectionFadePct: 7,
detectionOutsideOpacityPct: 1,
celestialRing: false,
};
// Tactical style defaults applied when users select military style presets.
export const STYLE_PRESET_DEFAULTS = {
retro: {
bloom: { enabled: false, intensity: BLOOM_INTENSITY_DEFAULT },
sharpen: { enabled: true, intensity: 49 },
styleParams: {
retro: {
pixelation: 1.0,
distortion: 0,
instability: 0.42,
},
},
hudVariant: 'tactical',
hudVisible: true,
detection: MILITARY_DETECTION_PRESET,
},
surveillance: {
bloom: { enabled: false, intensity: BLOOM_INTENSITY_DEFAULT },
sharpen: { enabled: true, intensity: 49 },
styleParams: {
surveillance: {
gain: 0.18,
bloom: 0.22,
scanlineStr: 0.96,
pixelation: 1.0,
},
},
hudVariant: 'tactical',
hudVisible: true,
detection: MILITARY_DETECTION_PRESET,
},
thermal: {
bloom: { enabled: false, intensity: BLOOM_INTENSITY_DEFAULT },
sharpen: { enabled: true, intensity: 49 },
styleParams: {
thermal: {
sensitivity: 0.85,
bloom: 0.2,
mode: 0.33,
pixelation: 1.0,
},
},
hudVariant: 'tactical',
hudVisible: true,
detection: MILITARY_DETECTION_PRESET,
},
};
/**
* GLSL fragment shader implementing an unsharp-mask sharpening filter.
* Samples a 3x3 neighborhood, computes box blur, then adds the
* difference (center - blur) scaled by `amount` for edge enhancement.
*/
export const SHARPEN_SHADER = /* glsl */ `
uniform sampler2D colorTexture;
uniform vec2 colorTextureDimensions;
uniform float amount;
in vec2 v_textureCoordinates;
void main() {
vec2 uv = v_textureCoordinates;
vec2 texel = 1.0 / colorTextureDimensions;
vec4 center = texture(colorTexture, uv);
vec4 blur = (
texture(colorTexture, uv + vec2(-texel.x, -texel.y)) +
texture(colorTexture, uv + vec2( 0.0, -texel.y)) +
texture(colorTexture, uv + vec2( texel.x, -texel.y)) +
texture(colorTexture, uv + vec2(-texel.x, 0.0)) +
center +
texture(colorTexture, uv + vec2( texel.x, 0.0)) +
texture(colorTexture, uv + vec2(-texel.x, texel.y)) +
texture(colorTexture, uv + vec2( 0.0, texel.y)) +
texture(colorTexture, uv + vec2( texel.x, texel.y))
) / 9.0;
vec4 sharpened = center + (center - blur) * amount;
out_FragColor = vec4(clamp(sharpened.rgb, 0.0, 1.0), center.a);
}
`;
/**
* Stable display labels for the active style and inherited Cockpit vision.
* English source text: render through t().
*/
export const STYLE_STATUS_LABELS = {
normal: msg('NORMAL'),
retro: msg('CRT'),
surveillance: msg('NVG'),
thermal: msg('FLIR'),
anime: msg('ANIME'),
noir: msg('NOIR'),
};