# Nitro Renderer nitro-renderer is a Javascript library for rendering Nitro in the browser using PixiJS ## Installation npm ``` npm install @nitrots/nitro-renderer ``` yarn ``` yarn add @nitrots/nitro-renderer ``` ## JSON / JSON5 configuration parser Every configuration file and gamedata file loaded by the renderer (figuredata, furnidata, productdata, effectmap, avatar actions, etc.) goes through `@nitrots/utils` → `JsonParser.ts`. The parser supports three modes, selected at the **host build time** through the compile-time constant `__NITRO_JSON_MODE__`: | Mode | Behaviour | |----------|---------------------------------------------------------------------------| | `legacy` | Strict `JSON.parse` only. Comments / trailing commas raise a clear error. | | `json5` | `JSON5.parse` only. Accepts comments, trailing commas, single quotes. | | `auto` | Try strict JSON first, fall back to JSON5. Default when the flag is unset.| URL hints are still honoured: files ending in `.json5` (or served with a `application/json5` content-type) always go through JSON5, regardless of mode. ### Wiring the flag into a host The renderer does **not** ship its own build for the flag — the host application (typically [Nitro V3](https://github.com/duckietm/Nitro-V3.git)) defines it via its bundler. Example with Vite: ```js // vite.config.mjs in the host export default defineConfig({ define: { __NITRO_JSON_MODE__: JSON.stringify('json5') // or 'legacy' / 'auto' } }); ``` If the constant is not defined the parser falls back to `auto`, which preserves the original behaviour of older releases — so existing hosts keep working without any change. ### Using the parser directly ```ts import { parseConfigJson, fetchConfigJson } from '@nitrots/utils'; const data = parseConfigJson(rawText, '/configuration/ui-config.json'); const data2 = await fetchConfigJson('/configuration/ui-config.json5'); ``` Errors carry the source URL and, in `legacy` mode, a hint about switching to JSON5 — making misconfigurations easy to diagnose in production logs. ## Split-aware gamedata loader `@nitrots/utils` also exports `loadGamedata`, the loader that backs every gamedata consumer in the renderer (FurnitureDataLoader, ProductDataLoader, EffectAssetDownloadManager, AvatarRenderManager, LocalizationManager). It accepts either a **single-file URL** (legacy) or a **directory URL** (split mode) — detected automatically by the trailing slash. ### Directory layout ``` / manifest.json5 # OPTIONAL — { "tiers": ["core", "custom", "seasonal"] } core/ manifest.json5 # REQUIRED — { "files": ["a.json5", "b.json5", ...] } a.json5 b.json5 custom/ # OPTIONAL tier manifest.json5 overrides.json5 seasonal/ # OPTIONAL tier manifest.json5 xmas.json5 ``` If the directory `manifest.json5` is absent, the loader falls back to the default tier order `core → custom → seasonal`. Each tier is skipped silently if its `manifest.json5` is missing. ### Merge semantics `mergeGamedata(a, b)` (also exported) implements the rules below; tiers and files within a tier are merged in order, with later layers overriding earlier ones: | Combination | Result | |------------------------------------------|----------------------------------------------| | Two plain objects | recursive merge, key by key | | Two arrays of objects sharing an id key | merged by id (later overrides earlier) | | Two arrays without an id key | concatenated | | Anything else | later value wins | Recognised id keys (in priority order): `id`, `classname`, `name`. Pass `mergeArrayIdKeys` in the options object to extend or override them. ### Programmatic usage ```ts import { loadGamedata, mergeGamedata } from '@nitrots/utils'; // host code never needs to care whether the URL is split or not const furnidata = await loadGamedata('https://example.com/gamedata/furnidata/'); // merge ad-hoc if you load tiers manually const merged = mergeGamedata(coreData, customData); ``` A CLI splitter for legacy single-file gamedata lives in the Nitro V3 client repo at `scripts/split-gamedata.mjs` — see the Nitro V3 README for usage.