orbit/data/shipScreen.json

375 lines
13 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 live fight's hull; full strength with no fight running).",
"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 (the class-selection flow lands with the class layer \u2014 a toast for now, never a dead click).",
"label": "CHOOSE YOUR CLASS",
"hint": "LEVEL {classAt} REACHED \u2014 THE CLASS LAYER AWAITS",
"toast": "CLASS SELECT OFFLINE \u2014 THE CLASS LAYER LANDS NEXT"
},
"classPlate": {
"_comment": "The class + insignia slot (data-driven seam: shipClass/insignia come from the save once class selection exists; until then the console shows the CHOOSE YOUR CLASS door).",
"label": "CLASS",
"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. 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",
"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). `baseline` is the profit reference with no shop under it: baseValue = the catalog value (data/goods.json), buy = this system's own buy price.",
"title": "BAY MANIFEST",
"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",
"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"
}
}
}