Docs › Reference

Reference

Configuration Reference

Configuration Reference

All settings live in config.yaml in the working directory (next to the JAR). The bundled src/main/resources/config.yaml is used as the default template. On first run, a legacy config.json is automatically migrated to config.yaml and the original is backed up to config.json.bak. Keys are now grouped into nested YAML sections rather than being flat enum names.

Key bindings accept either GLFW key codes (integers) or human-readable key names such as "SPACE", "Q", and "GLFW_KEY_F9". See the GLFW key token reference for the full list. Common values are shown in the tables below.


Sections

The config.yaml is organized into the following top-level sections:

Normal sections (relevant to all users):

SectionContents
displayAspect preset, window autosize, display shader library, deadzone mode, color profile, FPS
inputplayer1 / player2 key bindings, pause key
audioEnabled flag, region, DAC, FM6, PSG settings
charactersMain character, sidekick, data select combos
romsROM filenames for S1, S2, S3K; default game selection
captureTrace video capture output dir, scale, fps, codec
startupTitle screen, master title, legal disclaimer flags
rewindLive rewind enable/key, tape-coast parameters, audio history settings
crossGameCross-game feature donation enable and source
launchPer-game master-title launch profiles
discordDiscord Rich Presence enable, show timer, show zone

debug: block (developer/debug tooling — safe to ignore for normal play):

Sub-sectionContents
debug.flagsDebug subsystem, editor enable, collision view overlay
debug.keysAll debug/developer keyboard shortcuts
debug.startupLevel select on startup, S3K skip intros
debug.playbackBK2 movie path and playback control keys (unbound by default)
debug.traceRewindKey held during Trace Test Mode to rewind engine state
debug.traceRenderTrace Test Mode / capture visibility flags
debug.testModeTest mode enable flag and trace catalog directory
debug.crossGameData-select image regeneration overrides and coord-log key
debug.windowDEPRECATED manual width/height/scale — use display.aspect + display.windowAutosize instead

Note: SCREEN_WIDTH_PIXELS and SCREEN_HEIGHT_PIXELS are derived values computed from the display.aspect preset. They are never stored in config.yaml. debug.window.width / debug.window.height / debug.window.scale are deprecated; widescreen is driven by display.aspect profiles.


Display

KeyYAML pathTypeDefaultDescription
SCREEN_WIDTH_PIXELS(derived)int320Logical pixel width — the Mega Drive native horizontal resolution. Derived from display.aspect; never stored.
SCREEN_HEIGHT_PIXELS(derived)int224Logical pixel height — the Mega Drive native vertical resolution (224 for NTSC, 240 for PAL). Derived; never stored.
SCREEN_WIDTHdisplay / debug.window.widthint640Actual window width in OS pixels. Derived from aspect preset when display.windowAutosize=true.
SCREEN_HEIGHTdisplay / debug.window.heightint448Actual window height in OS pixels.
SCALEdebug.window.scaledouble1.0DEPRECATED additional rendering scale factor.
FPSdisplay.fpsint60Target frames per second. Affects game speed — use 60 for NTSC, 50 for PAL.
DISPLAY_COLOR_PROFILEdisplay.colorProfilestring"RAW_RGB"Palette presentation profile. "RAW_RGB" keeps the current direct 8-bit expansion, "MD_ANALOG" applies a darker Mega Drive-style analog ramp, and "NTSC_SOFT" applies the analog ramp plus mild desaturation.
DISPLAY_COLOR_PROFILE_TOGGLE_KEYdisplay.colorProfileToggleKeykeyVRuntime key used to cycle display color profiles. The selected profile is saved to config.yaml and shown briefly in the bottom-left corner.
DISPLAY_ASPECTdisplay.aspectstring"NATIVE_4_3"Display aspect preset. Controls the native pixel width used by the renderer. Accepted values: "NATIVE_4_3" (320 px, default), "WIDE_16_10" (352 px), "WIDE_16_9" (400 px), "ULTRA_21_9" (528 px), "SUPER_32_9" (800 px). EXPERIMENTAL / INCOMPLETE — widescreen rendering (UI pillarbox, parallax column extension) is not finished; only "NATIVE_4_3" is fully supported.
DISPLAY_WINDOW_AUTOSIZEdisplay.windowAutosizebooltrueWhen true and a widescreen preset is active, the OS window is derived from the preset at 2x baseline (e.g. WIDE_16_9 → 800×448). When false, SCREEN_WIDTH/SCREEN_HEIGHT are used verbatim so a custom window size is preserved. Has no effect when DISPLAY_ASPECT is "NATIVE_4_3".
DISPLAY_SHADER_LIBRARY_ROOTdisplay.shaderLibraryRootstring"shaders"Root directory scanned for user display shaders, resolved relative to the working directory.
DISPLAY_SHADER_SELECTIONdisplay.shaderSelectionstring"OFF"Last selected display shader. Use "OFF" or a root-relative forward-slash path under DISPLAY_SHADER_LIBRARY_ROOT.
DISPLAY_SHADER_NEXT_KEYdisplay.shaderNextKeykeyRIGHT_BRACKETRuntime key used to advance to the next display shader.
DISPLAY_SHADER_PREVIOUS_KEYdisplay.shaderPreviousKeykeyLEFT_BRACKETRuntime key used to move to the previous display shader.
DISPLAY_SHADER_PICKER_KEYdisplay.shaderPickerKeykeyBACKSLASHRuntime key used to open the searchable display shader picker.
DISPLAY_SHADER_DEFAULT_PHASEdisplay.shaderDefaultPhaseenum"PRESENTATION"Fallback render phase for standalone display shaders. Accepted values: "SCENE", "PRESENTATION", "FINAL".
WIDESCREEN_DEADZONE_MODEdisplay.deadzoneModestring"PROPORTIONAL"Camera horizontal deadzone behaviour on wide screens: "CENTER_SCALED" keeps the native 16px deadzone band; "PROPORTIONAL" scales the band width with the screen width. EXPERIMENTAL — takes effect only when a widescreen preset is active.

Display shader library

Display shaders are user-supplied post-processing shaders loaded from the root-level shaders/ directory. This is separate from src/main/resources/shaders, which contains engine-owned shaders required for normal rendering. The root shaders/ directory is gitignored so local shader packs and third-party shader licenses stay outside the repo unless they are reviewed separately.

Recommended layout:

shaders/
  Custom/
    warm-crt.glsl
  BizHawk/
    BizScanlines.cgp
    BizScanlines.glsl
  libretro-glsl/
    crt/
    scanlines/
    ...
    .openggf-libretro-glsl.properties

The engine scans .glsl, .cgp, and .glslp files at runtime and always includes Off. Use ] and [ to cycle quickly, or press BACKSLASH to open the searchable picker for large libraries. The picker filters by root-relative path and inferred category, so typing crt narrows entries such as libretro-glsl/crt/....

The optional libretro GLSL pack installer is available from the shader picker: open the picker with BACKSLASH, then press F5 to install or update the pack. The app downloads the upstream zip archive from GitHub, extracts it into shaders/libretro-glsl/, strips the archive’s top-level folder, stores update metadata in shaders/libretro-glsl/.openggf-libretro-glsl.properties, and rescans the shader library when the install/update finishes. That folder is owned by the installer; put personal shaders in a sibling folder such as shaders/Custom/.

Compatibility is intentionally bounded. Fragment-only shaders can sample the current scene through declared samplers named s_p, SceneTexture, or Texture. RetroArch and BizHawk-style uniforms are populated by location when declared: IN.video_size, IN.texture_size, IN.output_size, InputSize, TextureSize, OutputSize, FrameCount, FrameDirection, and MVPMatrix. Combined shaders may declare VertexCoord, TexCoord, and COLOR attributes; the engine binds them to fixed quad locations. The engine does not inject uniform declarations.

HLSL/Cg-only presets can be discovered but fail on selection unless a loadable GLSL sibling exists. Unsupported preset inheritance, external LUT textures, previous-frame history, and malformed shaders fail safely: the selection is rejected, the shader is remembered as failed for the current process, rendering continues, and the user can return to Off.

Display shaders affect presentation only. F12 screenshots are captured after the display shader composite, so screenshots include the selected shader. Trace replay/capture uses a separate render path that stops before display shader application, so trace artifacts stay shader-free; if trace capture is ever refactored to call the main Engine.display() path, display shader application must be gated off for trace capture.


ROM Files

Paths are relative to the working directory (where the JAR is launched).

KeyYAML pathTypeDefaultDescription
DEFAULT_ROMroms.defaultstring"s2"Which game to boot: "s1", "s2", or "s3k". Selects the corresponding ROM key below.
SONIC_1_ROMroms.sonic1string"Sonic The Hedgehog (W) (REV01) [!].gen"Filename of the Sonic 1 ROM.
SONIC_2_ROMroms.sonic2string"Sonic The Hedgehog 2 (W) (REV01) [!].gen"Filename of the Sonic 2 ROM.
SONIC_3K_ROMroms.sonic3kstring"Sonic and Knuckles & Sonic 3 (W) [!].gen"Filename of the Sonic 3&K (locked-on) ROM.

Startup Flow

KeyYAML pathTypeDefaultDescription
SHOW_LEGAL_DISCLAIMER_ON_STARTUPstartup.legalDisclaimerbooltrueShow the legal disclaimer screen on engine startup before the master title screen. White text on black, 5-second readability gate, any-key dismiss, fade-in/out transitions. Set false for headless tests, trace replay sessions, or CI runs that should not have to drive past this screen.
MASTER_TITLE_SCREEN_ON_STARTUPstartup.masterTitleScreenbooltrueShow the master title / game-selection screen on launch. When false, boots directly into the game set by DEFAULT_ROM.
TITLE_SCREEN_ON_STARTUPstartup.titleScreenbooltrueShow the game-specific title screen (e.g. Sonic 2 title screen) before gameplay. Ignored when MASTER_TITLE_SCREEN_ON_STARTUP is true and game selection is pending.
LEVEL_SELECT_ON_STARTUPdebug.startup.levelSelectOnStartupboolfalseJump straight to the level select screen instead of the title screen. Useful for development.
S3K_SKIP_INTROSdebug.startup.s3kSkipIntrosboolfalse(S3K only) Skip zone intro sequences such as the AIZ biplane cutscene and boot straight into playable gameplay.

Cross-Game Donation

KeyYAML pathTypeDefaultDescription
CROSS_GAME_FEATURES_ENABLEDcrossGame.enabledboolfalseEnable cross-game feature donation. When false, each game uses only its own native frontend and gameplay assets.
CROSS_GAME_SOURCEcrossGame.sourcestring"s2"Donor game for cross-game features. Currently supports "s2" and "s3k".
CROSS_GAME_S1_DATA_SELECT_IMAGE_GEN_OVERRIDEdebug.crossGame.s1DataSelectImageGenOverrideboolfalseForce regeneration of the runtime Sonic 1 donated Data Select screenshot cache on the next eligible boot.
CROSS_GAME_S2_DATA_SELECT_IMAGE_GEN_OVERRIDEdebug.crossGame.s2DataSelectImageGenOverrideboolfalseForce regeneration of the runtime Sonic 2 donated Data Select screenshot cache on the next eligible boot.

Cross-Game Debug Key

KeyYAML pathDefaultKey NameDescription
CROSS_GAME_S1_DATA_SELECT_IMAGE_COORD_LOG_KEYdebug.crossGame.s1DataSelectImageCoordLogKey39ApostropheWhile playing Sonic 1, log the current camera as a preview override point for donated Data Select screenshot tuning.

Launch Profiles

The master title screen stores per-game launch defaults under launch.s1, launch.s2, and launch.s3k. Select a game on the master title screen and press Tab to open the launch profile panel; stock games show the hover line Stock launch - Tab to configure. The panel uses the configured UP/DOWN bindings to choose a row and the configured LEFT/RIGHT bindings to change that row. Hardcoded Backspace resets the profile to stock; hardcoded Tab or Esc closes and saves it.

Profiles are persistent defaults for future manual launches, but applying a profile is session-only. A launch can temporarily override live rewind, cross-game donation, debug tools, display aspect, main character, and sidekick without writing those values into the global gameplay keys (rewind.liveEnabled, crossGame.*, debug.flags.debugView, display.aspect, or characters.*). Programmatic trace launches clear any stale launch profile overrides and skip profile application.

crossGameSource: "off" disables donation for that game launch and restores the built-in crossGame.source default in the session overlay so the donor choice cannot leak from a previous launch. When crossGameSource is "s3k", the launch panel hides mainCharacter and sidekick because the donated S3K Data Select screen owns team selection. When character rows are shown, their options follow the active donor: Sonic is always available, Tails requires Sonic 2 or Sonic 3&K data, and Knuckles requires Sonic 3&K data; hand-edited saved values outside that donor set are clamped before launch. aspect: "global" inherits the normal display.aspect setting and does not resize the window; pinned aspect values such as "WIDE_16_9" apply only for that game session and resize back when returning to the master title. In the launch panel, pinned 16:10 and 16:9 aspects are amber non-standard choices, while 21:9 and 32:9 are red experimental choices.

Stock defaults:

GamerewindcrossGameSourcedebugToolsaspectmainCharactersidekick
Sonic 1false"off"false"global""sonic""none"
Sonic 2false"off"false"global""sonic""tails"
Sonic 3&Kfalse"off"false"global""sonic""tails"
KeyYAML pathTypeDefaultDescription
LAUNCH_S1_REWINDlaunch.s1.rewindboolfalseEnable live rewind for manual Sonic 1 launches.
LAUNCH_S1_CROSS_GAME_SOURCElaunch.s1.crossGameSourceenum"off"Cross-game donor for manual Sonic 1 launches: "off", "s2", or "s3k".
LAUNCH_S1_DEBUG_TOOLSlaunch.s1.debugToolsboolfalseEnable debug tools for manual Sonic 1 launches.
LAUNCH_S1_ASPECTlaunch.s1.aspectenum"global"Display aspect for manual Sonic 1 launches: "global" or a display.aspect preset.
LAUNCH_S1_MAIN_CHARACTERlaunch.s1.mainCharacterenum"sonic"Main character for manual Sonic 1 launches.
LAUNCH_S1_SIDEKICKlaunch.s1.sidekickenum"none"Sidekick for manual Sonic 1 launches; "none" disables sidekick spawning.
LAUNCH_S2_REWINDlaunch.s2.rewindboolfalseEnable live rewind for manual Sonic 2 launches.
LAUNCH_S2_CROSS_GAME_SOURCElaunch.s2.crossGameSourceenum"off"Cross-game donor for manual Sonic 2 launches: "off", "s1", or "s3k".
LAUNCH_S2_DEBUG_TOOLSlaunch.s2.debugToolsboolfalseEnable debug tools for manual Sonic 2 launches.
LAUNCH_S2_ASPECTlaunch.s2.aspectenum"global"Display aspect for manual Sonic 2 launches: "global" or a display.aspect preset.
LAUNCH_S2_MAIN_CHARACTERlaunch.s2.mainCharacterenum"sonic"Main character for manual Sonic 2 launches.
LAUNCH_S2_SIDEKICKlaunch.s2.sidekickenum"tails"Sidekick for manual Sonic 2 launches; "none" disables sidekick spawning.
LAUNCH_S3K_REWINDlaunch.s3k.rewindboolfalseEnable live rewind for manual Sonic 3&K launches.
LAUNCH_S3K_CROSS_GAME_SOURCElaunch.s3k.crossGameSourceenum"off"Cross-game donor for manual Sonic 3&K launches: "off", "s1", or "s2".
LAUNCH_S3K_DEBUG_TOOLSlaunch.s3k.debugToolsboolfalseEnable debug tools for manual Sonic 3&K launches.
LAUNCH_S3K_ASPECTlaunch.s3k.aspectenum"global"Display aspect for manual Sonic 3&K launches: "global" or a display.aspect preset.
LAUNCH_S3K_MAIN_CHARACTERlaunch.s3k.mainCharacterenum"sonic"Main character for manual Sonic 3&K launches.
LAUNCH_S3K_SIDEKICKlaunch.s3k.sidekickenum"tails"Sidekick for manual Sonic 3&K launches; "none" disables sidekick spawning.

Allowed launch profile enums:

FieldValues
crossGameSource"off", "s1", "s2", "s3k"; the launched game cannot donate to itself and is clamped to "off" when hand-edited.
aspect"global", "NATIVE_4_3", "WIDE_16_10", "WIDE_16_9", "ULTRA_21_9", "SUPER_32_9"
mainCharacter"sonic", "tails", "knuckles"; selectable values are donor-gated.
sidekick"none", "sonic", "tails", "knuckles"; selectable values are donor-gated.

Characters

KeyYAML pathTypeDefaultDescription
MAIN_CHARACTER_CODEcharacters.mainstring"sonic"Identity of the player-controlled character. Currently only "sonic" is supported.
SIDEKICK_CHARACTER_CODEcharacters.sidekickstring"tails"CPU-controlled sidekick spawned alongside the main character. Defaults to "tails" (Tails AI enabled). Set to "sonic" to clone the player, or "" (empty) to disable the sidekick.
DATA_SELECT_EXTRA_PLAYER_COMBOScharacters.dataSelectExtraCombosstring""Extra team combinations shown on the S3K Data Select screen. Format is main,sidekick1,sidekick2;main2,sidekick1. The first character in each group is the main character; remaining entries are sidekicks. Example: "sonic,knuckles;sonic,tails,tails;knuckles,tails". This only affects Data Select team choices; normal gameplay and Level Select still use MAIN_CHARACTER_CODE and SIDEKICK_CHARACTER_CODE.

Audio

KeyYAML pathTypeDefaultDescription
AUDIO_ENABLEDaudio.enabledbooltrueMaster switch for all audio output (music and SFX).
REGIONaudio.regionstring"NTSC"Hardware region: "NTSC" (60 Hz) or "PAL" (50 Hz). Affects SMPS tempo timing and DAC sample rates.
DAC_INTERPOLATEaudio.dacInterpolatebooltrueApply linear interpolation to DAC (drum) samples. Reduces aliasing noise for a smoother sound.
AUDIO_INTERNAL_RATE_OUTPUTaudio.internalRateOutputboolfalseOutput audio at the YM2612 internal sample rate (~53 kHz) rather than the system rate. Useful for bit-accurate captures; may cause issues on some audio drivers.
PSG_NOISE_SHIFT_EVERY_TOGGLEaudio.psgNoiseShiftEveryTogglebooltruePSG noise LFSR clock behaviour. true = shift on every polarity toggle (MAME-style, brighter noise); false = shift on positive edges only (Genesis Plus GX / libvgm style, darker noise).
FM6_DAC_OFFaudio.fm6DacOffbooltrueSilence FM channel 6 whenever a DAC note is active. Matches the SMPSPlay parity hack used in Sonic 2; prevents FM bleed audible during percussion.

Capture

Trace video capture (the headless trace-capture driver / TraceCaptureTool) renders a chosen trace and muxes a lossless MKV via ffmpeg. These keys set the code defaults; CLI flags override them. The bundled config.yaml omits the optional capture block until a user needs to override one of these defaults.

KeyYAML pathTypeDefaultDescription
CAPTURE_OUTPUT_DIRcapture.outputDirstring"target/trace-videos"Output directory for trace capture videos.
CAPTURE_SCALEcapture.scaleint4Integer nearest-neighbor upscale factor applied to the captured frames.
CAPTURE_FPScapture.fpsint60Output frame rate for the captured video.
CAPTURE_CODECcapture.codecstring"ffv1"Capture video codec (e.g. ffv1).

Invoke the tool through Maven (requires a ROM in the working directory, an offscreen-capable GL context, and ffmpeg on PATH):

mvn exec:java "-Dexec.mainClass=com.openggf.tools.TraceCaptureTool" "-Dexec.args=--trace <id|name|dir> --out-dir target/trace-videos"

CLI flags (all optional except --trace; unspecified flags fall back to the CAPTURE_* defaults above):

FlagDefaultDescription
--trace <id|name|dir>(required)Trace to capture: a 0-based TraceCatalog index, a trace directory name, or a direct path to a trace directory.
--out-dir <dir>CAPTURE_OUTPUT_DIROutput directory. The file is written as capture-<trace-name>-<UTC>.mkv.
--scale <n>CAPTURE_SCALEInteger nearest-neighbor upscale factor.
--fps <n>CAPTURE_FPSOutput frame rate.
--codec <name>CAPTURE_CODECCapture video codec.
--no-ghosts / --ghostsTRACE_SHOW_DESYNC_GHOSTSHide / show the desync ghost(s) in the captured video (overrides the config flag for this run).

Desync-ghost / game-HUD / debug-HUD visibility during capture is governed by the TRACE_SHOW_* keys in the Debug section; --no-ghosts/--ghosts is a per-run override for the ghost flag. Game-HUD and debug-HUD visibility are set via those config keys (no CLI flag yet).

Audio: headless capture installs HeadlessSmpsAudioBackend, a true no-device SMPS backend that synthesizes the music for the recording but opens no audio device (no speaker output; works on machines with no audio hardware). Audio is captured at the engine’s 48 kHz synthesis rate and muxed as lossless FLAC, synced 1:1 with video.

Debug

BK2 playback controls are unbound by default and must be rebound in debug.playback before BK2 playback can be controlled from the keyboard.

KeyYAML pathTypeDefaultDescription
DEBUG_VIEW_ENABLEDdebug.flags.debugViewboolfalseEagerly initialise the debug overlay subsystem. Required for any runtime debug keys to function. Does not show anything on-screen until debug mode is activated.
EDITOR_ENABLEDdebug.flags.editorboolfalseAllow the experimental in-engine editor overlay to be entered from gameplay with Shift+Tab.
DEBUG_COLLISION_VIEW_ENABLEDdebug.flags.collisionViewboolfalseDraw collision sensor rays and solid object outlines over the scene at all times.
LIVE_REWIND_ENABLEDrewind.liveEnabledboolfalseEnable held-key rewind during ordinary live level play. Uses gameplay rewind snapshots, records live input while enabled, and presents reverse audio/fade state while held.
LIVE_REWIND_DETERMINISM_AUDITdebug.rewind.determinismAuditboolfalseAudit live-rewind determinism: re-simulates each completed rewind keyframe segment during live play and logs the first state divergence, pinpointing state that is missing from rewind capture. Disarms after the first divergence because replayed out-of-snapshot state cannot be rolled back.
LIVE_REWIND_TAPE_COAST_ENABLEDrewind.tapeCoastEnabledboolfalseEnable experimental live-rewind coast after releasing the rewind key. Disabled by default, so held rewind remains one step per visual frame. When enabled, reverse audio playback is resampled to match the current rewind speed (>1.0 pitches up, <1.0 plays slow-motion).
LIVE_REWIND_TAPE_COAST_MIN_STEPSrewind.tapeCoastMinStepsnumber0.25Initial rewind speed (in steps per visual frame) when the rewind key is first pressed. Values below 1.0 produce a slow-motion start: the speed controller’s fractional accumulator spreads each physics step across multiple visual frames. Speed then accelerates toward LIVE_REWIND_TAPE_COAST_MAX_STEPS. Used only when tape coast is enabled.
LIVE_REWIND_TAPE_COAST_ACCELERATIONrewind.tapeCoastAccelerationnumber0.25Optional tape-coast acceleration in rewind steps per held frame. Used only when tape coast is enabled.
LIVE_REWIND_TAPE_COAST_DECELERATIONrewind.tapeCoastDecelerationnumber0.5Optional tape-coast deceleration in rewind steps per released frame. Used only when tape coast is enabled.
LIVE_REWIND_TAPE_COAST_MAX_STEPSrewind.tapeCoastMaxStepsnumber4.0Maximum rewind steps per visual frame for optional tape-coast rewind. Values below 1.0 cap the rewind in slow-motion. Used only when tape coast is enabled.
REWIND_HISTORY_SECONDSrewind.historySecondsint60Seconds of live rewind keyframe and input history to retain. The effective retained window may be up to one keyframe interval longer so replay always has a complete keyframe-to-target input segment.
REWIND_AUDIO_HISTORY_LIMIT_TYPErewind.audioHistoryLimitTypestring"time"How the rewind audio PCM history ring is capped. "time" caps by REWIND_AUDIO_HISTORY_SECONDS; "size" caps by REWIND_AUDIO_HISTORY_SIZE_MB. Held rewind beyond the cap plays silence on develop (the audio-rewind feature branch engages the reverse resynthesizer instead).
REWIND_AUDIO_HISTORY_SECONDSrewind.audioHistorySecondsint60Seconds of stereo PCM history kept for held-rewind playback when REWIND_AUDIO_HISTORY_LIMIT_TYPE is "time".
REWIND_AUDIO_HISTORY_SIZE_MBrewind.audioHistorySizeMbint10Megabytes of stereo PCM history kept for held-rewind playback when REWIND_AUDIO_HISTORY_LIMIT_TYPE is "size". Stereo 16-bit at 48 kHz consumes ~192 KB/s, so 10 MB is roughly 54 s at that sample rate (~57 s at 44.1 kHz).
PLAYBACK_MOVIE_PATHdebug.playback.moviePathstring""Path to a BizHawk BK2 movie for playback debugging.
PLAYBACK_TOGGLE_KEYdebug.playback.toggleKeykey"" / unboundToggle playback mode.
PLAYBACK_LOAD_KEYdebug.playback.loadKeykey"" / unboundLoad/reload the BK2 movie.
PLAYBACK_PLAY_PAUSE_KEYdebug.playback.playPauseKeykey"" / unboundToggle playback play/pause.
PLAYBACK_STEP_BACK_KEYdebug.playback.stepBackKeykey"" / unboundStep the BK2 cursor backward by one frame.
PLAYBACK_STEP_FORWARD_KEYdebug.playback.stepForwardKeykey"" / unboundStep the BK2 cursor forward by one frame.
PLAYBACK_JUMP_BACK_KEYdebug.playback.jumpBackKeykey"" / unboundJump the BK2 cursor backward by a larger interval.
PLAYBACK_JUMP_FORWARD_KEYdebug.playback.jumpForwardKeykey"" / unboundJump the BK2 cursor forward by a larger interval.
PLAYBACK_FAST_RATE_KEYdebug.playback.fastRateKeykey"" / unboundCycle playback rate (1x/2x/4x/8x).
PLAYBACK_RESET_TO_START_KEYdebug.playback.resetToStartKeykey"" / unboundReset the BK2 cursor to PLAYBACK_START_OFFSET_FRAME.
PLAYBACK_START_OFFSET_FRAMEdebug.playback.startOffsetFrameint0Starting frame offset for BK2 playback.
TEST_MODE_ENABLEDdebug.testMode.enabledboolfalseReplace the master-title game-select with the Trace Test Mode picker that lists every trace in debug.testMode.catalogDir and plays the chosen trace back in the live engine. Dev-only. When true, DISPLAY_ASPECT is always forced to NATIVE_4_3 (320×224) regardless of its configured value — trace replay and test-mode runs are parity-critical and must always run at 320×224.
TRACE_CATALOG_DIRdebug.testMode.catalogDirstring"src/test/resources/traces"Directory scanned by TraceCatalog when TEST_MODE_ENABLED is true. Resolved against user.dir.
TRACE_SHOW_DESYNC_GHOSTSdebug.traceRender.showDesyncGhostsbooltrueIn Trace Test Mode and trace capture, render the desync ghost(s).
TRACE_SHOW_GAME_HUDdebug.traceRender.showGameHudbooltrueRender the game HUD (rings/score/time) during trace replay/capture.
TRACE_SHOW_DEBUG_HUDdebug.traceRender.showDebugHudboolfalseRender the debug HUD during trace replay/capture; individual panels follow the existing DebugOverlayToggle states.
DISCORD_RICH_PRESENCE_ENABLEDdiscord.enabledboolfalseOpt in to publishing OpenGGF menu/gameplay status through the local Discord desktop client. Disabled by default for privacy and no-ops when Discord is unavailable.
DISCORD_RICH_PRESENCE_SHOW_TIMERdiscord.showTimerbooltrueInclude the current level timer in Discord Rich Presence gameplay status when presence is enabled.
DISCORD_RICH_PRESENCE_SHOW_ZONEdiscord.showZonebooltrueInclude the current zone and act in Discord Rich Presence gameplay status when presence is enabled.

Level Editor (experimental)

The in-engine level editor (see EDITOR_ENABLED / debug.flags.editor) uses hardcoded key/mouse bindings — not configurable in config.yaml. While playing with EDITOR_ENABLED true, press Shift+Tab to toggle gameplay (playtest) ↔ editor.

InputAction
Shift+TabToggle editor / playtest mode
ArrowsMove world cursor / nudge selection
TabCycle focused region
SpaceApply primary action (place selected block)
EEyedrop block under cursor
LToggle active layer (FG / BG)
Enter / EscapeDescend / ascend the hierarchy
Ctrl+Z / Ctrl+Y / Ctrl+SUndo / Redo / Save
Left mouse (drag)Paint selected block (one undoable stroke)
Right mouseEyedrop hovered tile

Bindings live in EditorInputHandler and are not affected by the Key Bindings entries above.


Key Bindings

Key bindings accept any of the following formats:

FormatExampleNotes
GLFW numeric code81Traditional format
Numeric string"81"Same as above, as a string
Key name"Q"Human-readable, case-insensitive
Named key"SPACE", "ENTER", "F9"Special keys by name
Modifier key"LEFT_SHIFT", "RIGHT_CONTROL"Modifier keys
GLFW prefix"GLFW_KEY_Q"Full GLFW constant name (prefix stripped)

Invalid key names log a warning and fall back to the default binding for that key.

The tables below list each key’s name, default code, and the human-readable key name for the default.

Gameplay Controls

KeyYAML pathDefaultKey NameDescription
UPinput.player1.up265↑ ArrowLook up / enter tubes.
DOWNinput.player1.down264↓ ArrowCrouch / roll / spindash charge.
LEFTinput.player1.left263← ArrowMove left.
RIGHTinput.player1.right262→ ArrowMove right.
JUMPinput.player1.jump32SpaceJump / action button.
STARTinput.player1.start259BackspacePlayer 1 Start: ROM-accurate in-game pause (Game_paused / Pause_Loop). A press during level gameplay freezes the level update for the frame while the frame counter still advances; press again to resume. Distinct from PAUSE_KEY, which is the loop/timing-level pause that also halts audio.
PAUSE_KEYinput.pause257EnterPause / unpause the game.
FRAME_STEP_KEYdebug.keys.frameStep81QAdvance one frame while paused.
TRACE_REWIND_KEYdebug.traceRewind.key82RHold during visual Trace Test Mode replay to rewind deterministic engine state in real time, including reverse audio presentation and restored fade snapshots.
LIVE_REWIND_KEYrewind.liveKey82RHold during live level play to rewind deterministic gameplay state when LIVE_REWIND_ENABLED is true, including reverse audio presentation and restored fade snapshots.

Debug Navigation

KeyYAML pathDefaultKey NameDescription
NEXT_ACTdebug.keys.nextAct266PAGE_UPSkip to the next act within the current zone.
NEXT_ZONEdebug.keys.nextZone267PAGE_DOWNSkip to the first act of the next zone.
DEBUG_MODE_KEYdebug.keys.debugMode68DToggle free-fly debug movement mode (requires DEBUG_VIEW_ENABLED).
DEBUG_LAST_CHECKPOINT_KEYdebug.keys.lastCheckpoint67CTeleport the player to the most recently activated checkpoint.
LEVEL_SELECT_KEYdebug.keys.levelSelect298F9Open the level select screen at runtime.
TESTdebug.keys.test84TGeneric test button used during development.

Super Sonic / Emerald Debug

KeyYAML pathDefaultKey NameDescription
SUPER_SONIC_DEBUG_KEYdebug.keys.superSonic85UToggle Super Sonic transformation (requires DEBUG_VIEW_ENABLED and all emeralds).
GIVE_EMERALDS_KEYdebug.keys.giveEmeralds69EInstantly award all Chaos Emeralds (debug shortcut).

Special Stage Debug

These keys are only active while a Special Stage is running.

KeyYAML pathDefaultKey NameDescription
SPECIAL_STAGE_KEYdebug.keys.specialStage258TabEnter / exit Special Stage mode (debug).
SPECIAL_STAGE_COMPLETE_KEYdebug.keys.specialStageComplete269EndComplete the current Special Stage and award the emerald.
SPECIAL_STAGE_FAIL_KEYdebug.keys.specialStageFail261DeleteFail the current Special Stage without awarding the emerald.
SPECIAL_STAGE_SPRITE_DEBUG_KEYdebug.keys.specialStageSpriteDebug301F12Toggle the Special Stage sprite debug viewer.
SPECIAL_STAGE_PLANE_DEBUG_KEYdebug.keys.specialStagePlaneDebug292F3Cycle Special Stage plane visibility debug modes.

Test-only system properties

These properties are read by JVM system property lookups (-D<name>=<value> on the mvn or java command line) rather than config.yaml. They exist for diagnostic test runs only and must remain unset in CI.

PropertyTypePurpose
oggf.trace.hydrateBoolean (default false)Diagnostic hydrate switch for trace replay tests. When true AND the trace’s metadata.json declares a recorder version at or above 9.2-s2 (see TraceMetadata.nativePreludeMode()), the test harness snaps engine state to the recorded ROM frame-0 snapshot (player position-record buffer, sidekick CPU state, per-slot SST values) BEFORE the per-frame comparison loop begins. A run with this enabled is NOT a valid green replay: the switch masks the very divergences trace replay is designed to surface. Use only to isolate prelude bugs from gameplay-loop bugs. A WARN-level log line emits when the switch fires; TestTraceHydrateSwitchDefault is the CI guard that asserts the property is unset on master.
openggf.trace.s3k.probesBoolean (default false)Enables verbose S3K-specific trace replay probes (cnz cylinder, aiz boundary, etc.). Diagnostic only.

Example config.yaml

The following is the bundled default src/main/resources/config.yaml:

# OpenGGF configuration — grouped and documented.
# Indentation is significant (YAML). This file is rewritten cleanly on save.

# ── Display ──
display:
  aspect: "NATIVE_4_3"   # Display aspect preset; resolves screen pixel width, height stays 224
  windowAutosize: true   # Derive the window size from the aspect preset at the 2x baseline
  shaderLibraryRoot: shaders   # Root directory scanned for user display shaders
  shaderSelection: "OFF"   # Last selected display shader: OFF or a root-relative forward-slash path
  shaderNextKey: RIGHT_BRACKET   # Runtime key to advance to the next display shader
  shaderPreviousKey: LEFT_BRACKET   # Runtime key to move to the previous display shader
  shaderPickerKey: BACKSLASH   # Runtime key to open the searchable display shader picker
  shaderDefaultPhase: PRESENTATION   # Fallback render phase for standalone display shaders
  deadzoneMode: "PROPORTIONAL"   # Camera horizontal deadzone behaviour on wide screens
  colorProfile: "RAW_RGB"   # Display-only color profile for Mega Drive palette presentation
  colorProfileToggleKey: V   # Runtime key to cycle the display color profile
  fps: 60   # Frames per second to render (changes game speed)

# ── Input ──
input:
  pause: ENTER   # Toggle pause
  player1:
    up: UP   # Player 1: look up
    down: DOWN   # Player 1: crouch/roll
    left: LEFT   # Player 1: move left
    right: RIGHT   # Player 1: move right
    jump: SPACE   # Player 1: jump
  player2:
    up: I   # Player 2: look up
    down: K   # Player 2: crouch/roll
    left: J   # Player 2: move left
    right: L   # Player 2: move right
    jump: RIGHT_SHIFT   # Player 2: jump
    start: ENTER   # Player 2: start

# ── Audio ──
audio:
  enabled: true   # Enable music and SFX
  region: "NTSC"   # Region for audio timing
  dacInterpolate: true   # DAC interpolation (smoother sound)
  internalRateOutput: false   # Output audio at the internal YM2612 rate (~53kHz)
  psgNoiseShiftEveryToggle: true   # PSG noise LFSR clock mode: true=shift on every toggle (MAME), false=positive edges (GPGX)
  fm6DacOff: true   # Mute FM6 when a note plays on it while DAC is enabled (SMPSPlay parity hack)

# ── Characters ──
characters:
  main: "sonic"   # Sprite code of the main playable character
  sidekick: "tails"   # Sprite code of the CPU sidekick; empty string disables the sidekick
  dataSelectExtraCombos: ""   # Semicolon-separated extra player combos for the data select screen

# ── ROMs ──
roms:
  sonic1: "Sonic The Hedgehog (W) (REV01) [!].gen"   # Filename of the Sonic 1 ROM
  sonic2: "Sonic The Hedgehog 2 (W) (REV01) [!].gen"   # Filename of the Sonic 2 ROM
  sonic3k: "Sonic and Knuckles & Sonic 3 (W) [!].gen"   # Filename of the Sonic 3&K ROM
  default: "s2"   # Which game to load by default

# ── Startup ──
startup:
  titleScreen: true   # Show the title screen on startup
  masterTitleScreen: true   # Show the master (game-selection) title screen on startup
  legalDisclaimer: true   # Show the legal disclaimer screen before the master title screen

# ── Rewind (live) ──
rewind:
  liveEnabled: false   # Enable held-key rewind during ordinary live play
  liveKey: R   # Key held to rewind during live play
  tapeCoastEnabled: false   # Continue rewinding with a decelerating tape-coast after key release
  tapeCoastAcceleration: 0.25   # Per-tick speed increase while tape-coast is held
  tapeCoastDeceleration: 0.5   # Per-tick speed decrease after release
  tapeCoastMaxSteps: 4.0   # Maximum rewind steps per tick
  tapeCoastMinSteps: 0.25   # Minimum rewind steps per tick; below 1.0 gives slow-motion rewind
  historySeconds: 60   # Seconds of live rewind keyframe and input history to retain
  audioHistoryLimitType: "time"   # How the rewind audio PCM history ring is sized
  audioHistorySeconds: 60   # Seconds of PCM history kept when audioHistoryLimitType=time
  audioHistorySizeMb: 10   # Megabytes of PCM history kept when audioHistoryLimitType=size

# ── Cross-Game ──
crossGame:
  enabled: false   # Enable cross-game feature donation (e.g. S2 sprites in S1)
  source: "s2"   # Donor game for cross-game features

# ── Launch Profiles ──
# Per-game launch defaults edited from the master title screen.
launch:
  s1:
    rewind: false   # Default Sonic 1 launch profile: enable live rewind
    crossGameSource: "off"   # Default Sonic 1 launch profile: cross-game donor
    debugTools: false   # Default Sonic 1 launch profile: enable debug tools
    aspect: "global"   # Default Sonic 1 launch profile: display aspect override
    mainCharacter: "sonic"   # Default Sonic 1 launch profile: main character
    sidekick: "none"   # Default Sonic 1 launch profile: sidekick character
  s2:
    rewind: false   # Default Sonic 2 launch profile: enable live rewind
    crossGameSource: "off"   # Default Sonic 2 launch profile: cross-game donor
    debugTools: false   # Default Sonic 2 launch profile: enable debug tools
    aspect: "global"   # Default Sonic 2 launch profile: display aspect override
    mainCharacter: "sonic"   # Default Sonic 2 launch profile: main character
    sidekick: "tails"   # Default Sonic 2 launch profile: sidekick character
  s3k:
    rewind: false   # Default Sonic 3&K launch profile: enable live rewind
    crossGameSource: "off"   # Default Sonic 3&K launch profile: cross-game donor
    debugTools: false   # Default Sonic 3&K launch profile: enable debug tools
    aspect: "global"   # Default Sonic 3&K launch profile: display aspect override
    mainCharacter: "sonic"   # Default Sonic 3&K launch profile: main character
    sidekick: "tails"   # Default Sonic 3&K launch profile: sidekick character

# ── Discord Rich Presence ──
discord:
  enabled: false   # Enable Discord Rich Presence updates
  showTimer: true   # Show the level timer in Rich Presence
  showZone: true   # Show the zone and act in Rich Presence

# ════════════════════════════════════════════
#  DEBUG  (developer tooling — safe to ignore for normal play)
# ════════════════════════════════════════════
debug:
  flags:
    debugView: false   # Enable the debug overlay subsystem; visible HUD starts hidden until toggled
    editor: false   # Allow entering the level editor from gameplay
    collisionView: false   # Draw the collision overlay
  keys:
    test: T   # Debug-only test button
    nextAct: PAGE_UP   # Advance to the next act
    nextZone: PAGE_DOWN   # Advance to the next zone
    debugMode: D   # Toggle debug movement mode
    frameStep: Q   # Step forward one frame while paused
    lastCheckpoint: C   # Teleport to the last checkpoint
    levelSelect: F9   # Open the level select screen
    superSonic: U   # Toggle Super Sonic debug mode
    giveEmeralds: E   # Give all chaos emeralds
    specialStage: TAB   # Toggle special stage mode
    specialStageComplete: END   # Complete the special stage with an emerald
    specialStageFail: DELETE   # Fail the special stage
    specialStageSpriteDebug: F12   # Toggle the special stage sprite debug viewer
    specialStagePlaneDebug: F3   # Cycle special stage plane visibility debug modes
  startup:
    levelSelectOnStartup: false   # Open Level Select on startup instead of loading the first zone
    s3kSkipIntros: false   # Skip S3K zone intro sequences (AIZ biplane, etc.)
  playback:
    moviePath: ""   # Path to a BizHawk BK2 movie for playback debugging
    toggleKey: ""   # Toggle playback mode
    loadKey: ""   # Load/reload the BK2 movie
    playPauseKey: ""   # Toggle playback play/pause
    stepBackKey: ""   # Step the cursor back one frame
    stepForwardKey: ""   # Step the cursor forward one frame
    jumpBackKey: ""   # Jump the cursor back by a larger interval
    jumpForwardKey: ""   # Jump the cursor forward by a larger interval
    fastRateKey: ""   # Cycle playback rate (1x/2x/4x/8x)
    resetToStartKey: ""   # Reset the cursor to the start offset
    startOffsetFrame: 0   # Starting frame offset for BK2 playback
  traceRewind:
    key: R   # Key held in Trace Test Mode to rewind deterministic engine state
  rewind:
    determinismAudit: false   # Re-simulate each completed live-rewind keyframe segment and log the first divergence
  traceRender:
    showDesyncGhosts: true   # Render desync ghosts in Trace Test Mode and trace capture
    showGameHud: true   # Render the game HUD during trace replay/capture
    showDebugHud: false   # Render the debug HUD during trace replay/capture
  testMode:
    enabled: false   # Replace the master title with the trace picker (dev-only)
    catalogDir: "src/test/resources/traces"   # Directory scanned for traces when test mode is enabled
  crossGame:
    s1DataSelectImageGenOverride: false   # Force regeneration of the S1 data-select image cache
    s2DataSelectImageGenOverride: false   # Force regeneration of the S2 data-select image cache
    s1DataSelectImageCoordLogKey: APOSTROPHE   # Log the current camera position as an S1 data-select preview override
  window:
    width: 640   # DEPRECATED manual window width; used only when display.windowAutosize=false
    height: 448   # DEPRECATED manual window height; used only when display.windowAutosize=false
    scale: 1.0   # DEPRECATED AWT debug-viewer scale factor