ForkOrFry is pivoting from a fake takeover prank extension into a browser-extension-hosted local game shell based on hurrycurry.
This repo is currently in the “extension game shell” phase: the end goal is a single-player, fully local game running inside an extension-owned UI surface. Godot integration is not done yet.
- ✅ Firefox extension scaffolding exists
- ✅ WXT-based build/dev/packaging scripts exist
- ✅ CI runs lint, tests, and build for the extension
- ✅ Firefox packaging workflow exists
- ✅ Idle → renewed-activity shell trigger is implemented in the extension background flow
- ✅ Extension-owned reusable large popup shell window is implemented as the current runtime surface
- ✅ Local checkpoint/resume placeholder state exists for shell window lifecycle resets
- ⏳ Local hurrycurry client integration is still to be implemented
- ⏳ Multiplayer/server removal is still in progress as a repo pivot
- ⏳ Bot players, production save/resume, and burger-level locking are still to be implemented
- ⏳ Godot WebAssembly embed is still future work
- Define the single-player local-only direction
- Keep the browser extension as the runtime container
- Add CI and Firefox packaging workflows
- Preserve the extension repo as the implementation home
- Replace prank/takeover behavior with inactivity → renewed activity flow
- Move runtime UI into a reusable popup-window shell
- Vendor or otherwise localize the
hurrycurryclient build - Remove runtime dependency on any game server
- Convert game state to local authoritative ownership
- Turn the current shell checkpoint placeholder into production local persistence and fast resume
- Implement rule-based bots to replace remote players
- Lock the shipped experience to burger level only
- Add save/load checkpointing for constrained extension lifecycle
- Prepare the Godot WebAssembly export path
- Separate asset/theme swaps from core gameplay logic
Convert the project into:
- single player only
- no server dependency
- bots replacing all remote players
- a browser-hosted lightweight extension application running inside a popup or side-panel-style container
The final runtime must live inside a browser extension UI context, not a full-tab application.
- Do not use Docker.
- Do not build or deploy the Rust server.
- Do not preserve multiplayer networking as a runtime feature.
- Treat server code as reference only.
- The client must fully own game state.
- Target environment:
- Godot WebAssembly export
- embedded inside a browser extension popup or side-panel-style UI
- compatible with constrained viewport sizing and frequent open/close lifecycle events
- Trigger on inactivity first, then on renewed mouse activity.
- Open the game inside an extension-owned popup/pane surface rather than a full browser tab.
- Bundle a local fork of
hurrycurrydirectly in the extension repo. - Ship a single-player-only build.
- Keep gameplay completely local and offline.
- Persist save/progress locally.
- Lock the first shipped experience to the burger level only.
- Leave asset/theme replacement for a later phase.
extension/— Firefox extension app, WXT config, scripts, tests.github/workflows/— CI and Firefox packaging workflowsdocs/— pivot analysis and supporting notesREADME.md— project direction, developer guide, and roadmapLICENSE/THIRD_PARTY_NOTICES.md— licensing and attribution for the hurrycurry pivot
Upstream hurrycurry is currently a reference target documented in docs/pivot-analysis.md; it is not vendored into this repo yet.
ci.ymlruns on pull requests plus pushes tomain/release/**- installs dependencies
- runs lint
- runs tests
- runs the Firefox build
- uploads the built extension directory as an artifact
pr-preview.ymlruns on pull requests and manual dispatch- installs dependencies
- runs lint, tests, and the Firefox package build
- builds the review/source bundle
- validates the packaged artifacts
- uploads preview XPI and source-bundle artifacts for reviewers
package-firefox.ymlruns on tag push or manual dispatch- installs dependencies
- resolves the Firefox add-on ID
- runs lint and tests
- packages release artifacts
- uploads the unsigned XPI and source bundle
- Node.js
^20.19.0 || >=22.12.0 - npm
zip/unzipavailable on your PATH for packaging + validation scripts- Python 3 if you need to regenerate extension icons
- Firefox desktop browser for temporary loading and manual verification
cd extension
npm installcd extension
npm run devcd extension
npm run previewcd extension
npm run buildcd extension
npm testWatch mode:
cd extension
npm run test:watchcd extension
npm run lintAuto-fix where safe:
cd extension
npm run lint:fixFirefox XPI package:
cd extension
npm run package:firefoxSource bundle:
cd extension
npm run package:source-bundleRelease artifact bundle:
cd extension
npm run package:releaseIf you are packaging artifacts intended to match a published Firefox add-on ID, set FORKORFRY_GECKO_ID before running the release workflow/scripts.
Validate release artifacts:
cd extension
npm run validate:release-artifacts- Run
npm run buildinextension/ - Open Firefox and go to
about:debugging#/runtime/this-firefox - Click Load Temporary Add-on
- Select
extension/dist/firefox-mv3/manifest.json
- Load the temporary add-on in Firefox.
- Open the toolbar popup and click Arm idle trigger.
- Let Firefox enter the configured idle state.
- Return to activity and verify the extension opens or refocuses the large shell window.
- Use Open pane now to test the shell directly.
- Close and reopen the shell to verify the placeholder checkpoint/resume status is preserved.
npm run package:firefox— local unsigned XPI for manual installsnpm run package:source-bundle— source archive for release/review workflowsnpm run package:release— full release artifact buildnpm run validate:release-artifacts— checks packaged outputs
| Command | Purpose |
|---|---|
npm run dev |
Run the WXT Firefox development loop |
npm run preview |
Serve a preview build locally |
npm run lint |
Run ESLint across the extension code |
npm test |
Run the Vitest suite |
npm run build |
Produce the Firefox MV3 extension bundle |
npm run package:firefox |
Build and zip an unsigned Firefox XPI |
npm run package:source-bundle |
Create the source archive used for review/release |
npm run package:release |
Build release artifacts end-to-end |
npm run validate:release-artifacts |
Verify packaged outputs and metadata |
npm run icons:generate |
Regenerate the extension icon assets |
Firefox action popups are ephemeral. The shipped UX still needs to feel like an extension popup/pane application, so the implementation should prefer a side-panel-style or similarly extension-owned constrained UI surface, with popup lifecycle-safe pause/resume behavior when persistence is needed.
Produce:
- architecture breakdown for client, server, and protocol
- network flow mapping
- dependency graph
- list of networking entry points
- list of gameplay systems dependent on server state
- identification of gameplay/network coupling points
Phase 1 output lives in docs/pivot-analysis.md.
Design a migration that:
- removes server authority completely
- converts the client into a self-contained simulation
- replaces multiplayer synchronization with local state management
- accounts for browser extension popup/side-panel lifecycle limits
Implement or stage:
- full disablement of server connections
- removal or stubbing of networking layers
- replacement of remote game state with local authoritative state
Implement bot players to replace all remote players.
Bots must:
- behave like real players through the input/command system
- support movement
- support object interaction
- participate in the cooking loop
- start with rule-based logic
- remain extensible for smarter future AI
Prepare for:
- Godot WebAssembly export
- embedding inside a browser extension popup or side panel
- fixed or resizable small viewports
- rapid open/close lifecycle events
- deterministic startup from scratch when needed
- lightweight initialization with no native dependencies
Current extension files that will be repurposed:
extension/src/core/background.ts— idle lifecycle and trigger orchestrationextension/src/core/takeover.ts— current extension-page open/reuse logicextension/src/core/state.ts—browser.storage.localstate persistenceextension/src/core/messages.ts— popup/background command contractextension/src/features/popup/app.ts— current toolbar popup controlsextension/src/features/takeover/app.ts— current fake takeover UIextension/src/entrypoints/takeover/*— existing extension page entrypointextension/wxt.config.ts— manifest/action wiring
Upstream hurrycurry areas that matter most:
client/— Godot clientserver/— Rust server and simulation referencetest-client/— TypeScript protocol referenceprotocol.md— network contract
The upstream hurrycurry repo is AGPL-3.0-only. Since the pivoted product is intended to vendor and modify that code locally, this repo is being prepared for AGPL-3.0-only distribution as the safest license baseline. See LICENSE and THIRD_PARTY_NOTICES.md.
- Keep changes aligned with the single-player, local-only, extension-hosted direction.
- Do not reintroduce multiplayer or server runtime dependencies.
- Prefer incremental changes that preserve the current extension shell while the game layer is being added.
- Keep browser lifecycle, persistence, and constrained viewport behavior in mind for every UI change.
- Update this README when the pivot status changes materially.
- replace the prank/takeover flow with inactivity → renewed activity behavior
- move the runtime surface into an extension popup/pane-style game UI
- vendor
hurrycurrylocally - remove live networking and server dependence
- replace remote players with local bots
- add local persistence and fast resume behavior
- lock the first shipped build to the burger level
- keep art/theme swaps isolated for a later pass