/** * The "decode" scramble — the shared type-out effect of the console. * * The main menu uses it on the Galaxy Seed field (it "decodes" in as the * panel assembles); the game uses it on the system dossier HUD — the * system name and every data line below it type themselves in as the * ship arrives. One effect, two scenes. * * Over `dur` ms the target string reveals left-to-right while the * unrevealed slots hold random glyphs from the decode alphabet — the * console pulling a signal out of static. * * Pure (no Phaser): build one per line with a start time, poll * `display(time)` from the scene's `update()`, and drop it once * `finished(time)`. The time base is the engine loop time the scene's * `update(time, delta)` receives (=== `this.time.now` after that frame). * * const dec = new ScrambleDecode('Kepler-9', t0, DECODE_DURATION); * // each frame: if (dec.started(time)) text.setText(dec.display(time)); * // done when: dec.finished(time) */ /** The alphabet unrevealed slots draw from (no vowels, no 0/1 — signal, not language). */ export const DECODE_CHARS = 'abcdefghjkmnpqrstuvwxyz23456789#%+*<>?'; /** The menu's seed-field window (ms) — the canonical decode timing. */ export const DECODE_DURATION = 620; export class ScrambleDecode { /** * @param {string} value the final text * @param {number} t0 absolute start time (scene time, in ms) * @param {number} [dur] reveal window in ms */ constructor(value, t0, dur = DECODE_DURATION) { this.value = String(value ?? ''); this.t0 = t0; this.dur = dur > 0 ? dur : 1; } started(time) { return time >= this.t0; } finished(time) { return (time - this.t0) / this.dur >= 1; } /** * The display string at `time`: the revealed prefix of the target with * the rest scrambled. '' before the start, the exact target once * finished (the reveal lands at ~87% of the window, then holds). */ display(time) { if (!this.started(time)) return ''; if (this.finished(time)) return this.value; const u = (time - this.t0) / this.dur; const reveal = Math.floor(Math.max(0, Math.min(1, u * 1.15)) * this.value.length); let out = ''; for (let i = 0; i < this.value.length; i++) { out += i < reveal ? this.value[i] : DECODE_CHARS[(Math.random() * DECODE_CHARS.length) | 0]; } return out; } } /** * Per-line window for multi-line decodes (the system dossier): ~70 ms per * character — the menu's feel — floored so short lines don't flicker and * capped so long ones don't drag. */ export function decodeDur(length = 0) { return Math.max(420, Math.min(880, 320 + length * 46)); }