orbit/data/vignettes.json

112 lines
9.4 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"$comment": "VIGNETTES — dialogue scenes played ON A PLANET (SurfaceScene), triggered by the world's location buttons: the EXPLORE drawer's service points (the neutral capital's Bar) and the SHOP (deck slot). A vignette is a sequence of LINES — each with a speaker (a character), text, and a speech clip — played in a window centered on the screen (js/ui/VignetteWindow.js) OVER the location's looping clip, which keeps playing in the background. NEXT advances the lines; the LAST line's button (DONE) closes the window and returns to the looping clip alone. Vignettes are GATED BY QUEST STEPS: each entry names the quest that holds it + the index of the step it is — it is available while that quest is granted, unclaimed, and the step still open (js/vignettes/VignetteModel.js → vignetteAvailable, the scene builds the gate's facts from the sleeping GameScene). Finishing it is the step's WITNESS (GameScene._questCheckEval's 'vignettePlayed' check reads the run's played ledger — the same shape as the comms' trestleTalked/trestleMet witnesses). A speaker's face is the PLANET cut of their clip — assets/videos/characters/planet-<id>.mp4 (the comms' space cut is <id>.mp4) — and is ALWAYS played muted (the voice is the line's speech clip, never the video). Assets (the character clip + each line's speech) load ON DEMAND by the hub (js/vignettes/VignetteHub.js) when a vignette is armed — never in a scene's preload, so the initial load stays lean. The played ledger marks when the scene COMPLETES (the opposite of comms' mark-on-start): a conversation is a place you can return to — leave mid-scene and it re-arms on the next visit to the location.",
"enabled": true,
"audio": {
"$comment": "A line's voice plays at its OWN volume (volume) — the manager's master is left untouched (in v4 `sound.setVolume` IS the master, so ducking it would quiet the voice too). While a voice talks, the other playing sounds (the surface hum) are ducked PER-SOUND by musicDuck (a fraction of each one's own volume) and restored exactly when the voice ends — the comms' recipe (data/comms.json → audio).",
"volume": 1.0,
"musicDuck": 0.3
},
"characters": {
"$comment": "The speakers. label = the window's header; role = the small line beside it. `video` is optional: the speaker's PLANET clip (the window's left panel), defaulting to assets/videos/characters/planet-<id>.mp4 — the planet cut of the comms' space cut (planet-trestle.mp4 vs trestle.mp4, assets/videos/characters/).",
"trestle": {
"label": "TRESTLE",
"role": "OUT-OF-SYSTEM MENTOR"
},
"carol": {
"label": "CAROL",
"role": "COURIER"
}
},
"vignettes": [
{
"id": "special_delivery_bar_meeting",
"location": "bar",
"quest": "special_delivery",
"step": 0,
"$comment": "'Special Delivery' step 1 — the neutral capital's bar: Trestle's welcome (trestle-q3-01) + Carol's four beats (carol-q3-01..04). It plays when the quest is held and the bar is entered on the capital. COMPLETING it (the DONE press) runs the scene's story beats (GameScene.onVignetteComplete): the ship's hold is built out FIRST (effects.cargoHold — the run's ship starts with cargoHold 0, data/ship.json) and THEN the 'special-package' joins the hold — Carol's 'I've asked some of my men to build out 4 cargo bays' / 'the cargo I need transported has been loaded' lines are the truth the moment the scene ENDS; and — while the quest is HELD (granted, unclaimed) — the HOME WORLD becomes the destination (the delivery's route — Carol's 'just bring this package back to the merchant on your home world' line is the trigger, and the compass points home for the flight back; the beat is gated on the quest's holding, so once the quest ends a bar visit never re-aims the destination). The completion also marks the step: the quest's check is 'vignettePlayed' (check.id = this id) and reads the run's played ledger (registry 'vignettesPlayed' — VignetteHub marks it on completion, SaveData persists it); the 'cargoUpgraded' step stands done with the package aboard (its witness — check.id 'special-package').",
"effects": {
"$comment": "The story beat the DONE press runs (GameScene.onVignetteComplete — BEFORE the quest's package handoff, the hold must fit the package): cargoHold = the ship's unlocked cargo bays, MAX-wins (never a downgrade — the run's ship starts at 0, data/ship.json). The scene's lines are the truth: Carol's crew built out the bays.",
"cargoHold": 4
},
"lines": [
{
"from": "trestle",
"text": "Hey Kid. Thanks for meeting us here. Meet Carol, she's part of a team that.. well, let's discuss that later. Right now Carol has a package that needs delivering, and you need training on how to trade cargo.",
"audio": "assets/speech/trestle/trestle-q3-01.mp3"
},
{
"from": "carol",
"text": "It's nice to meet you. Trestle speaks highly of you. He thinks you might be able to help me with a delivery I need to make.",
"audio": "assets/speech/carol/carol-q3-01.mp3"
},
{
"from": "carol",
"text": "That ship of yours is.. well, lets say there is room for improvement. I hope you don't mind, I've asked some of my men to build out 4 cargo bays inside of it. That should give us what we need to get you transporting.",
"audio": "assets/speech/carol/carol-q3-02.mp3"
},
{
"from": "carol",
"text": "I've also seen to it that the cargo I need transported has been loaded. This should be a quick job for you. I can't go back to your home star system, for reasons I can't devuldge, but just bring this package back to the merchant on your home world and sell it to him.",
"audio": "assets/speech/carol/carol-q3-03.mp3"
},
{
"from": "carol",
"text": "After you've done that, launch back into space and I'll contact you. Get this job done and there might be a future for you in this galaxy afterall. We'll talk more later.",
"audio": "assets/speech/carol/carol-q3-04.mp3"
}
]
}
],
"$vignettes_comment": "The playable scenes — each one: `id` (the played ledger's key + the quest's 'vignettePlayed' witness), `location` (the world slot that triggers it — 'bar' the neutral capital's BAR service, 'shop' the SHOP deck slot; case-insensitive), `quest` + `step` (the gate: the quest it is a step of, and the index of that step in the quest's checks — available while the quest is granted, unclaimed, and the step is not yet done; omit both for an ungated scene), `once` (default true — a scene plays once per run; once:false re-arms on every visit), and `lines` (the dialogue, in order — each line: `from` a speaker id, `text` the words, `audio` the speech clip file (optional — a text-only line is valid)). The first scene ships: the bar's Trestle + Carol meeting (special_delivery_bar_meeting — 'Special Delivery' step 1; assets/speech/trestle/trestle-q3-01.mp3 + assets/speech/carol/carol-q3-01..04.mp3).",
"window": {
"$comment": "The centered window (js/ui/VignetteWindow.js) — the comms box's centered twin: on the left the speaker's clip in a bracketed feed panel (muted, looping while the line holds — a NO SIGNAL plate if the clip never lands), on the right the line's text decoding in, with the NEXT button below it — the primary action in amber (the same attention pulse as the comms' ACKNOWLEDGE), reading DONE on the last line. videoSize 256 = the planet cut at FULL size (the clip is 256×256 — the face is never downscaled); width 800 leaves a 502px text column (800 − 2·14 pad − 256 feed − 14 gap). The window SIZES TO THE LINE IN PLAY (textHeightFor → _rebuildLayout): a later line taller than the first grows the window — backplate, button, pulse, re-center — so the words never run into the button or the window's edge. The SCRIM dims the world behind the window so it owns the moment — the looping clip behind it keeps moving (the location is the set). startDelayMs = the beat between the location's clip coming up and the window opening: the place reads first, then the scene begins.",
"width": 800,
"pad": 14,
"headerGap": 8,
"videoSize": 256,
"videoGap": 14,
"startDelayMs": 700,
"text": {
"fontSize": 13,
"lineHeight": 18,
"letterSpacing": 0.4
},
"button": {
"label": "NEXT",
"doneLabel": "DONE",
"$gap": "the row of space between the line's text and the NEXT/DONE button — one full line-height (18) on top of the old 10: the words and the button read as separate rows, never crowded",
"gap": 28,
"fontSize": 11,
"paddingX": 16,
"paddingY": 7,
"letterSpacing": 2
},
"pulse": {
"$comment": "The NEXT/DONE button's attention pulse: the button wears the window's amber, an amber halo breathes under it, and two staggered sonar rings expand out — the one live control on the surface is unmistakable while the scene holds.",
"enabled": true,
"color": "#ffd84d",
"periodMs": 1300
},
"animation": {
"inMs": 260,
"outMs": 420
},
"scrim": {
"color": "#02040a",
"alpha": 0.4
},
"colors": {
"panel": "#0a1120",
"panelAlpha": 0.94,
"border": "#22405f",
"borderAlpha": 0.9,
"notch": 10,
"neon": "#00e5ff",
"ink": "#eaf6ff",
"dim": "#7d92c4",
"faint": "#3d4c74",
"amber": "#ffc94d"
}
}
}