- TypeScript 74.9%
- CSS 20.5%
- Python 2.6%
- Nix 1.6%
- HTML 0.4%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
allod site view refuses without --vm when no machine's repository list names this site, which is true for momo-match today and out of scope for this issue to change. |
||
| data | ||
| nix | ||
| public | ||
| scripts | ||
| src | ||
| test | ||
| .gitignore | ||
| flake.lock | ||
| flake.nix | ||
| index.html | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| site.toml | ||
| tsconfig.json | ||
| vite.config.ts | ||
Momo Match
A match-3 game with a sponsored, three-question thinker survey. Every adjacent swap costs a move, including swaps that do not make a match. The game shows a survey after every fifth move while a level is still active (up to three times per session) and after a level is completed. A survey has no timer or Skip button: answer all three questions to see a thinker profile, then continue to the game. Completing an in-game survey grants five extra moves. The level ends when the score target is met or the moves run out.
The site is https://play.computelocal.org. The sponsor and editorial review
labels in public/ads.json are placeholders until the partner approves them.
The survey copy should be reviewed before it is presented as partner-approved.
Survey data
public/thinkers.json contains 12 thinker profiles. Each profile has a stable
id, a name, role, image_url, summary, quote, and HTTPS Wikipedia wiki_url.
The image_url must point to /thinkers/<id>.webp. The 12 supplied portraits
are in public/thinkers/, each 512 × 512 pixels.
public/questions.json contains 101 questions. Each question has an integer
id, a domain, a prompt, and exactly three choices. Each choice has display
text and a list of thinker_ids that must exist in thinkers.json. Both
files have "version": 1 at the top level. The JSON files are the current
source of truth for survey text and thinker weights.
The game draws three distinct questions for each survey. It cycles through the question bank without repeats until the bank is exhausted. Every chosen answer gives one point to each thinker tagged on that choice. The thinker with the most points appears at the end. A tie goes first to the thinker tagged on fewer choices across the full question bank, then to one tagged earlier in the three answers, then alphabetically by ID. The result links to the thinker's Wikipedia page. There are no correct or incorrect answers. The portraits preload during idle browser time after the survey data loads, so the result screen can use an already decoded image.
The CSV files in data/ are the original imports, not the current survey data.
scripts/render-survey.py still reads those files and overwrites both JSON
files, so running it would discard the subsequent edits to the questions and
thinker profiles. Update the CSVs first if the converter is needed again.
The survey layout and timing are in public/ads.json. Its only supported ad
type is survey; placements can use level_complete, level_fail,
every_n_moves, or session_start. A survey ad has a title and may have a
positive reward_moves value. The game applies a move reward only when it is
shown during active play or as a failure rescue.
Try your own JSON
Press the backtick or tilde key (` or ~), or tap the level number five times on a phone, to open the developer panel. Use Export thinkers.json and Export questions.json to download the current data. Choose one or both replacement files and press Import and validate. The panel checks the JSON syntax, required fields, duplicate IDs, Wikipedia URLs, and every choice's thinker references. It reports the file and array position of errors and does not apply invalid files. A valid import takes effect only in that browser and persists across reloads; Reset survey data restores the deployed files.
The Thinker images section accepts one ZIP archive or multiple WebP files
named for thinker IDs. It checks names, WebP signatures, browser decoding,
512 × 512 dimensions, and a 1 MB per-image size limit before applying any
file. A valid import is stored only in that browser. Export all images
downloads the active images as a ZIP; Reset images restores the deployed
portraits. The supplied friedrich-hayek.webp name is accepted as an alias
for f-a-hayek.webp during import.
The panel also has a placement config editor for ads.json, a Next survey
button, and metrics. Metrics stay in browser storage; they count impressions,
completed surveys, choices per question, and thinker results.
Build and publish
The game uses Vite, React, and TypeScript. For local development with Node 22:
npm ci
npm run dev
npm test
npm run build
To use Nix instead of an installed Node/npm:
nix shell nixpkgs#nodejs_22 -c sh -c 'npm ci && npm run dev'
To preview the game with hot reload from a dev VM instead, run
allod site serve in this checkout and open the address it prints; from the
hypervisor, allod site view --vm <vm> momo-match does the same without a
hand-written forward, where <vm> is the dev VM whose checkout is being
edited.
nix build produces the static site in result/. To publish changes from the
nexus host, run allod site check, allod site deploy --dry-run, and
allod site deploy in this checkout. The domain is set in site.toml; the
deployed .htaccess prevents stale HTML and survey JSON from lingering in
browsers.