402 lines
15 KiB
JSON
402 lines
15 KiB
JSON
{
|
|
"_comment": "SHIP CONSOLE \u2014 the command deck's SHIP button (js/ui/ShipWindow.js, depth 80, the MapWindow/QuestWindow idiom). LEFT = the bay camera (assets/videos/ship.mp4, a muted 2:3 loop; the clip is authored separately \u2014 a missing file leaves the NO SIGNAL plate up and the console still works). RIGHT = the tab row (Ship Status / Skill Tree / Cargo Holds \u2014 `standby: true` renders the socket dimmed with its standbyTag and a press fires the locked toast instead of switching) over the tab's plate. The Ship Status plate reads the ship's LIVE numbers through the `status.rows` table below: code owns behavior, this file owns labels, units, order, formatting and where each number comes from (`from` = a namespaced path \u2014 `config:<data path>`, `ship:<Ship field path>`, `live:<CombatSystem field>` read while a fight is running and off the maxima otherwise; `op: reciprocal` turns a cooldown into a rate). Ship Skill Tree stays OFFLINE until the class/skill layer lands; Cargo Holds lists the trade bays + the mineral aggregate, and a filled bay opens the good's scout summary (js/economy/TradeScout.js \u2014 the buy/sell screens' report).",
|
|
"enabled": true,
|
|
"title": "SHIP SYSTEMS",
|
|
"meta": "HULL & HARDWARE // LIVE TELEMETRY",
|
|
"video": {
|
|
"_comment": "The bay camera feed (same contract as map.video / quests.video): `file` is a clip under assets/videos/ (or a full relative path / URL). Muted, looping, 2:3 portrait. A missing file leaves the NO SIGNAL plate up.",
|
|
"file": "ship.mp4",
|
|
"aspect": [
|
|
2,
|
|
3
|
|
],
|
|
"tag": "BAY CAMERA // LIVE FEED",
|
|
"noSignalTag": "BAY CAMERA OFFLINE"
|
|
},
|
|
"tabs": [
|
|
{
|
|
"id": "status",
|
|
"label": "Ship Status",
|
|
"accent": "#7ce8a4"
|
|
},
|
|
{
|
|
"id": "skills",
|
|
"label": "Skill Tree",
|
|
"accent": "#ffc94d",
|
|
"standby": true,
|
|
"standbyTag": "OFFLINE"
|
|
},
|
|
{
|
|
"id": "cargo",
|
|
"label": "Cargo Holds",
|
|
"accent": "#00e5ff"
|
|
}
|
|
],
|
|
"skillsLockedToast": "SKILL TREE OFFLINE \u2014 NO CLASS ON FILE",
|
|
"skillsPanel": {
|
|
"_comment": "The OFFLINE tab's body (the final structure stays visible): the locked plate's headline + the copy that explains what lands there.",
|
|
"headline": "SKILL TREE OFFLINE",
|
|
"note": "COMBAT SKILLS ARM WHEN THE CLASS LAYER LANDS.\nCHOOSE A CLASS AT COMBAT LEVEL 5 \u2014 THE TREE GROWS FROM THERE."
|
|
},
|
|
"glitch": {
|
|
"_comment": "The console's glitch voice (the quests window's): intervalMs between bursts, durationMs the burst holds, slices RGB bands across the feed, maxOffset px of slide.",
|
|
"enabled": true,
|
|
"intervalMs": [
|
|
4200,
|
|
9200
|
|
],
|
|
"durationMs": [
|
|
110,
|
|
260
|
|
],
|
|
"slices": [
|
|
1,
|
|
4
|
|
],
|
|
"maxOffset": 9
|
|
},
|
|
"sweep": {
|
|
"_comment": "The scan band that crawls down the feed while the console is up.",
|
|
"enabled": true,
|
|
"intervalMs": [
|
|
5200,
|
|
9800
|
|
],
|
|
"durationMs": [
|
|
1400,
|
|
2200
|
|
]
|
|
},
|
|
"status": {
|
|
"_comment": "The SHIP STATUS tab. readout = the hardware table (order = draw order); level = the combat record + the level 0\u21925 journey.",
|
|
"hardwareTitle": "HARDWARE READOUT",
|
|
"groups": [
|
|
{
|
|
"id": "armor",
|
|
"label": "ARMOR"
|
|
},
|
|
{
|
|
"id": "flight",
|
|
"label": "FLIGHT"
|
|
},
|
|
{
|
|
"id": "guns",
|
|
"label": "GUNS"
|
|
},
|
|
{
|
|
"id": "hold",
|
|
"label": "HOLD"
|
|
}
|
|
],
|
|
"rows": [
|
|
{
|
|
"_comment": "HULL \u2014 the ship's max structure (data/ship.json \u2192 stats.hullIntegrity) with the live combat hull as the meter fill.",
|
|
"id": "hull",
|
|
"group": "armor",
|
|
"label": "HULL STRENGTH",
|
|
"from": "live:hullMax",
|
|
"unit": "HP",
|
|
"format": "int",
|
|
"meter": {
|
|
"of": "live:hull"
|
|
},
|
|
"accent": "#ff2d6f",
|
|
"note": "STRUCTURAL LIMIT",
|
|
"hotBelow": 0.34
|
|
},
|
|
{
|
|
"_comment": "CURRENT HULL \u2014 the armor actually on the ship right now (the combat ledger's hull; it persists between fights and reads full once a landing or jump-arrival repairs it).",
|
|
"id": "hullNow",
|
|
"group": "armor",
|
|
"label": "CURRENT HULL",
|
|
"from": "live:hull",
|
|
"unit": "HP",
|
|
"format": "int",
|
|
"meter": {
|
|
"_comment": "The bar is the SAME armor meter as HULL STRENGTH (current over max) \u2014 written as an explicit pair because this row's own value is the numerator.",
|
|
"fill": "live:hull",
|
|
"max": "live:hullMax"
|
|
},
|
|
"accent": "#ff7ba0",
|
|
"nominalLabel": "NOMINAL",
|
|
"hotBelow": 0.34
|
|
},
|
|
{
|
|
"id": "shields",
|
|
"group": "armor",
|
|
"label": "SHIELDS",
|
|
"from": "live:shieldsMax",
|
|
"unit": "HP",
|
|
"format": "int",
|
|
"accent": "#00e5ff",
|
|
"hotBelow": 0.34
|
|
},
|
|
{
|
|
"_comment": "SHIELD LEVEL \u2014 the live shield bar (recharges after shieldRegenDelay s without a hit at shieldRegenRate/s).",
|
|
"id": "shieldNow",
|
|
"group": "armor",
|
|
"label": "SHIELD LEVEL",
|
|
"from": "live:shields",
|
|
"unit": "HP",
|
|
"format": "int",
|
|
"meter": {
|
|
"_comment": "Same meter as SHIELDS (current over max).",
|
|
"fill": "live:shields",
|
|
"max": "live:shieldsMax"
|
|
},
|
|
"accent": "#78b4ff",
|
|
"nominalLabel": "FULL",
|
|
"hotBelow": 0.34
|
|
},
|
|
{
|
|
"id": "shieldRegen",
|
|
"group": "armor",
|
|
"label": "SHIELD RECHARGE",
|
|
"from": "config:combat.playerShip.shieldRegenRate",
|
|
"unit": "/s",
|
|
"format": "int",
|
|
"accent": "#00e5ff",
|
|
"meta": {
|
|
"_comment": "The recharge's dead time after a hit (data/combat.json \u2192 playerShip.shieldRegenDelay), drawn as the row's meta line.",
|
|
"label": "ARM AFTER",
|
|
"from": "config:combat.playerShip.shieldRegenDelay",
|
|
"unit": "s",
|
|
"format": "int"
|
|
}
|
|
},
|
|
{
|
|
"id": "accel",
|
|
"group": "flight",
|
|
"label": "ACCELERATION",
|
|
"from": "config:ship.thrust",
|
|
"unit": "px/s\u00b2",
|
|
"format": "int",
|
|
"accent": "#7ce8a4"
|
|
},
|
|
{
|
|
"id": "maxSpeed",
|
|
"group": "flight",
|
|
"label": "MAX VELOCITY",
|
|
"from": "config:ship.maxSpeed",
|
|
"unit": "px/s",
|
|
"format": "int",
|
|
"accent": "#7ce8a4"
|
|
},
|
|
{
|
|
"id": "turn",
|
|
"group": "flight",
|
|
"label": "TURN RATE",
|
|
"from": "config:ship.rotSpeed",
|
|
"unit": "rad/s",
|
|
"format": "1dp",
|
|
"accent": "#7ce8a4"
|
|
},
|
|
{
|
|
"_comment": "FIRE RATE \u2014 the cannon's shots per second (the reciprocal of data/combat.json \u2192 player.weapon.cooldown).",
|
|
"id": "fireRate",
|
|
"group": "guns",
|
|
"label": "FIRE RATE",
|
|
"from": "config:combat.player.weapon.cooldown",
|
|
"op": "reciprocal",
|
|
"unit": "/s",
|
|
"format": "2dp",
|
|
"accent": "#ffc94d"
|
|
},
|
|
{
|
|
"id": "damage",
|
|
"group": "guns",
|
|
"label": "DAMAGE",
|
|
"from": "config:combat.player.weapon.damage",
|
|
"unit": "/hit",
|
|
"format": "int",
|
|
"accent": "#ffc94d"
|
|
},
|
|
{
|
|
"_comment": "DPS \u2014 damage \u00d7 fire rate (the row's meta read, not a stored number).",
|
|
"id": "dps",
|
|
"group": "guns",
|
|
"label": "DPS",
|
|
"from": [
|
|
{
|
|
"from": "config:combat.player.weapon.damage"
|
|
},
|
|
{
|
|
"from": "config:combat.player.weapon.cooldown",
|
|
"op": "reciprocal"
|
|
}
|
|
],
|
|
"op": "product",
|
|
"unit": "/s",
|
|
"format": "1dp",
|
|
"accent": "#ffd84d",
|
|
"meta": {
|
|
"label": "SHOT SPEED",
|
|
"from": "config:combat.player.weapon.bulletSpeed",
|
|
"unit": "px/s",
|
|
"format": "int"
|
|
}
|
|
},
|
|
{
|
|
"id": "cargoBays",
|
|
"group": "hold",
|
|
"label": "CARGO BAYS",
|
|
"from": "ship:stats.cargoHold",
|
|
"unit": "bays",
|
|
"format": "int",
|
|
"meter": {
|
|
"of": "ship:cargo.used"
|
|
},
|
|
"accent": "#00e5ff",
|
|
"meta": {
|
|
"label": "GRID",
|
|
"from": "config:economy.cargo.maxSlots",
|
|
"unit": "SLOTS",
|
|
"format": "int"
|
|
}
|
|
},
|
|
{
|
|
"id": "mineralHold",
|
|
"group": "hold",
|
|
"label": "MINERAL STORAGE",
|
|
"from": "ship:stats.mineralStorage",
|
|
"unit": "u",
|
|
"format": "int",
|
|
"meter": {
|
|
"of": "ship:minerals"
|
|
},
|
|
"accent": "#78b4ff"
|
|
},
|
|
{
|
|
"id": "miningSpeed",
|
|
"group": "hold",
|
|
"label": "MINING RATE",
|
|
"from": "ship:stats.miningSpeed",
|
|
"unit": "\u00d7 base",
|
|
"format": "2dp",
|
|
"accent": "#a8ffc4"
|
|
}
|
|
],
|
|
"creditsLabel": "CREDITS",
|
|
"noCombatNote": "DRIVE DARK \u2014 NO CONTACTS"
|
|
},
|
|
"level": {
|
|
"_comment": "The combat record (js/combat/XpManager.js \u2014 the curve is data/progression.json). The journey plate shows levels `from`\u2026`to` as a timeline of milestone nodes with the XP fill between them; at `classAt` (and above) the timeline gives way to CHOOSE YOUR CLASS, and once a class is on file (playerClass.name) it shows the class + insignia instead. Every string lives here.",
|
|
"title": "COMBAT RECORD",
|
|
"levelWord": "LEVEL",
|
|
"xpLabel": "XP",
|
|
"nextLabel": "NEXT LV",
|
|
"maxLabel": "MAX LEVEL",
|
|
"journeyTitle": "THE JOURNEY // LV {from}\u2013{to}",
|
|
"from": 0,
|
|
"to": 5,
|
|
"classAt": 5,
|
|
"milestones": [
|
|
{
|
|
"level": 0,
|
|
"label": "SADDLE",
|
|
"note": "FIRST SEAT"
|
|
},
|
|
{
|
|
"level": 1,
|
|
"label": "SOLO",
|
|
"note": "FIRST KILL"
|
|
},
|
|
{
|
|
"level": 2,
|
|
"label": "SCUFFED",
|
|
"note": "HULL HOLDING"
|
|
},
|
|
{
|
|
"level": 3,
|
|
"label": "HUNTED",
|
|
"note": "ON THE BOARD"
|
|
},
|
|
{
|
|
"level": 4,
|
|
"label": "VETERAN",
|
|
"note": "GUNS HOT"
|
|
},
|
|
{
|
|
"level": 5,
|
|
"label": "CHOSEN",
|
|
"note": "PICK A CLASS"
|
|
}
|
|
],
|
|
"chooseClass": {
|
|
"_comment": "The level-5 door: the timeline's replacement. The press fires the scene's onChooseClass seam, which opens the SELECT YOUR CLASS console (js/ui/ClassWindow.js) over the parked world \u2014 a DEFERRED pick re-opens here, so this door is the run's second way in. `toast` is only the fallback voice when the class layer is switched off (data/classes.json \u2192 enabled: false).",
|
|
"label": "CHOOSE YOUR CLASS",
|
|
"hint": "LEVEL {classAt} REACHED \u2014 THE CLASS LAYER AWAITS",
|
|
"toast": "CLASS SELECT OFFLINE \u2014 THE CLASS LAYER IS SWITCHED OFF"
|
|
},
|
|
"classPlate": {
|
|
"_comment": "A class is on file: the console shows its name + insignia (a FRAME INDEX off assets/images/classes.png, drawn in the class's own accent) instead of the door. `insigniaFrame` is the fallback when the save carries no class id; `skillPointsLine` is the banked-point readout (js/player/ClassState.js \u2014 the tree that spends them is the next layer).",
|
|
"label": "CLASS",
|
|
"insigniaFrame": 0,
|
|
"skillPointsLine": "+{n} SKILL POINTS BANKED",
|
|
"noneLabel": "NO CLASS ON FILE"
|
|
}
|
|
},
|
|
"cargo": {
|
|
"_comment": "The CARGO HOLDS tab. The hold is trade goods only \u2014 one good per bay, in fill order (js/economy/CargoHold.js); locked bays are the hold's upgrade room. Each bay also carries the PURCHASE COST the player actually paid for it (recorded in CargoHold when the shop trade lands; null where no cost is on file \u2014 the quest package's handoff): the hold meta prints the load's total cost, each bay tile its own, and the bay manifest prices its exits against it. MINERALS is the aggregate aboard vs capacity (the Mineral HUD's numbers \u2014 js/entities/Ship.js). A filled bay is tappable: it opens the good's summary + best exits (data below \u2192 detail).",
|
|
"holdTitle": "TRADE BAYS",
|
|
"holdMeta": "{used} / {capacity} BAYS \u00b7 {room} FREE",
|
|
"costMeta": " \u00b7 {cost} CR PAID",
|
|
"unknownCost": "NO COST",
|
|
"emptyNote": "HOLD EMPTY \u2014 EVERY BAY IS CLEAN",
|
|
"noBaysNote": "NO CARGO BAYS INSTALLED \u2014 UPGRADE THE HOLD",
|
|
"lockedTag": "LOCKED",
|
|
"manifestTag": "MANIFEST \u25b8",
|
|
"lockedRoomMeta": "+{locked} LOCKED BAYS \u00b7 UPGRADE THE HOLD AT HARGUN ({slots} TOTAL)",
|
|
"mineralsTitle": "MINERAL HOLDS",
|
|
"mineralsMeta": "{minerals} / {capacity} u",
|
|
"emptyMineralsNote": "NO ORE ABOARD",
|
|
"creditsLabel": "CREDITS",
|
|
"detail": {
|
|
"_comment": "The selected good's summary (the shop scout's report \u2014 js/economy/TradeScout.js scoutGood). THE PROFIT BASELINE: the bay's own PURCHASE COST when it is on file (the credits/unit the player actually paid \u2014 recorded in js/economy/CargoHold.js at the moment of purchase; paidLabel + costLine say so on the plate). A bay with no cost on file (the quest package's handoff, a save predating the record) falls back to `baseline`: baseValue = the catalog value (data/goods.json), buy = this system's own buy price \u2014 baselineLine says which.",
|
|
"title": "BAY MANIFEST",
|
|
"paidLabel": "PAID",
|
|
"costLine": "PAID {cost} CR/UNIT \u2014 EXITS ARE PRICED AGAINST THAT PURCHASE",
|
|
"baselineLine": "REF {ref} CR \u00b7 LOCAL BUY {buy}",
|
|
"categoryLabel": "CLASS",
|
|
"tierLabel": "T",
|
|
"valueLabel": "BASE VALUE",
|
|
"originLabel": "MADE IN",
|
|
"hubLabel": "HUB POOL",
|
|
"producerLabel": "MADE OF",
|
|
"demandLabel": "SOUGHT ON",
|
|
"exitsTitle": "BEST EXITS",
|
|
"exitsEmpty": "NO CHARTED EXIT YET \u2014 EVERY CAPITAL BUYS EVERYTHING",
|
|
"exitMeta": "{hops} HOPS",
|
|
"hereTag": "HERE",
|
|
"exitCue": "TAP TO SET DESTINATION",
|
|
"exitHint": "TAP AN EXIT TO SET IT AS YOUR DESTINATION",
|
|
"exitHover": {
|
|
"_comment": "the row's hover state (the tap surface lights up: the plate fill, its neon edge + glow)",
|
|
"fill": "#0c2740",
|
|
"fillAlpha": 0.85
|
|
},
|
|
"setDestination": {
|
|
"_comment": "The BEST-EXIT confirm (js/ui/ConfirmOverlay.js, hosted by the console so it always paints above it) \u2014 the same SET DESTINATION dialog the planet shop's scout and the map's SYSTEM tab use. {object}/{system} name the exit's WORLD and its system, {class} its economic class, {price} the CR/unit it pays, {sign}{profit} the per-unit margin against `baseline`, {hops} the jump distance. line2NoHops is the row without a charted hop count.",
|
|
"title": "SET DESTINATION",
|
|
"confirmLabel": "SET DESTINATION",
|
|
"cancelLabel": "CANCEL",
|
|
"accent": "#00e5ff",
|
|
"width": 520,
|
|
"height": 176,
|
|
"line1": "DESTINATION \u2014 {object} \u00b7 {system}",
|
|
"line2": "{class}SELLS {price} CR/UNIT \u00b7 {sign}{profit}/UNIT \u00b7 {hops} HOPS",
|
|
"line2NoHops": "{class}SELLS {price} CR/UNIT \u00b7 {sign}{profit}/UNIT"
|
|
},
|
|
"profitBar": {
|
|
"_comment": "the per-unit margin rail under each exit row \u2014 scaled against the list's best row, so goods of different value compare the same way",
|
|
"track": "#14324f",
|
|
"fill": "#7ce8a4",
|
|
"fillNeg": "#ff5a6e"
|
|
},
|
|
"baseline": "baseValue",
|
|
"topN": 3,
|
|
"backLabel": "BACK TO BAYS"
|
|
}
|
|
}
|
|
}
|