My kids and I vibe coded a jump & run game over the weekend. What started as a Python script turned into a full Fabric analytics pipeline — with a playable game running inside a notebook, stats saved to a Delta table, and a Power BI report on top.
Here is the game. Click the canvas below and start playing.
🎮 Play the Game
Controls: Arrow Keys / WASD to move · Space / W to jump · F to attack · Stomp enemies from above
If the embed does not load, open the game directly: https://kornalexander.github.io/jump-and-run/jump_and_run_v2.html
How It Started
My three boys wanted to build a game. We started with Python and Pygame — a classic jump & run with platforms, enemies, coins, water hazards, and a dragon boss at the end. The character collects power-up items (fox, egg, bat) that change its form and unlock different attacks: a lightning strike or a sonic wave.
It worked, but Pygame means installing Python locally. I had a different idea: what if we could play it inside a Microsoft Fabric notebook?
One Line to Play
I rewrote the entire game in HTML5 Canvas and JavaScript. The game logic — physics, collision detection, level generation, enemy AI, particle effects, audio — is a single self-contained HTML file. No external dependencies, no CDN links, no server.
Embedding it in a Fabric notebook is one line:
displayHTML(open("./builtin/jump_and_run.html").read())
Upload the HTML file to your Lakehouse Files, run the cell, and the game renders right inside the notebook output. My boys could not believe it.
The V2: Professional Polish
After the first version worked, I could not stop. The V2 adds:
- Web Audio API — retro sound effects for jumps, coins, stomps, attacks, and the victory fanfare
- Particle system — coin sparkles, death bursts, attack trails, ambient fireflies
- Smooth camera — lerp-based follow cam that keeps the action centered
- Screen shake — on hits and attacks for extra game feel
- Parallax background — layered mountains and stars that move at different speeds
- Gradient rendering — sky gradients, glowing water, soft lighting on platforms
All of it in ~1000 lines of vanilla JavaScript, no frameworks, no build step.
The Stats Pipeline
A game without stats is just — playing. But we are in Fabric. So I added a stats tracker.
After every game-over (win or lose), the game generates a JSON blob with 17 metrics:
{
"duration_seconds": 142.5,
"score": 3850,
"won": true,
"lives_left": 2,
"deaths_total": 1,
"deaths_enemy": 0,
"deaths_water": 1,
"deaths_fall": 0,
"coins_collected": 24,
"enemies_stomped": 5,
"enemies_zapped": 3,
"attacks_used": 8,
"jumps": 87,
"forms_collected": "fox,egg",
"final_form": "egg",
"max_x_reached": 12400
}
A second notebook cell uses ipywidgets to create a paste-and-save UI. You copy the JSON from the game output, paste it into a text area, click Save, and it appends the row to a game_stats Delta table in the Lakehouse.
A third cell runs a SQL summary:
SELECT
COUNT(*) AS total_games,
SUM(CASE WHEN won THEN 1 ELSE 0 END) AS wins,
ROUND(100.0 * SUM(CASE WHEN won THEN 1 ELSE 0 END) / COUNT(*), 1) AS win_rate,
MAX(score) AS high_score,
ROUND(SUM(duration_seconds) / 60, 1) AS total_playtime_min,
SUM(coins_collected) AS total_coins,
SUM(enemies_stomped + enemies_zapped) AS total_kills,
SUM(deaths_total) AS total_deaths,
SUM(jumps) AS total_jumps
FROM game_stats
Now my kids argue about who is the best player — with data.
Taking It Further: Power BI Report & Automated Stats Collection
The Delta table is nice, but I imagine my boys want a leaderboard they can check anytime — not a SQL query. So the next step is a Power BI report on top of the game_stats table. Direct Lake, obviously. No import, no scheduled refresh. The report reads straight from the Delta table in the Lakehouse. Every new game round shows up the moment you refresh the page.
But the manual paste step still bothers me. Right now, after each game-over you have to copy the JSON, switch to the save cell, paste it, and click Save. That works, but it’s manual. The goal is to fully automate it — the game writes stats directly to the Lakehouse without any manual step in between. The challenge: Fabric’s displayHTML() runs inside a sandboxed iframe with no access to the parent notebook, no postMessage, no clipboard API, and no way to call PySpark from JavaScript. Every automatic approach I tried — OneLake REST API from the iframe, postMessage to the notebook, navigator.clipboard — was blocked by the sandbox.
The workaround I am exploring: a lightweight Fabric API endpoint (or a Data Pipeline trigger) that the game’s JavaScript can POST the JSON to directly. If Fabric eventually opens up notebook cell-to-cell communication or relaxes the iframe sandbox, the whole thing becomes a one-click experience. For now, the ipywidgets paste-and-save UI is the pragmatic solution.
Why This Matters (Beyond the Fun)
This project is a real demonstration of what Fabric can do:
- displayHTML() renders any self-contained HTML inside a notebook cell — games, dashboards, custom UIs, interactive visualizations
- ipywidgets enables interactive controls (text areas, buttons, dropdowns) natively in notebook output — no external web framework needed
- Delta tables are first-class citizens — any structured data, from any source, can land in the Lakehouse
- SQL analytics run directly against Delta tables — no separate query engine, no ETL
- The full pipeline — from data generation to storage to analysis — lives in a single notebook
If a kids’ game can become a full analytics pipeline in a weekend, imagine what you can do with your business data.
Try It Yourself
The complete source code is on GitHub:
🔗 https://github.com/KornAlexander/jump-and-run
| File | Description |
jump_and_run python game basis.py |
Original Python/Pygame version |
jump_and_run.html |
HTML5 Canvas version with stats tracking |
jump_and_run_v2.html |
V2 with audio, particles, parallax & smooth camera |
Jump and Run.ipynb |
Fabric notebook — play, save stats, view summary |
To run it in Fabric:
- Upload the HTML file to your Lakehouse → Files
- Create a notebook attached to the Lakehouse
- Run:
displayHTML(open("./builtin/jump_and_run.html").read())
(I do not endorse burning your company’s Fabric capacity for gaming. But if your manager asks — you were “testing displayHTML performance.”)