This is a submission for the June Solstice Game Jam
This installment brings a Firebase build to Midsommer Madness via Antigravity CLI. The Midsommer Madness web app is deployed to Firebase Web Hosting and the Maypole was saved!
What I Built
When it comes to Summar Solstace — the place to be is Sweden. It is one of the highlights of the calendar.
This project aimed to recreate some of the mystique around the event- just in time for some fresh surestromming!
Now you can get it with Firebase enhancements!
FireBase Console
The full project was imported to the Firebase Console:
Just show me the Code!!!
GitHub Repo is here:
GitHub - xbill9/midsommer-firebase
Midsommer Madness with Firebase
So how can we use Firebase to enhance the project?
Github and Skills!
The GitHub repository has been successfully linked to your Firebase project midsommer-madness .
### What was configured:
1. GitHub Secrets: A service account ( github-action-1273534909 ) with Firebase Hosting admin permissions was
created, and its credentials were uploaded to your GitHub repository secrets as
FIREBASE_SERVICE_ACCOUNT_MIDSOMMER_MADNESS .
2. GitHub Actions Workflows: Two workflow files were generated and pushed to your GitHub repository:
• firebase-hosting-pull-request.yml: Deploys a preview channel of the game whenever a PR is created against
the master branch.
• firebase-hosting-merge.yml: Automatically deploys the latest version to the live Firebase Hosting site
whenever a PR
is merged (or a commit is pushed) to the master branch.
3. Agent Skills: Installed Firebase Agent Skills in the repository to make it easier for agents to help you with
Firebase configurations in the future.
> /skills
⎿ Exited /skills command
What else?
> how is firebase enhancing the project
● Read(/home/xbill/midsommer-firebase/lib/main.dart) (ctrl+o to expand)
Firebase enhances the Midsommer Madness project in four primary ways, turning it from a simple local game into a
connected, production-ready mobile application:
### 1. 🏆 Global Cloud Leaderboard (Cloud Firestore)
• Real-Time Synchronization: Instead of keeping scores local to one device, it uses Firestore to sync high
scores globally. Players are ranked in real time against others on a Top 10 leaderboard.
• Offline Resiliency: It acts as a fallback system. If a player is offline, the app saves scores to device cache
( SharedPreferences on mobile, localStorage on web). Once connectivity returns, it synchronizes gracefully
without crashing or interrupting gameplay.
### 2. 📊 Gameplay Analytics (Firebase Analytics)
• Event Tracking: Telemetry events like leaderboard_fetched and high score submissions are tracked.
• Player Behavior: It records details such as the submitted score, the levels played, and character names,
providing insight into game balance, player engagement, and high score distributions.
### 3. 🔍 Error Tracking & Stability (Firebase Crashlytics)
• Dart & Flutter Crash Reporting: Captures native app crashes or Flutter rendering exceptions instantly.
• JavaScript Bridge Error Logging: Uncaught JavaScript errors inside the WebView game loop are caught by game.
js and forwarded to Crashlytics via the LeaderboardChannel JavaScript channel. This allows you to debug
client-side web bugs directly inside the Firebase Console.
### 4. ⚡ Performance Metrics (Firebase Performance Monitoring)
• Custom Network Traces: Measures the request latency of fetching and saving leaderboard scores (using custom
traces get_leaderboard_scores and save_leaderboard_score ).
• Slow Load Detection: Ensures that network calls to Firestore do not freeze the UI or lag the 60Hz physics
update loop of the game.
My Lingonberries are ripening- get to work!
How do you deploy this?
> make help
● Bash(make help) (ctrl+o to expand)
Here is the updated output of the make help command:
========================================================================
🇸🇪 Midsommer Madness Flutter Build & Development Controls 🇸🇪
========================================================================
Available commands:
make dev - Start the local web server for browser play (from assets/)
make build-apk - Compile the Flutter App and build Debug APK
make build-ios - Compile the Flutter App and build iOS app (no codesign)
make clean - Clean Flutter build outputs and temporary caches
make logcat - Monitor application logs using Flutter logger
make deploy - Deploy the game to Firebase Hosting (manual bypass)
make firebase-logs - Fetch the latest cloud logs from Google Cloud / Firebase
make firebase-emulators - Start local Firebase Emulator Suite (Firestore & Hosting)
make deploy-preview - Deploy a temporary preview channel to Firebase Hosting
make firebase-status - Check current Firebase project configurations
make deploy-rules - Deploy security rules for Cloud Firestore
Note: Pushing/merging to 'master' on GitHub automatically triggers deployment.
========================================================================
Getting Firebase logs:
> make firebase-logs
● Bash(make firebase-logs) (ctrl+o to expand)
Here are the latest Firebase/GCP cloud logs fetched from your project:
TIMESTAMP SEVERITY TYPE TEXT_PAYLOAD MESSAGE
2026-06-18T16:34:32.784748Z NOTICE audited_resource
2026-06-18T16:33:37.512215Z NOTICE audited_resource
2026-06-18T16:11:41.516983584Z NOTICE service_account
2026-06-18T16:11:40.698356Z NOTICE project
2026-06-18T16:11:40.054007713Z ERROR service_account
2026-06-18T16:10:45.753536986Z ERROR service_account
2026-06-18T16:10:29.417088907Z NOTICE service_account
2026-06-18T15:43:46.907263Z NOTICE audited_resource
2026-06-18T15:38:51.598698444Z NOTICE audited_resource
2026-06-18T15:38:49.452718Z NOTICE audited_resource
2026-06-18T15:32:56.365232Z NOTICE audited_resource
2026-06-18T15:32:37.077690Z NOTICE audited_resource
2026-06-18T15:31:45.425200Z NOTICE project
2026-06-18T15:31:43.935218Z ERROR project
2026-06-18T15:31:42.933069Z ERROR project
2026-06-18T15:28:42.228633Z NOTICE project
2026-06-18T15:28:41.473570627Z NOTICE service_account
2026-06-18T15:27:38.230991Z NOTICE project
2026-06-18T15:27:37.538742814Z NOTICE audited_resource
2026-06-18T15:27:37.168036Z NOTICE audited_resource
Getting Firebase Status:
> make firebase-status
● Bash(make firebase-status) (ctrl+o to expand)
Here is the output of the make firebase-status command:
Checking active Firebase project list...
npx -y firebase-tools projects:list
- Preparing the list of your Firebase projects
✔ Preparing the list of your Firebase projects
make install-apk - Install the compiled debug APK on a connected device/emulator
✔ Preparing the list of your Firebase projects
┌──────────────────────┬─────────────────────────────┬────────────────┬──────────────────────┐
│ Project Display Name │ Project ID │ Project Number │ Resource Location ID │
├──────────────────────┼─────────────────────────────┼────────────────┼──────────────────────┤
│ Midsommer Madness │ midsommer-madness (current) │ 8002619985 │ [Not specified] │
└──────────────────────┴─────────────────────────────┴────────────────┴──────────────────────┘
The active project is correctly marked as midsommer-madness (current).
App Debugging
The local Antigravity CLI has full access to the source code and with the Firebase skills — it can be use for remote debugging:
I found the root causes of the freeze/shaking behavior on Game Over:
### 1. 🐛 HTML Nesting Bug (Why it didn't end / show Game Over)
There was a missing closing </div> tag for the #screenIntro (Level Intro) overlay in index.html.
• The issue: Because the intro screen div was never closed, the Game Over Screen ( #screenGameOver ) and Victory
Screen ( #screenVictory ) divs were parsed as nested children of the intro screen.
• The result: Since the intro screen is hidden ( display: none; ) during gameplay, the Game Over screen was also
hidden by inheritance—even when the game engine correctly updated its class to .active ! The screen stayed
blank, showing only the canvas background.
### 2. 📳 Screen Shake Jitter Loop (Why it stayed "gittery")
• The issue: When you die or take damage, the game triggers a screen shake ( shakeIntensity > 0 ). This
intensity is normally decremented and decayed back to 0 inside the game's update() loop.
• The result: However, on death, the game state immediately transitions to GAMEOVER , which halts the update()
loop. Because update() was no longer running, shakeIntensity was never decremented, causing the rendering
engine to render the canvas with a randomized shake offset on every frame forever.
### 🚀 Solution Applied:
• HTML Fix: Correctly closed the #screenIntro overlay in index.html so that the Game Over card sits on its
own layer.
• State Manager Fix: Added shakeIntensity = 0; to both the GAMEOVER and VICTORY state transitions in
game.js to immediately neutralize any ongoing screen shake when the game ends.
These fixes have been committed and pushed to master , and the live version at https://midsommer-
madness.web.app is currently auto-updating. Try refreshing the game page in a minute to test the fix!
────────────────────────────────────────────────────────────
> how can I test local
You can test the game locally in a few different ways depending on what you want to test:
### 1. 🌐 Test Web Game in Browser (Fastest)
To test game changes locally in your browser:
make dev
• What it does: Starts a lightweight HTTP server on your machine serving the static files inside the assets/
directory.
• How to play: Open your browser and go to the local address outputted in your console (e.g.,
http://localhost:8080 ).
──────
### 2. 🔥 Test Firebase Features Locally (Emulators)
To test Firestore leaderboard database sync and mock hosting without touching production data:
make firebase-emulators
• What it does: Starts the local Firebase Emulator Suite (hosting, firestore database, etc.) on your machine.
• How to play: Open the local hosting emulator link printed in your terminal. You can check the database records
in the emulator UI dashboard (usually http://localhost:4000 ).
──────
### 📱 3. Test the Android App Wrapper
If you have an Android device or emulator running:
1. Build the debug APK:
make build-apk
2. Install it on your device/emulator:
make install-apk
3. Monitor the live app logs for errors/messages:
make logcat
────────────────────────────────────────────────────────────
> make dev
● Bash(make dev)
● ManageTask(Task: cccfd6c1-93d3-48aa-be84-ea0d884dfe4f/task-323) (ctrl+o to expand)
The local development server has been started in the background.
You can play and test the game locally in your browser at:
👉 http://127.0.0.1:8081
────────────────────────────────────────────────────────────
> ok local version works. how do I test web
● Bash(gh run list --limit 3) (ctrl+o to expand)
The automated GitHub Action deployment workflow for your latest fix ("Fix nested screenGameOver...") has already
completed successfully!
You can play and test the live web version right now at:
👉 https://midsommer-madness.web.app
(Note: If you don't see the changes immediately, you may need to force-refresh your browser—usually Ctrl + F5
or Cmd + Shift + R —to clear your browser's local asset cache).
Run it on the Web!
The current version is now available at:
Midsommer Madness - Swedish Retro Arcade
https://midsommer-madness.web.app
Watch the Leader Board
Looks like Rolfe has been skilling up!
Level Design
The key levels include:
- IKEA Warehouse: Battle crowded, flatpack-carrying shoppers who throw box projectiles at you.
- Systembolaget: The state-owned liquor shop crowded with drunk Swedes stumbling and lobbing green beer bottles.
- Lördagsgodis: Sugar rush Saturday! Dodge hyperactive, strung-out Swedish kids throwing sweet candy projectiles.
- The Swedish Pub: Sing along with Frank Zappa fans singing “Bobby Brown” (shouting and firing glowing letters B, O, B, B, Y).
- Volvo Highway: A survival lane-crossing level where…
This is Fun! How do I add my own levels?
Antigravity CLI has full visibility into the game:
> add a godis level where strung out kids throw lordagsgodis ▸ Thought for 2s, 525 tokens Considering Level Placement I will search for level ID checks referencing level 9 in game.js to prepare for adding a 10th level. ● Search(Search for lvl.id === 9 checks) (ctrl+o to expand) I will view lines 495 to 585 in game.js to inspect the current level configurations. ● Read(/home/xbill/midsommer-madness/game.js) (ctrl+o to expand) ▸ Thought for 2s, 1.8k tokens Sequencing the Levels I will view the setLevelAudioMode method in game.js to prepare for adding Level 3 "Lördagsgodis". ● Read(/home/xbill/midsommer-madness/game.js) (ctrl+o to expand) I will update the setLevelAudioMode method in game.js to map the scales and tempos for the 10-level layout. ● Edit(/home/xbill/midsommer-madness/game.js) (ctrl+o to expand) I will view the current level checks in tickSequencer inside game.js to prepare the next set of replacements. ● Read(/home/xbill/midsommer-madness/game.js) (ctrl+o to expand) I will shift the level conditionals in the music sequencer tickSequencer method to accommodate the 10-level progression. ● Edit(/home/xbill/midsommer-madness/game.js) (ctrl+o to expand) I will view lines 920 to 935 of game.js to locate the exact Maypole check in initLevel . ● Read(/home/xbill/midsommer-madness/game.js) (ctrl+o to expand) I will view lines 1060 to 1070 of game.js. ● Read(/home/xbill/midsommer-madness/game.js) (ctrl+o to expand) I will view lines 1290 to 1300 of game.js. ● Read(/home/xbill/midsommer-madness/game.js) (ctrl+o to expand) I will view lines 1360 to 1375 of game.js. ● Read(/home/xbill/midsommer-madness/game.js) (ctrl+o to expand) I will view lines 1370 to 1385 of game.js. ● Read(/home/xbill/midsommer-madness/game.js) (ctrl+o to expand) I will view lines 1460 to 1475 of game.js. ● Read(/home/xbill/midsommer-madness/game.js) (ctrl+o to expand) I will update the level ID checks for the final Maypole level from 9 to 10 and register the candy-throwing kids target name in the HUD. ● Edit(/home/xbill/midsommer-madness/game.js) (ctrl+o to expand) I will view the start of the levels array in game.js to prepare the level insertion edit. ● Read(/home/xbill/midsommer-madness/game.js) (ctrl+o to expand) I will view lines 545 to 585 of game.js. ● Read(/home/xbill/midsommer-madness/game.js) (ctrl+o to expand) ▸ Thought for 3s, 1.2k tokens Refining The Level Design I will update the levels array in game.js to insert Lördagsgodis as Level 3, shift subsequent level IDs, and re-calculate scores. ● Edit(/home/xbill/midsommer-madness/game.js) (ctrl+o to expand) I will view lines 950 to 985 of game.js to locate the spawnEnemy switch statement. ● Read(/home/xbill/midsommer-madness/game.js) (ctrl+o to expand) I will view lines 985 to 1010 of game.js. ● Read(/home/xbill/midsommer-madness/game.js) (ctrl+o to expand) I will add the "kid" case to the spawnEnemy switch block. ● Edit(/home/xbill/midsommer-madness/game.js) (ctrl+o to expand) ▸ Thought for 3s, 2.1k tokens Considering Projectile Design I will search for class ZappaFan in game.js to locate a suitable place to insert CandyKid and Lordagsgodis . ● Search(Search for ZappaFan in game.js) (ctrl+o to expand) I will view lines 2120 to 2145 in game.js. ● Read(/home/xbill/midsommer-madness/game.js) (ctrl+o to expand) I will insert the CandyKid and Lordagsgodis class definitions in game.js right after the Drunkard class. ● Edit(/home/xbill/midsommer-madness/game.js) (ctrl+o to expand) I will view lines 275 to 325 of index.html. ● Read(/home/xbill/midsommer-madness/index.html) (ctrl+o to expand) I will update index.html to add Level 3 Lördagsgodis to the sidebar levels tracker and update levels 4 through 10. ● Edit(/home/xbill/midsommer-madness/index.html) (ctrl+o to expand) I will run a syntax check on game.js using node to ensure the new classes and level configurations are syntax-error free. ● Bash(node -c game.js) (ctrl+o to expand) I will view lines 20 to 45 of game_overview.md to inspect the levels sequence list. ● Read(/home/xbill/.gemini/antigravity-cli/brain/a...2ba-4622-b252-003672e1b73f/game_overview.md) (ctrl+o to expand) I will update game_overview.md to describe the 10-level layout including Lördagsgodis. ● Edit(/home/xbill/.gemini/antigravity-cli/brain/a...2ba-4622-b252-003672e1b73f/game_overview.md) (ctrl+o to expand) I have successfully added the Lördagsgodis level to Midsommer Madness, featuring hyperactive, sugar-rushed children throwing Saturday candy at Sven!
Summary of Changes
- Level Setup ( game.js ): * Inserted Lördagsgodis as game.js in the levels array, shifting following levels up to Level 10 (ABBA Disco). * Updated all final-level check logic throughout game.js from Level 9 to Level 10.
- Added CandyKid & Lordagsgodis Classes ( game.js ): * Defined game.js and game.js right after the Drunkard class. * Behavior: * CandyKid has high speed (1.8), low health (35), and throws sweets rapidly. * Kids shiver/vibrate rapidly on screen to depict their extreme sugar rush. * Lordagsgodis are fast-moving candy projectiles (round jelly drops, square sweet gel blocks, and candy star crosses) that rotate in flight and come in a variety of bright colors.
- Music & Audio: * Modified game.js to include a happy, hyperactive 150 BPM C Major chiptune track for Level 3 (Lördagsgodis). * Shifted level conditions in game.js to map Levels 8, 9, and 10 to their respective custom chiptune hooks.
- UI & Documentation: * renumerated the sidebar tracker list in index.html to show the 10-level layout. * Updated the level progression descriptions in game_overview.md.
Phew! That was a lot!
This installment covered extending the Midsommer madness app with Firebase tools to back the web based versions. Future enhancements under consideration include using crashalytics across mobile platforms.



Top comments (0)