Skip to content
eemresariPublic

About

Projection-mapped chemistry game for science centers — camera-detected physical blocks steer compound balls into a beaker.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

KimyaLab

A projection-mapped chemistry game where physical black blocks on a board, seen by a camera, become invisible physics walls for virtual compound particles.

🇹🇷 Türkçe özet: KimyaLab, dik bir tahtaya projeksiyonla yansıtılan fiziksel-dijital melez bir kimya laboratuvarı oyunudur; tahtaya konan siyah bloklar kamerayla tespit edilip oyunda görünmez fizik duvarına dönüşür. Çevrimdışı çalışan, lisans kapılı, Nuitka + Inno Setup ile paketlenen bir sergi yazılımıdır; kurulum ve kalibrasyon ayrıntıları docs/INSTALL.md içindedir.

Game field: pipes with valves feeding compound particles toward the beaker

Game field (design reference, version 13): six pipes with valves, one per compound, and the beaker at the bottom center.

Overview

KimyaLab is an exhibition piece, not a desktop game. A 16:9 game field is projected onto an upright board. Six pipes (H₂O, Mg, Na, O₂, HCl, K) extend in from the edges and drip colored compound particles. Visitors place solid black blocks on the board; the camera finds them and the game treats each one as an invisible wall or ramp, so particles bounce off the real block as if it were part of the simulation. When different compounds collect in the beaker, a reaction animation plays and a score is awarded. Valves open while a black disc is held over them.

The blocks are never drawn in the projection. The physical world and the physics engine are overlaid on each other, which is why calibrating the camera-to-projection mapping is the core engineering problem of the project.

It runs fully offline on a Windows 11 exhibition PC and opens in its own full-screen embedded window; no browser, no address bar. Gameplay details, the reaction table, physical dimensions and hardware requirements are in docs/PROJE-RAPORU.md (Turkish).

Features

  • Camera-driven physical interaction. Black blocks are detected by image processing only: no markers, no QR codes.
  • Pluggable obstacle sources. The game engine never knows where obstacles come from; it only calls ObstacleSource.poll() -> list[Obstacle]. A fixed-bar source runs without a camera for testing, a contour source reads the camera in production.
  • In-game calibration wizard. Camera, lens, thresholds, measurements, an 8-point geometry mapping and live fine-tuning in one operator UI, with no terminal needed.
  • Offline by design. The physics engine and fonts are vendored; there are no network requests at runtime.
  • License-gated distribution. The game assets ship encrypted and cannot be opened without a signed license.
  • Windows installer. Nuitka standalone build wrapped in an Inno Setup installer with a SHA-256-stamped ZIP.

Architecture

                       +---------------------------+
 camera --> OpenCV --> | obstacle_source.py        |
 (black blocks)        |  ObstacleSource.poll()    |   FakeObstacleSource
                       |  Contour / Fake sources   |   (fixed bars, no camera)
                       +-------------+-------------+
                                     | Obstacle list
                       +-------------v-------------+
                       | ws_server.py              |  WebSocket bridge,
                       | ws://127.0.0.1:8765, 30 Hz|  operator monitor window
                       +-------------+-------------+
                                     | JSON "state" messages (PROTOCOL.md)
                       +-------------v-------------+
                       | web/ client              |  Matter.js physics,
                       | canvas2d, full screen     |  pipes, valves, beaker, reactions
                       +---------------------------+
 web_calistir.py starts HTTP (web_sunucu.py), the WS bridge and the embedded window.

The Python side does vision and the browser side does the game. They are coupled only by the versioned WebSocket data contract in PROTOCOL.md (currently v6, additive changes only). Ports 8000/8765 are picked automatically if occupied and injected into the page.

Tech stack

Layer Technology
Vision Python 3.11+, OpenCV 4.x (Otsu + contours + minAreaRect, homography), NumPy
Transport websockets (WS bridge), built-in HTTP server
Game client JavaScript, Matter.js (vendored), Canvas 2D
Window pywebview (embedded full-screen WebView)
Licensing Ed25519 signatures, AES-256-GCM content package (cryptography)
Packaging Nuitka standalone, Inno Setup 6
Tests pytest, camera-free

Engineering highlights

  • Calibration you can trust. The camera-to-game mapping is an 8-point homography (4 corners + 4 edge midpoints) reported with a residual in pixels. The same 8 crosshair positions exist in both Python (kalibrasyon.py) and the browser (web/render.js); tests/test_nisangah_esitligi.py fails if they ever diverge, because silent drift would make calibration look successful while shifting every block.
  • Order is enforced in code. Lens calibration must precede geometry; if the lens is recalibrated afterward, the geometry is flagged stale and the wizard asks for it again (contour_calibration.geometri_bayat_mi). The wizard is a state machine (sihirbaz.py) tested without a camera.
  • Graceful degradation. If the camera cannot be opened the app still starts without it and points the operator at the camera step of the wizard, instead of exiting and making the fix unreachable.
  • Stable tracking. Detected blocks go through alpha-beta tracking with coasting, so a block briefly occluded by a hand keeps its identity.
  • Protocol regression guard. With the wizard closed, the state message keys must stay identical to the previous protocol version; tests/test_ws_sihirbaz.py pins the key set, and it is extended deliberately, in the same commit, when the protocol grows.
  • Offline-safe by test. tests/test_cevrimdisi.py fails if a CDN link leaks back in; an earlier CDN dependency produced a blank screen when the exhibition had no internet.
  • Cryptographic license gate, not an if. The game's web/ tree is obfuscated, zipped and AES-256-GCM encrypted into web.pak. The decryption key is not in the executable; it travels in the signed license payload. Only an Ed25519 public key is embedded, so the app can verify a key but never mint one. Activation is bound to the machine (2 of 3 hardware identifiers) and guards against clock rollback.
  • Packaging lessons captured in tests. A onefile build triggered a Windows Defender ML false positive, so the project moved to a Nuitka standalone folder inside an Inno installer; tests/test_kurucu.py blocks onefile from returning and blocks local calibration or activation files from leaking into the installer.
  • Path handling for frozen builds. All file paths go through one module (paths.py) that distinguishes read-only resources from writable data, so calibration is never written to a temporary extraction folder; tests/test_yollar.py locks this.
  • Test suite. 625 test functions across 41 files, none requiring hardware. Camera polling, the GUI calibration loops and projection alignment are verified by hand on the real setup.

Project status

Version 0.9.1 (Nuitka standalone build and Inno Setup installer are produced; see docs/TESLIM.md for the delivery flow). Calibration wizard, publish preparation and the license gate are complete. The code-signing certificate has not been acquired, so Windows shows a SmartScreen warning on first install. A legacy 4-corner calibration path is retained because its homography loader is still used in the live pipeline. The earlier pygame desktop version is archived under docs/arsiv/ and unused. Formerly named SEKTIRMECE.

Repository layout

Path Purpose
web_calistir.py Single-command launcher (HTTP + WS + window)
ws_server.py Vision-to-browser WebSocket bridge and operator monitor
obstacle_source.py, obstacle_geometry.py Obstacle sources (contour / fake) and segment/polygon conversion
kamera_geometri.py, ince_ayar.py Camera-to-game math and fine-tune persistence
sihirbaz.py Calibration wizard state machine
web/ Browser client (Matter.js physics, rendering, pipes, beaker, reactions)
PROTOCOL.md Python ↔ browser WebSocket data contract
lisans*.py, web_paket.py License gate and encrypted content package
build.py, installer/ Nuitka build and Inno Setup installer
tests/ Camera-free pytest suite
docs/ Project report, install guide, delivery notes, plans and specs

Running locally

python -m venv .venv && source .venv/bin/activate   # Windows: .\.venv\Scripts\activate
pip install -r requirements.txt
python web_calistir.py            # no camera: fixed test bars
python web_calistir.py --contour  # with camera (production mode)

Run the tests with pip install -r requirements-dev.txt && pytest. The production target is Windows 11; a KIMYALAB.bat launcher is provided for source runs.

Full setup (flags, packaging, installer, calibration, data folders, licensing): docs/INSTALL.md (Turkish).

About

Projection-mapped chemistry game for science centers — camera-detected physical blocks steer compound balls into a beaker.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages