Techmino is a cross-platform tetromino stacking game built with Lua and LÖVE 11.5. It combines many single-player rule sets with replays/TAS, custom games, localization, configurable presentation and controls, AI players, and online rooms/battles.
conf.luaconfigures LÖVE, platform/window behavior, enabled engine modules, and theTechminosave identity.main.luais the application bootstrap.main.lualoadsZframework, which owns the LÖVE event loop and exposes global services such asSCN,TASK,FILE,HTTP,WS, and graphics/audio helpers. Bootstrap then loads shared game tables/functions, assets, persisted state, modes, backgrounds, and scenes.- UI actions call
loadGame(mode, quickPlay, net)inparts/gameFuncs.lua. This resolvesMODES[mode], populatesGAME, and transitions throughSCNtogameornet_game. - Player construction in
parts/player/init.luaresolves configuration in this precedence order:GAME.modeEnv->GAME.setting-> globalSETTING->parts/player/gameEnv0.luadefaults. It then merges the selectedparts/eventsets/hooks and initializes randomizers/tasks. - Input flows from
Zframeworkto the current scene, then throughKEY_MAP/virtual keys to player methods. Each frame updates scene state, players, and cooperativeTASKcoroutines; drawing delegates to players and scene widgets. gameOver/trySaveupdate ranks, records, statistics, and optional compressed replay data. Online flows use JSON over HTTP/WebSocket inparts/net.lua, feeding room state and remote player streams.- Modes, scenes, backgrounds, and shaders are filesystem-discovered after
FILE.isSafechecks. Keep filenames, registry IDs, and returned module tables consistent so discovery succeeds.
| Path | Purpose |
|---|---|
parts/scenes/ |
UI/application states. Scene modules return callbacks plus optional declarative widgetList. |
parts/modes/ |
Declarative mode definitions (env, scoring, comparison, ranks). |
parts/eventsets/ |
Reusable gameplay hooks selected by env.eventSet. |
parts/player/ |
Player construction, simulation, rendering, and piece sequence generators. |
parts/language/ |
Locale tables, dictionaries, and localized manuals. |
parts/backgrounds/, parts/shaders/ |
Auto-discovered visual modules and GLSL shaders. |
media/ |
Shipped images, music, effects, samples, and voice packs. Preserve third-party attribution. |
Zframework/ |
Bundled legacy LÖVE framework and global runtime services; modify conservatively. |
.github/build/ |
Platform-specific packaging resources, icons, and templates. |
.github/actions/ |
Local composite actions used by CI. |
LÖVE 11.5 must be installed and available as love.
# Run from the repository root
love .
# Run the built-in mode-loading smoke scan
love . --test
# CI's headless form, using its downloaded AppImage and packaged artifact
xvfb-run --auto-servernum ./love.AppImage ./core.love --testThere is no repository-defined Makefile, dependency-install script, formatter command, or lint command. .github/workflows/main.yml is the authoritative build/package workflow. It packages media/, parts/, Zframework/, conf.lua, main.lua, version.lua, legals.md, and license.txt into core.love, then produces Android, Linux, web, and Windows artifacts. Do not invent npm/LuaRocks workflows.
For web packaging, CI uses unpinned npx love.js; check .github/workflows/main.yml before reproducing or changing that command.
- Follow
.editorconfig(EmmyLuaCodeStyle): spaces, final newline, compact calls/tables, and no spaces around operators, assignments, or commas. Preserve the repository's dense Lua style instead of reformatting surrounding code. - Naming: camelCase for functions/locals,
_camelCasefor private helpers, uppercase for shared registries/state (GAME,MODES,SETTING), and mostly lowercase snake_case for mode/scene IDs (sprint_40l,net_game). Match existing filenames even where older files use camelCase. - Modules normally return plain tables. Representative patterns:
parts/scenes/about.luafor a scene andparts/modes/sprint_40l.luafor a mode. Avoid introducing class or dependency-injection frameworks. - State management is intentionally global/data-driven. Canonical shared schemas live in
parts/gameTables.lua; global lifecycle and persistence functions live inparts/gameFuncs.lua. Cache globals/library calls into locals in hot paths, as existing player/render code does. TASK.new(function() ... coroutine.yield() ... end)is the cooperative async pattern. Use existingTEST.yieldN,TEST.yieldT, task locks, and wait helpers rather than blocking the LÖVE loop.- Persisted file operations use
pcalland surface localizedMES.new('error', ...)messages. Missing assets/translations use fallback values plus warnings. Use assertions for programmer invariants, not recoverable player-facing failures. - In project convention, double-quoted strings are generally player-readable text and single-quoted strings are internal values. Except for Lua's
gcinfo,gcidentifiers abbreviate graphics. - New locales require coordinated changes to
parts/language/lang_<locale>.lua, registration inmain.lua, and selection UI inparts/scenes/lang.lua. Respect fallback locale behavior. - New modes should remain declarative and reuse
parts/eventsets/where possible. Adding a registry entry toparts/modes.luaand a matching safe module filename integrates the mode with discovery and smoke QA.
conf.lua: LÖVE 11.5 configuration, platform globals, save identity, and window/module settings.main.lua: bootstrap, global subsystem wiring, asset/locale registration, module discovery, persisted-state loading, and--testhandling.Zframework/init.lua: customlove.run, event dispatch, lifecycle hooks, and runtime error capture.parts/gameTables.lua: canonical shared state/default tables.parts/gameFuncs.lua: game lifecycle, persistence, settings, ranking, and replay functions.parts/scenes/game.lua: primary local-game scene and input/update/draw flow.parts/player/init.lua,parts/player/player.lua: player environment composition and simulation behavior.parts/modes.lua: mode metadata, map placement, icons, and unlock graph.parts/net.lua,parts/netPlayer.lua: online transport, room state, and remote players.version.lua: runtime and package version metadata consumed by CI.updateLog.txt: release history; CI parses the first numeric section for release notes..editorconfig: the only repository formatting policy..github/workflows/main.yml: CI triggers, smoke test, packaging, release, and Pages deployment.legals.md,license.txt: LGPLv3 and third-party notices.
- Runtime: LÖVE 11.5 (LuaJIT in normal LÖVE builds). Standalone Lua 5.3 in CI is only used to read release metadata.
- Package manager: none. There is no
package.json, lockfile, rockspec, or vendored package-manager workflow. - Treat
Zframeworkas legacy internal infrastructure, not a reusable framework recommendation. Existing code depends on its globals and event loop. - Build outputs belong under CI's
build//release/staging, not in source directories. Current CI packages Android, Linux, web, and Windows; macOS/iOS assets exist but have no current workflow jobs. - Update
version.luaand place the newest entry first inupdateLog.txtfor releases. Check.github/actions/update-version/action.ymlcarefully: its snapshot identity replacement no longer matches currentconf.lua.
love . --testis an application-level smoke scan, not a unit suite. It waits for startup, enters and exits every discovered mode exceptnetBattle, watches the framework error collector, and exits 0/1.- CI runs the packaged
core.loveunder LÖVE 11.5 and Xvfb before downstream platform packaging. A passing scan proves mode initialization/scene transitions do not raise captured runtime errors; it does not prove gameplay correctness. - There is no Busted/LuaUnit-style suite, dedicated
tests/tree, fixture/mock system, coverage tooling, or stated coverage threshold. - Adding a discoverable mode automatically includes it in the smoke scan. For behavior beyond loadability, exercise the changed scene/mode manually and document the scenario in the change description.
- Manual input-event QA is available through the in-app console command
test, which opensparts/scenes/test.lua. This is separate from the--teststartup flag. - Bug reports should include a crash screenshot and reproduction steps or trigger conditions, matching
.github/ISSUE_TEMPLATE/.