Skip to main content

Architecture Overview

einky is split across ten repositories under the einky GitHub organization. Each repo has a single, narrow responsibility; the meta repo bootstraps a clone of every other one as siblings on disk.

Repo layout

einky/ # workspace parent (any name)
├── .github/ # org profile, shared workflows, issue templates
├── meta/ # workspace bootstrap, ADRs, shared scripts
├── docs/ # this site (Docusaurus)
├── os/ # pi-gen recipe building the Raspberry Pi OS image
├── runtime/ # on-device Python supervisor
├── launcher/ # Ren'Py game shown at boot — the menu
├── server/ # FastAPI backend (catalog, telemetry)
├── web/ # web frontend (admin / store / management)
├── case/ # enclosure CAD, BOM, wiring
└── games/ # Ren'Py game projects
RepoResponsibility
.githubOrg-wide GitHub config — profile README, reusable workflows, issue templates.
metaSingle entry point for contributors. Hosts bootstrap.sh, versions.env, the local Docker dev stack, and the ADRs surfaced under the Architecture Decisions section of this sidebar.
docsHuman-readable design docs and guides — what you are reading now.
ospi-gen-based image build. Produces the SD card image with the runtime, launcher, and SDK pre-installed.
runtimeOn-device Python supervisor. Owns the framebuffer-to-SPI pipeline, the input event loop, and the lifecycle of the Ren'Py SDK process (start/stop/swap project).
launcherA Ren'Py game that acts as the boot menu. The runtime starts it like any other title; selecting an entry tells the runtime to swap projects and re-launch the SDK.
serverFastAPI backend serving the game catalog, telemetry ingestion, and management endpoints. See Server research.
webWeb frontend for the catalog and admin tooling. Talks to server.
caseEnclosure CAD, BOM, wiring diagrams.
gamesRen'Py game sources shipped with or sideloaded onto the device.

Engine model

einky uses the vanilla Ren'Py SDK orchestrated by a custom runtime — there is no fork, no patched engine, no rebuilt binary. The SDK is downloaded as released by Ren'Py upstream (see meta/scripts/install_sdk.sh) and run unmodified.

Everything einky-specific lives outside the engine:

  • runtime/ is the supervisor. It launches the SDK against the active project, captures rendered frames from Xvfb, runs the dither pipeline, pushes bytes to the e-ink driver, and translates GPIO button presses into Ren'Py keyboard events.
  • launcher/ is the boot UI. Because it is a regular Ren'Py game, the same display pipeline that draws every other title also draws the menu — there is no separate render path.

Boot sequence

power on
→ systemd starts runtime (PID 1 child)
→ runtime starts Xvfb + spawns Ren'Py SDK on launcher game
→ user presses a button → launcher dispatches a "play <game>" intent over a local socket
→ runtime stops the launcher SDK process, swaps the project path, restarts the SDK
→ game runs; quitting the game returns to the launcher (same swap, in reverse)

Where data lives

ConcernLives in
Game binaries / assetsgames/ on disk; managed by the runtime
Catalog metadataserver/ (Postgres)
Build pinned versionsmeta/versions.env