orbit/js/utils/Theme.js

37 lines
1.4 KiB
JavaScript

import { config } from '../config/Config.js';
import { toColor } from './Color.js';
/**
* Helpers for the shared visual theme (data/theme.json).
*
* The theme is the game's UI language — fonts, palette, and CRT/glitch
* tuning — so every scene reads from here instead of hardcoding looks:
*
* import { fontStack, themeColor } from '../utils/Theme.js';
* const titleStyle = { fontFamily: fontStack('header'), ... };
* const neon = themeColor('neon', 0x00e5ff);
*/
/**
* Canvas-ready CSS font stack for a theme font kind ('header' | 'body').
*
* fontStack('header') → "'Ethnocentric', 'Arial Black', 'Impact', sans-serif"
*
* Falls back to a plain system stack if the theme section is missing
* (e.g. a config that predates theme.json).
*/
export function fontStack(kind = 'body') {
const f = config.get(`theme.fonts.${kind}`);
if (f && typeof f.family === 'string' && f.family.length > 0) {
const family = /[^a-z0-9-]/i.test(f.family) ? `'${f.family}'` : f.family;
const fallbacks = Array.isArray(f.cssFallbacks) ? f.cssFallbacks : [];
return [family, ...fallbacks, 'sans-serif'].join(', ');
}
return "'Segoe UI', 'Helvetica Neue', Arial, sans-serif";
}
/** A theme palette color as an int: themeColor('neon', 0x00e5ff) */
export function themeColor(name, fallback = 0xffffff) {
return toColor(config.get(`theme.colors.${name}`, undefined), fallback);
}