• docs/superpowers/specs/20

    From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Thursday, July 09, 2026 01:55:00
    https://gitlab.synchro.net/main/sbbs/-/commit/5b22fcff57fe8acdd12ae0ab
    Modified Files:
    docs/superpowers/specs/2026-07-08-syncmoo1-sfx-audio-design.md
    Log Message:
    syncmoo1: spec -- fix the s_ rationale, flag the transcode-version gap

    Two corrections to the SFX audio spec, both found by checking what the
    other doors actually do rather than assuming.

    The spec claimed the "s_" prefix keeps the sfx and music namespaces from aliasing. It does not, and nothing needs to: cache_name() already
    separates them by sub-directory (<prefix>/sfx/<leaf> vs
    <prefix>/music/<key>). The prefix is a legibility tag, which is what SyncDuke's own comment says of its "<trackname>_<hash>" scheme -- "the
    name just makes the cache files readable". Keep "s_", drop the false
    reason.

    More usefully: termgfx does not ship our VOC verbatim. sfx_store_bytes() transcodes it to an 8-bit WAV, so s_<hash> names the SOURCE bytes, not
    the cached ones. Music already solved this -- mus_key() appends _v<MUS_RENDER_VER> so the name changes when the renderer does. SFX have
    no such tag. Harmless today, because every session re-Stores and the
    Store overwrites; it becomes a stale-audio bug the moment step 3 makes name-presence mean "skip the upload". Step 3 now says the leaf must gain
    its own transcode-version tag (s_<hash8>_v<n>, 13 chars, inside the
    16-byte bound termgfx enforces) before, or with, widening the C;L glob.

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Thursday, July 09, 2026 01:55:00
    https://gitlab.synchro.net/main/sbbs/-/commit/01f7dea9c9e7fc2a8ca46204
    Modified Files:
    docs/superpowers/specs/2026-07-08-syncmoo1-sfx-audio-design.md
    Log Message:
    syncmoo1: spec -- repair the step-3 follow-on, state both preconditions

    The previous commit inserted the transcode-version note into the step-3
    heading and left the old sentence's tail orphaned: a paragraph beginning
    " Only safe once step 2 lands:" with no subject.

    Rewrite the section so it names both of step 3's preconditions, which are independent and easy to conflate:

    1. Step 2 must land first -- the C;L skip is name-presence, so it is
    only correct once SyncDOOM's and SyncDuke's SFX names are
    content-addressed rather than keyed on a WAD/GRP-dependent id.

    2. The SFX leaf must gain a transcode-version tag. termgfx Stores a
    WAV transcoded from our VOC, so s_<hash> names the source bytes and
    not the cached ones; music already appends _v<MUS_RENDER_VER> for
    exactly this reason.

    Docs only.

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Friday, July 17, 2026 02:57:00
    https://gitlab.synchro.net/main/sbbs/-/commit/e3024f0fc318a49f4e2f0967
    Added Files:
    docs/superpowers/specs/2026-07-16-syncretro-lobby-enter-sound-design.md Log Message:
    docs: design for a SyncRetro lobby enter_sound

    SyncDuke and SyncDOOM play a one-shot, sysop-supplied sound when a player enters the lobby. The SyncRetro consoles (SyncNES, SyncIvision) don't. The mechanism is already shared -- game_lobby.js's enter_sound(), which syncretro_lobby.js already loads -- so this is a call, an ini key and docs.

    Records the two decisions that took the most getting to:

    - No built-in sound. A synthesized blip would need no asset and would reach
    terminals that have the audio APC but no libsndfile, but A;Synth has no
    envelope, and a console effect is mostly its decay. And a Synth sequence
    tuned until it reproduces a specific game's sound is a derivative of that
    sound -- arriving as code rather than a WAV changes nothing. Only a
    generic blip is clean, and that isn't what the feature is for.

    - The key is [lobby] enter_sound, not [audio]. [lobby] is game_lobby.js's
    contract and matches the siblings; SyncRetro's [audio] documents the
    in-game Opus stream from the core, which a one-shot lobby SFX shares
    nothing with.

    Also records a concern that was raised and disproved, so it isn't chased
    again: enter_sound's fixed "lobby_enter" name does NOT defeat a wildcard's per-entry randomness, because enter_sound loads cterm_lib.js into a fresh
    scope each call, so its upload-once cache starts empty every entry. Verified under jsexec.

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Saturday, July 18, 2026 03:02:00
    https://gitlab.synchro.net/main/sbbs/-/commit/e3df945410f392ae2268c9ed
    Added Files:
    docs/superpowers/specs/2026-07-17-syncscumm-m3-input-design.md
    Log Message:
    syncscumm: design M3, keyboard and mouse input

    Design for making a ScummVM adventure playable over the terminal --
    Beneath a Steel Sky first. Today the backend's pollEvent() only ever
    emits EVENT_QUIT, so no key or pointer input reaches the engine.

    The cursor compositor already exists (built in M2 for the GUI overlay),
    so M3 is purely input plumbing: turn terminal input into Common::Events
    and call warpMouse() so the existing compositor draws the pointer.

    Mouse is absolute point-and-click, modelled on syncconquer: SGR pixel
    mouse (DEC 1016) with an automatic cell (DEC 1006) fallback that the
    terminal selects by what it reports back. Per the user's decision, the
    mouse handshake is extracted into a shared termgfx/mouse module first
    and syncconquer refactored onto it, before syncscumm consumes it.
    Keyboard reuses termgfx's key-mode negotiator, mapping decoded keys to
    ScummVM KeyState.

    Also records the resolved hotkey conflict (drop the door +/- volume key,
    pass it to the engine, whose GMM Options dialog has the volume sliders)
    and the decision to defer the sixel quantizer-stability gate out of M3.

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Sunday, July 19, 2026 15:25:00
    https://gitlab.synchro.net/main/sbbs/-/commit/43cf5c5c07455b137b04030d
    Added Files:
    docs/superpowers/specs/2026-07-19-libtermgfx-termio-extraction-design.md
    Log Message:
    docs: design spec for the libtermgfx terminal-I/O extraction

    Sub-project 1 of the syncrpg (EasyRPG / RPG Maker door) effort: lift syncscumm's sst_io.c terminal-I/O engine -- the render pipeline (canvas
    probe, aspect scale, sixel/JXL tiers, pacing), the input decode
    (kitty/evdev keyboard + SGR mouse), and the DOOR32/socket I/O -- into a
    shared libtermgfx termgfx_termio module with a door-facing API, then
    refactor syncscumm onto it behavior-identically so a second door can
    reuse it.

    The audio stream, encoders, key-mode and node helpers are already shared
    and out of scope. Behavior identity is gated on syncscumm's existing
    boot/unit tests passing unedited, a before/after wire-byte diff, and a
    live confirm.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Sunday, July 19, 2026 15:25:00
    https://gitlab.synchro.net/main/sbbs/-/commit/986e8c66c289bdab6eb9fcde
    Modified Files:
    docs/superpowers/specs/2026-07-19-libtermgfx-termio-extraction-design.md
    Log Message:
    docs: reframe the termio extraction spec around all-door convergence

    The per-door terminal-I/O orchestration is duplicated across all five
    graphical doors -- syncretro_io.c, syncscumm's sst_io.c, syncduke_io.c, syncdoom's i_video/r_draw/v_video, and syncconquer's door_io.c -- not just syncscumm. The low-level primitives (caps, geometry, sixel/jxl, pace,
    mouse, keymode, door32, audio, node) are already shared in libtermgfx, but
    the loop that drives them was never carved out.

    Reframe termgfx_termio as the canonical shared orchestration every
    graphical door converges on: seed it from syncscumm's (most recently
    hardened) sst_io.c, but design the API against the union of all the doors' *_io.c needs, not merely clone one. The bounded first step is unchanged -- migrate only syncscumm + syncrpg now; retro/duke/doom/conquer migrate as separate later efforts.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Sunday, July 19, 2026 23:59:00
    https://gitlab.synchro.net/main/sbbs/-/commit/08de21af537ce5e8b9982e13
    Added Files:
    docs/superpowers/specs/2026-07-19-syncrpg-door-design.md
    Log Message:
    syncrpg: add the EasyRPG door design spec (sub-project 2)

    Design for a dedicated Synchronet door playing RPG Maker 2000/2003 games via
    a vendored EasyRPG Player driving the shared termgfx_termio, flagship Yume Nikki (freeware original + English fan-translation). Adds a truecolor present path to termgfx_termio (present_rgbx, 32-bit XRGB fed zero-copy from EasyRPG's screen) and moves the median-cut quantizer into the shared lib as termgfx_quant, verified not to regress syncscumm's indexed path. Mirrors syncscumm's structure: vendored engine, per-game getdata.js + install-xtrn, per-user saves, milestones M0 truecolor path -> M1 video -> M2 keyboard ->
    M3 audio -> M4 package/live on Yume Nikki.

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Sunday, July 19, 2026 23:59:00
    https://gitlab.synchro.net/main/sbbs/-/commit/06781056c08a02a40b5bd078
    Modified Files:
    docs/superpowers/specs/2026-07-19-syncrpg-door-design.md
    Log Message:
    syncrpg: pin Yume Nikki source (Playism 0.10a) in the design spec

    Lock the flagship game-data source to the official Playism 2012 English
    release of Yume Nikki 0.10a (archive.org yume-nikki-010a): English is baked into the .ldb (no separate translation step), extraction is headless (unpack the outer zip, then the inner YumeNikki.lzh; Setup.exe is never run), and the asset filenames are Shift-JIS. Record the documented controls (arrows, ESC menu, Enter/Z/Space confirm, Numpad 9/1/3/5) and drop the now-resolved open questions.

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Tuesday, July 21, 2026 01:49:00
    https://gitlab.synchro.net/main/sbbs/-/commit/395b9159644b8a0ee6a199f2
    Modified Files:
    docs/superpowers/specs/2026-07-19-syncrpg-door-design.md
    Log Message:
    syncrpg: re-pin the flagship source to a portable plain-ZIP (rmarchiv 0.10a)

    getdata.js must be portable Synchronet JS (Windows + Linux), and Synchronet's native Archive (libarchive) opens ZIP but not LHA -- so the Playism source (nested .lzh + Shift-JIS filenames) is not portably extractable. Re-pin to the official Steam/Playism English Yume Nikki 0.10a as a plain ZIP from
    rmarchiv.de (the EasyRPG-recommended archive): native Archive extracts it cleanly, ASCII asset filenames (no transcode / --encoding), EasyRPG boots it headless. The tokened rmarchiv download URL is flagged as a plan task.

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Tuesday, July 21, 2026 21:53:00
    https://gitlab.synchro.net/main/sbbs/-/commit/15780517d5df4349c3e29f17
    Added Files:
    docs/superpowers/specs/2026-07-21-door-idle-detection-design.md
    Log Message:
    doors: design spec for graphical-door idle-user detection

    Synchronet's per-program "Maximum Inactivity" cannot detect an idle user in
    any of the termgfx graphical doors. xtrn_sec.cpp does apply the setting for
    the door's duration, but enforcement in input_thread() tests a counter that
    is reset on any successful socket read -- and every termgfx door paces its frame loop with DSR acks, so the terminal answers ~10x/sec with no human involved. The counter never approaches the threshold. The failure is silent
    and points the safe-looking way: the setting reads as configured, and does nothing.

    Observed on node 11 this afternoon: a SyncRetro NES session 236 minutes in,
    TCP healthy and the door rendering at ~10fps, where every inbound segment
    was exactly 6 bytes (ESC[1;1R, the pace-ack) across 1,759 consecutive
    segments -- not one keystroke. The user had walked away and nothing at any layer was positioned to notice.

    The design puts the clock in the door, where real key events can be told
    apart from terminal auto-replies: a shared termgfx/idle.{h,c} state machine
    fed from the door's key dispatch, a sysop-configurable [idle] section with
    an exempt ARS defaulting to EXEMPT H, and warn-then-exit-to-lobby so a silent-but-engaged user watching a cutscene gets a chance to stay. The door exits rather than hanging up, which lets the BBS's own session inactivity timeout take over once pacing stops.

    Also records a parsing hazard the implementation has to close: the JS parse_duration() in game_lobby.js treats a bare number as days while
    xpdev's C parse_duration() treats it as seconds, and both will read the
    same ini key.

    SyncRetro adopts it first; the other five doors are tracked as follow-on
    work so the divergence stays visible.

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Tuesday, July 21, 2026 21:53:00
    https://gitlab.synchro.net/main/sbbs/-/commit/fbdff744f0b711125545a224
    Modified Files:
    docs/superpowers/specs/2026-07-21-door-idle-detection-design.md
    Log Message:
    doors: extend the idle-detection spec to all six graphical doors

    Surveying the other five doors turned up a constraint the first draft did
    not account for: only half of them have a JS lobby. syncretro, syncduke and syncdoom build their command lines in JS and so can evaluate an exempt ARS
    at launch; syncscumm, syncconquer and syncmoo1 are static xtrn.ini entries
    with nowhere to run that check. DOOR32.SYS cannot close the gap either --
    it carries no exempt flags, and termgfx's parser does not even extract the security level.

    So the spec now describes two launch shapes. Lobby doors evaluate
    exempt_ars and pass -i<seconds>; the other three take the same [idle] keys
    from their own ini and additionally honor -i on the static command line.
    The resulting exemption asymmetry is recorded as an accepted consequence
    rather than left to be discovered, along with what it would take to close.

    Also captured per door: the activity hook sites, the mouse hook, the exit
    check and the warning renderer. Two doors grew parallel key dispatchers and need multi-site hooks; hooking their deeper common point is rejected
    because synthetic key-up expiry timers also call it, which would forge
    activity for a user who has left. Mouse motion needs the report handler
    rather than the event queue everywhere except syncscumm, the only door that queues a motion event.

    Three doors need more than a hook. syncscumm has no session time limit at
    all -- termio reads the drop file's limit and discards it -- and no
    transient overlay; both get built in termgfx_termio so syncrpg inherits
    them. syncmoo1 has no overlay either. syncduke has no unified exit check. syncconquer is the cheapest and is proposed as the first target: its
    time-limit function is already a warn-only stub whose own comment invites
    this escalation.

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net