Gamepad Enforcer · Developer Guide

Build once. Enforce everywhere.

This guide defines the shared Gamepad Enforcer development contract for GE-supported games, GE-Ink, GE-Overlay, GEDU, GE HUD, GE Dump diagnostics, and GE Cursor. It is written as a self-contained implementation reference for patching shared GE behavior centrally instead of repeatedly patching each game.

Self-contained HTML Audience: GE developers Line endings: CRLF preferred in source patches No stubs · No hard-coded dev hosts

1. Purpose and Non-Negotiables

Gamepad Enforcer is the shared input, overlay, cursor, diagnostic, and support layer for Puzzlum/GE-supported browser games. A GE fix should normally land in shared GE code, not in a single game, whenever the behavior is expected across all supported games.

Centralize shared behavior

Overlay toggles, face-button labeling, GE HUD press feedback, cursor axis handling, and GE-Ink loading rules belong in shared GE support modules unless a game truly has a unique rule.

Alias-first input

Never assume raw browser button indexes or raw axes are consistent across controller families. Gameplay and cursor movement consume GE-resolved aliases.

No obsolete routes

GE-supported games use direct public paths and JavaScript GE-Ink. Do not route game scripts, assets, maps, bundles, or loading through obsolete ink.php.

Patch rule: preserve paths, preserve user data, use Windows newlines and tabs for project source patches, and do not ship stubs. A “valid zip” means all modified files are present, path-correct, and usable as-is.

2. Module Map and Supported Games

ModuleRoleDeveloper Contract
Gamepad EnforcerInput runtime, aliases, state, chords, combos, cursor source, shared events.Own raw input normalization and expose stable resolved state through window.ge.
GE-InkSafe asset/data loader and converter.Expose window.ink, use direct public paths, convert CSV to JSON by default, only convert CSV to PNG with the png flag.
GE-OverlayGE-owned controller/status overlay.Read window.ge runtime state; never depend on per-game input internals.
GE HUDShared clickable/toggleable HUD surface for GE features such as Overlay, Rankings, Cursor controls, and diagnostics.Use ZIndex-aware hitboxes, consistent bump/outline feedback, and consume inputs correctly.
GE CursorMouse/gamepad virtual cursor for GE-enabled games.Use GE-resolved axis aliases, top-layer rendering, hover feedback, and magnitude-aware motion.
GE DumpDiagnostics snapshot/export for gamepad, overlay, HUD, cursor, and Ink state.Capture current runtime state without mutating gameplay; output copyable/downloadable JSON for debugging.
GEDUGamepad Enforcer Development Utility.Show raw diagnostic tables immediately from navigator.getGamepads(); config/Auto detection must be explicit and non-destructive.

GE-supported games

Supported project directories are Desert-Storm-WMD-Sweeper, Dungeon, Mineshaft/2D, Mineshaft/3D, Overworld, and Roe2. Releases include official and alpha.

Use game-specific adapters only for game-specific semantics. For example, DSWS may define hex-hover drawing rules, while GE Cursor owns axis mapping, speed gain, and movement smoothing.

3. Paths, Bootstrapping, and Safe Roots

Keep a strict difference between repository/filesystem paths and browser runtime URLs.

PurposeFilesystem / Repo PathRuntime URL
Shared aliases, chords, combos/public/Gamepad-Enforcer/GE//Gamepad-Enforcer/GE/
Controller configs/public/Gamepad-Enforcer/Gamepads//Gamepad-Enforcer/Gamepads/
Shared JS/public/Gamepad-Enforcer/js//Gamepad-Enforcer/js/
GE-supported game assets/public/{release}/{project}/assets/…/{release}/{project}/assets/…
Catalog support scripts/{flavor}-scripts/Catalog/Server-side support only; do not expose arbitrary filesystem paths.
Runtime URLs must not include /public. /public describes files below the document root, not browser-visible route text.

Boot order

Support bootstrapge-support.php once
GE-Inkwindow.ink stable
GE runtimewindow.ge stable
HUD / Overlay / Cursorshared UI modules
Game adapterconsume resolved state
<!-- Runtime example: no /public in browser URLs. -->
<script src="/Gamepad-Enforcer/js/ge.js"></script>
<script src="/Gamepad-Enforcer/js/gamepad-input.js"></script>
<script src="/Gamepad-Enforcer/js/ge-overlay.js"></script>

Safe roots

  • JavaScript-based file manipulation is limited to ${ink.origin}/Gamepad-Enforcer/ and ${ink.origin}/${ink.release_dir}/${ink.project_dir}/.
  • Extra allowlisted roots such as /Gamepad-Enforcer/, /GE/, and /Gamepads/ require ge_paths truthy. Default is false.
  • Do not hard-code local vhosts, private GoDaddy paths, or development-only hostnames.

4. Runtime State Contract

GE-owned UI reads the GE runtime. GE-supported games consume the resolved GE state; they do not reinterpret raw browser input on their own.

window.ge = window.ge || {
	state: [],              // per-slot resolved runtime state
	raw: [],                // raw sampled gamepad state for diagnostics
	config: {},             // loaded controller mappings/configs
	aliases: {},            // semantic alias tables
	chords: {},             // chord definitions such as SS
	combos: {},             // combo definitions such as Full-Hold
	hud: {},                // GE HUD surfaces and hitboxes
	overlay: {},            // GE Overlay model
	cursor: {},             // GE Cursor state
	dump: {}                // GE Dump diagnostics helpers
};

Compatibility shape

Some older code may expose both window.ge.* and window.ge.GE.*. New code should normalize to a single runtime object early, then read through stable helper methods.

State ownership

Only GE should own raw polling, alias resolution, combo timing, overlay activation, and GE Cursor axis interpretation. Games own gameplay outcomes.

Polling cadence

GE/GEDU diagnostic polling should target 20fps, with refresh delay clamped to a 50ms minimum. Render animations may use the browser frame loop, but raw input state should not be sampled by multiple unsynchronized loops.

5. Input Pipeline

The input pipeline turns unstable browser/gamepad data into stable, semantic game actions.

Raw browser inputnavigator.getGamepads()
Slot statelast-known raw state
Controller configfamily + mappings
Aliases / chords / combossemantic labels
Consumersgame, HUD, overlay, cursor

Raw state rules

  • When a gamepad slot timestamp freezes, maintain the last known raw input state for that slot rather than zeroing it.
  • Raw axes are not assigned consistently across all controller types. Use resolved aliases/config mappings for gameplay and cursor movement.
  • Gamepad Faces map through the alias chain, not raw browser input indexes.
  • Raw A, B, X, Y labels are Xbox-style by default. Nintendo-style labels are selected only when the config/device indicates Nintendo/Switch/Joy-Con/8BitDo Nintendo layout or face labels are in Nintendo order.

Labeled Input Processing

Labeled Input Processing should be its own class. The class receives raw slot samples plus the selected controller config and emits stable labeled values such as Face South, Left Stick X, Overlay Toggle, Cursor Click, or a game-specific action alias.

class LabeledInputProcessor {
	constructor({ aliases, chords, combos, config }) {
		this.aliases = aliases;
		this.chords = chords;
		this.combos = combos;
		this.config = config;
		this.previous = new Map();
	}

	processSlot(slotIndex, rawSample, nowMs) {
		const mapped = this.applyControllerConfig(rawSample);
		const labels = this.applyAliases(mapped);
		const chords = this.applyChords(labels, nowMs);
		const combos = this.applyCombos(labels, chords, nowMs);

		return {
			slotIndex,
			timestamp: rawSample.timestamp,
			mapped,
			labels,
			chords,
			combos
		};
	}
}

6. Chords, Combos, and Repeats

GE combos are semantic. Do not encode raw buttons into game logic.

NameMeaningNotes
SSStart + Select chord.Used as a shared foundation for GE feature toggles.
Full-HoldHeld repeat combo.Usually defined with Repeats: Held and a configured Delay.
SS: Full-HoldStart + Select held chord/combo.Should toggle GE Overlay on and off regardless of current active slot.
Series-Tap: 1, Series-Tap: 2, Series-Tap: 3Released count over the given delay time.The numeric suffix is the Repeats label property.
Combo matching should preserve intent across controller layouts. A player should not have to know whether their device is exposing Xbox, Sony, Nintendo, or 8BitDo face labels internally.

7. GE Overlay

GE Overlay is GE-owned UI. It displays controller state and GE feature status by reading window.ge, not by scraping game input handlers.

Responsibilities

  • Show active gamepad slots, resolved aliases, pressed/held/released states, and meaningful GE feature toggles.
  • Display the actual physical controller-based face symbols for the selected family/layout.
  • Do not display the family name inside face activations. Show the symbol and the value.
  • For face buttons and D-pad directions, render the label above the value. Sticks may use a stick-specific visual layout.
  • Toggle through the shared combo path: Overlay Toggle → SS: Full-Hold → Released when that mapping is configured.
  • SS: Full-Hold must toggle the overlay both on and off, regardless of current slot.

Controller family display rules

FamilyFace symbolsSelection rule
Xbox/defaultA, B, X, YDefault raw face-label interpretation.
Sony, , , Selected by config/device family or explicit labels.
NintendoB, A, Y, XOnly selected when config/device indicates Nintendo/Switch/Joy-Con/8BitDo Nintendo-style layout or labels are in Nintendo order.

Overlay visual contract

  • GE Overlay and Rankings must use the same press/bump feedback on hitbox click/release.
  • GE Overlay and Rankings must use the same active/brighter outline behavior when toggled on or open.
  • Overlay hitboxes participate in the shared GE HUD ZIndex hit-test, not in an independent click stack.
  • Overlay should remain readable when a game modal consumes gameplay input, unless that modal explicitly hides GE UI.

8. GE HUD Features

GE HUD is the shared on-screen control surface for GE features such as Overlay, Rankings, Cursor, Dump, and diagnostics.

Hitbox rules

  • Every GE HUD hitbox has a ZIndex and participates in topmost-first hit testing.
  • Only the winning topmost hitbox should receive a pointer/gamepad activation for a given press.
  • Click/release feedback must be consistent across HUD items: bump on press/release, brighter outline when active/open.
  • The first HUD click must be fully actionable. Do not require a warm-up click to arm a hitbox.
  • HUD hitbox geometry updates must happen before input dispatch for the current frame/tick.

Input consumption

Party panels, battle modes, menus, and modal game screens should consume regular mouse, keyboard, and gamepad input. They should still allow inputs that activate GE HUD items unless the game intentionally disables GE UI.
function dispatchPointerPress(pointer) {
	const hudHit = ge.hud.hitTest(pointer, { topmostOnly: true });

	if (hudHit) {
		ge.hud.activate(hudHit, pointer);
		return { consumedBy: 'GE HUD', allowGame: false };
	}

	if (game.modalConsumesInput()) {
		return { consumedBy: 'Game Modal', allowGame: false };
	}

	return game.dispatchPointerPress(pointer);
}

HUD feature registry

FeatureTypical HUD BehaviorShared Requirements
OverlayToggle display of GE Overlay.Use shared active outline and bump feedback.
RankingsToggle scoreboard/rankings panel.Must not miss the first click; visual feedback matches Overlay.
CursorEnable/disable virtual cursor, cursor lock, or cursor mode.Runs through GE Cursor state and shared hit-testing.
DumpOpen/copy/export diagnostic snapshot.Must not mutate gameplay or clear current input state.
DiagnosticsOpen GEDU-like runtime panel where available.Read-only by default; explicit changes only.

9. GE Cursor

GE Cursor is the shared virtual cursor system for mouse/gamepad-supported UI and game surfaces. It must feel consistent across supported games while allowing game-specific hover rendering.

Core rules

  • Gamepad cursor motion uses GE-resolved stick aliases/config mappings, never fixed raw axes.
  • Mouse-based cursor motion and gamepad-based cursor motion update the same cursor state object.
  • Cursor render should sit above game canvas layers and below deliberate modal overlays when those overlays own input.
  • Cursor hover hit testing honors GE HUD ZIndex first, then game UI, then game world.
  • Cursor click uses resolved labels such as Cursor Click or a mapped face alias, not raw button[0].

Magnitude-aware movement

Stick motion should throttle based on inverse stick magnitude while applying a configurable gain. Small stick values move precisely; strong stick values move quickly and smoothly. This system belongs in GE Cursor itself, not in one game adapter.

function updateGeCursorFromStick(cursor, stick, dtMs, config) {
	const deadzone = config.deadzone ?? 0.15;
	const gain = config.cursorGain ?? 1.0;
	const maxSpeed = config.cursorMaxSpeed ?? 1200;
	const magnitude = Math.hypot(stick.x, stick.y);

	if (magnitude < deadzone) {
		cursor.velocity.x = 0;
		cursor.velocity.y = 0;
		return cursor;
	}

	const normalized = Math.min(1, (magnitude - deadzone) / (1 - deadzone));
	const speed = maxSpeed * gain * normalized;
	const nx = stick.x / magnitude;
	const ny = stick.y / magnitude;

	cursor.x += nx * speed * (dtMs / 1000);
	cursor.y += ny * speed * (dtMs / 1000);
	cursor.x = clamp(cursor.x, 0, cursor.bounds.width - 1);
	cursor.y = clamp(cursor.y, 0, cursor.bounds.height - 1);
	return cursor;
}

Game-specific hover responsibilities

GameGE Cursor Shared ResponsibilityGame Adapter Responsibility
DSWSResolved stick axes, movement gain, pointer state, click dispatch.Redraw stable board portion per honeycomb update; draw animated tiles per refresh; draw hexagonal outline for hovered tile.
DungeonResolved cursor movement and HUD hit testing.Respect game panels that consume input while allowing GE HUD activations.
OverworldShared gamepad cursor state and click labels.Project cursor into viewport/world and handle OSK/game-specific UI surfaces.
Roe2Shared gain/deadzone handling.Provide per-game speed defaults only if needed; do not bypass GE Cursor motion.

10. GE Dump Diagnostics

GE Dump creates a structured diagnostic snapshot for debugging input mapping, overlay state, HUD hitboxes, GE Cursor movement, and GE-Ink loading without disturbing gameplay.

Dump payload

FieldContentNotes
metaTimestamp, URL, release, project, user agent, GE versions if available.Do not include private filesystem roots.
gamepadsRaw and resolved slot state, timestamps, mappings, controller ids.Preserve last-known state when browser timestamps stall.
aliasesLoaded aliases/chords/combos and active resolution result.Useful for face-family and combo bugs.
overlayVisible/open state, active slot, displayed labels, toggle path.Validate no family name leaks into face activation display.
hudRegistered hitboxes, ZIndex order, active/open states.Diagnose first-click misses and overlapping controls.
cursorCursor position, source, velocity, gain/deadzone, hover target.Diagnose slow/fast/stale cursor motion.
inkGE-Ink origin, release/project, ge_paths, requested asset paths.Do not expose private root paths.
gameCurrent game adapter name and input-consumption mode.Read-only snapshot; avoid save-state mutation.

Reference helper

function createGeDump() {
	const ge = window.ge || {};
	const ink = window.ink || {};

	return {
		meta: {
			createdAt: new Date().toISOString(),
			location: String(location.pathname + location.search),
			userAgent: navigator.userAgent
		},
		gamepads: {
			raw: ge.raw || [],
			state: ge.state || []
		},
		aliases: {
			aliases: ge.aliases || {},
			chords: ge.chords || {},
			combos: ge.combos || {}
		},
		overlay: ge.overlay || {},
		hud: ge.hud || {},
		cursor: ge.cursor || {},
		ink: {
			origin: ink.origin,
			release_dir: ink.release_dir,
			project_dir: ink.project_dir,
			ge_paths: !!ink.ge_paths
		},
		game: window.geGameAdapter?.diagnostics?.() || null
	};
}
GE Dump output may be copied, saved, or attached to bug reports. Scrub private filesystem roots and authentication details. Runtime URLs and public asset paths are acceptable.

11. GE-Ink Integration

GE-Ink is the shared safe loader/converter for GE-supported games. It should expose window.ink reliably and avoid overwriting GE-Ink-derived server globals.

Data conversion rules

  • .csv files are comma-separated value files.
  • GE-Ink should directly convert CSV to JSON unless plain or raw flags are present.
  • CSV should convert to PNG only when the png flag is set.
  • Flags do not need assigned values. ?png and ?png=1 should both be acceptable.
  • Every image produced by GE-Ink must render onto a transparent alpha base.

Asset path expansion

// Request string used by a game or support module:
assets/textures/json/WATR_004_24.json?png=1&frame=0&w=8&h=8&style=cover

// GE-Ink expands according to origin/release/project rules:
${ink.origin}/${ink.release_dir}/${ink.project_dir}/assets/textures/json/WATR_004_24.json?png=1&frame=0&w=8&h=8&style=cover

Obsolete route policy

GE-supported games must not use ink.php for scripts, assets, maps, bundles, or game loading. ink.php may exist for older projects, but not as the GE-supported game loading path.

12. GEDU Developer Utility

GEDU is the development utility for inspecting and assigning gamepad mappings without hiding raw browser behavior.

GEDU raw table rules

  • Refresh the raw diagnostic table immediately from navigator.getGamepads().
  • Do not wait to load /Gamepads/<controller>.json before showing raw rows.
  • Auto detection stays behind an explicit Auto button.
  • The table starts with raw input rows, then assignable types and labels.
  • Raw polling owns raw table construction. Layout/config application must not re-trigger polling.
  • Diagnostics refresh should not reapply config/layout or dispatch layout/config events.

Duplicate fetch prevention

Use a shared cached JSON getter for aliases, defaults, chords, combos, and controller configs. Do not let Main.js, gamepad-input.js, GamepadConfigSelect.js, GamepadOverlay.js, and helpers independently fetch the same GE JSON tables.

13. Game Integration Contract

A GE-supported game integrates by consuming the shared GE state and declaring its game-specific action meanings.

Adapter shape

window.geGameAdapter = {
	name: 'Dungeon',
	projectDir: 'Dungeon',
	releaseDir: 'alpha',

	consumeGeState(state, ge) {
		// Read resolved aliases and combos only.
		// Do not sample navigator.getGamepads() here.
	},

	consumeHudAction(action, ge) {
		// Handle GE HUD feature actions or return false.
		return false;
	},

	diagnostics() {
		return {
			modalConsumesInput: this.modalConsumesInput?.() || false,
			activePanel: this.activePanel || null
		};
	}
};

Integration checklist

  • Load GE support once per page refresh for GE-supported games, GEDU, and Gamepad-Enforcer.
  • Use runtime URLs without /public.
  • Use direct public paths / JS GE-Ink, not obsolete ink.php.
  • Read window.ge.state[slot] for gameplay input.
  • Route face buttons through alias mappings and family display rules.
  • Let GE HUD hitboxes receive their activation before modal gameplay input consumes the event.
  • Use GE Cursor for gamepad cursor motion; implement only game-specific hover/render behavior in the adapter.
  • Expose a safe diagnostics object for GE Dump.

14. Per-Game Notes

GameImportant GE NotesCommon Regression Tests
Desert Storm WMD SweeperGE Cursor redraws stable board portions per honeycomb update; animated tiles and hovered hex outline draw per refresh.Gamepad cursor smoothness, gain, hover hex outline, GE HUD first-click toggle.
DungeonParty Panel and Battle Mode consume regular inputs but allow GE HUD item activation. Use conditions/data-driven game logic where applicable.Battle action selection, Auto-Walk, HUD/Cursor visibility, modal input consumption.
Mineshaft 2DUse shared GE support and resolved aliases. Avoid per-game raw face/axis assumptions.Overlay toggle, cursor click, mapped movement.
Mineshaft 3D3D camera/movement may have specialized action meanings, but should still consume resolved labels.Stick axes, face labels, overlay display.
OverworldGamepad cursor, OSK, viewport/world projection, and cache safety need careful layering.Cursor on top canvas, OSK toggle, player/camera control, GE-Ink alpha images.
Roe2Cursor speed must use shared GE Cursor gain/deadzone rather than per-game raw-axis speed hacks.Cursor not too fast, overlay labels, combo handling.

15. Troubleshooting

SymptomLikely CauseFix
Overlay lights up multiple face buttons per press.Raw indexes or family labels are being mixed with alias resolution.Route face activations through one resolved alias chain and render only the selected physical symbol/value.
Rankings bumps but does not toggle on first click.Hitbox geometry or activation state updates after dispatch.Update HUD hitbox registry before input dispatch; hit-test topmost ZIndex first.
GE Overlay has active outline but Rankings does not.Feature-specific visual code diverged.Move bump/outline state into shared GE HUD visual contract.
Gamepad cursor is low polling rate or choppy.Cursor is tied to raw polling or fixed raw axes.Use GE Cursor with resolved stick aliases, magnitude-aware motion, and a render loop that interpolates state.
Cursor is too fast in Roe2.Per-game speed hack bypasses shared gain/deadzone.Tune GE Cursor cursorGain and cursorMaxSpeed per adapter defaults without bypassing shared movement.
GEDU repeatedly reloads defaults/config JSON.Multiple modules independently fetch shared GE JSON files.Use shared cached json_get(); centralize aliases/chords/combos loading.
GE-Ink returns an image for CSV unexpectedly.png conversion path triggered incorrectly.CSV converts to JSON by default; only PNG when png flag is present.
Runtime asset path 404s with /public.Filesystem path used as browser URL.Remove /public from runtime URLs; keep it only in server/filesystem references.

16. Smoke Tests and Release Checks

Shared GE smoke tests

  • Connect an Xbox-style controller; confirm raw A/B/X/Y displays as Xbox by default.
  • Connect Nintendo/Switch/Joy-Con/8BitDo Nintendo-style layout; confirm face labels display in Nintendo order only when config/device indicates it.
  • Hold Start + Select; confirm SS: Full-Hold toggles GE Overlay on and off regardless of slot.
  • Click/toggle GE Overlay and Rankings; confirm identical bump and active/brighter outline behavior.
  • Click each GE HUD item from a cold page load; confirm no first-click misses.
  • Move GE Cursor with mouse and gamepad; confirm both update the same cursor state and topmost hit target.
  • Open GE Dump; confirm payload contains gamepads, aliases, overlay, HUD, cursor, Ink, and game diagnostics without private filesystem roots.
  • Open GEDU; confirm raw table appears immediately before Auto/config selection.

Packaging rules

  • Use path-preserving deltas. Modified files must land at their real project paths.
  • Include obsolete-file removal scripts when replacing duplicate GE files. Keep the new /public/Gamepad-Enforcer/js/ and PHP boot paths intact.
  • Do not delete rankings, saves, GE state, or other non-image localStorage tables when clearing stale image caches.
  • Zip artifacts must be valid and complete. No placeholder files, stubs, or “TODO” implementations.

17. Coding Style and Patch Discipline

Formatting

Use Windows newlines (CRLF) and tabs for indentation in project source patches. Preserve existing local style when editing legacy files.

Naming

When applying project ucase behavior, uppercase the first character at each leading alphanumeric token boundary, not only the first character of the whole string.

Patch discipline

  • Prefer narrow shared fixes over duplicate per-game patches.
  • Do not rewrite unrelated game systems to fix a GE support bug.
  • Do not let diagnostics mutate gameplay state.
  • Keep raw input, resolved input, rendered overlay, and game actions as separate layers.
  • When fixing an input regression, test at least one Xbox-style mapping and one non-Xbox family mapping.

18. Glossary

TermDefinition
AliasA semantic input label resolved from raw controller state and config, such as Face South or Cursor Click.
ChordA simultaneous input combination, such as SS for Start + Select.
ComboA timed or repeated semantic input sequence, such as Full-Hold or Series-Tap.
GE HUDShared on-screen GE feature controls and hitboxes.
GE OverlayGE-owned controller/status overlay reading window.ge.
GE CursorShared virtual cursor controlled by mouse or resolved gamepad input.
GE DumpStructured diagnostics snapshot/export for GE runtime debugging.
GEDUGamepad Enforcer Development Utility for raw diagnostics and mapping.
Runtime URLBrowser-visible path. It never includes /public.
Filesystem pathServer/repository path. It may include /public under the document root.