Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 33 additions & 25 deletions .claude/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,36 @@

## Packages

- **originGUI/** — In-game mod menu (TypeScript, bundled with esbuild). Injected into the Prodigy game page.
- **extension/** — Plasmo-based MV3 Chrome extension (Play Origin):
- Blocks original `game.min.js` via declarativeNetRequest
- Removes CSP/X-Frame-Options headers
- Injects patched game code + mod menu bundle via the `onreset` attribute trick
- Custom login background and logo redirects
- Fetches `manifest.json` from the sibling `P-NP` repo's `dist/`
- Fetches the original `game.min.js` directly from `code.prodigygame.com`
- Applies the manifest's regex rules + wraps with prefix/suffix in the background service worker
- Caches the patched result in `chrome.storage.local` keyed by `{gameClientVersion, manifestHash}`
- **originGUI/** — In-game mod menu (TypeScript, bundled with esbuild). `build.mjs` also emits `dist/menu.js` (gitignored): the bundle wrapped as `export default function startOriginMenu()` so the extension can package it.
- **extension/** — Plasmo-based MV3 Chrome extension (Play Origin). On branch `chrome/packaged-runtime` it runs no remote code:
- Prodigy loads its own, unmodified `game.min.js`
- `contents/runtime.ts` (MAIN world, `document_start`) wraps `Object.defineProperty` to capture webpack export objects, resolves hook targets by shape/name, installs the education bypasses and builds `window._`
- `contents/menu.ts` (MAIN world, `document_idle`) runs the packaged originGUI on `origin:ready`
- `background.ts` only registers two DNR redirects that swap the login background and logo for packaged, web-accessible art
- Prodigy's CSP is left intact
- Master still ships the old P-NP `manifest.json` + `onreset` pipeline for Edge/Firefox
- **typings/** — Reverse-engineered TypeScript type definitions for Prodigy's game objects
- **meta/** — Documentation, guides

## Key Technical Details

- **Package manager:** pnpm. Workspace defined in `pnpm-workspace.yaml`.
- **Build tools:** esbuild for originGUI, Plasmo for extension
- **Injection method:** `document.documentElement.setAttribute("onreset", code)` + `dispatchEvent(new CustomEvent("reset"))` + `removeAttribute("onreset")` — bypasses MV3 CSP restrictions
- **Content script:** runs in `world: "MAIN"` via `chrome.scripting.registerContentScripts()` from the background service worker
- **DNR rules:** registered dynamically in `extension/background.ts` via `chrome.declarativeNetRequest.updateDynamicRules()`
- **Content scripts:** Plasmo registers the MAIN-world scripts with `chrome.scripting.registerContentScripts()` from the service worker
- **DNR rules:** registered dynamically in `extension/background.ts` via `chrome.declarativeNetRequest.updateDynamicRules()` (ids 3, 4: `extensionPath` redirects)
- **Log prefix:** `[Origin]` in all console output
- **Window globals:** `__ORIGIN_INJECTED__`, `__ORIGIN_REWRITTEN__`, `__ORIGIN_GAME_URL__`, `__ORIGIN_GUI_URL__`
- **DOM attributes:** `data-origin-game-url`, `data-origin-gui-url`, `data-origin-ready`, `data-origin`
- **Storage keys:** `originGameUrl`, `originGuiUrl`
- **Window globals:** `_` (lodash, plus Play Origin's `instance`, `constants`, `player`, `network`, `gameData`, `membership`, `functions.setMembership`), `__ORIGIN_READY__`
- **Events:** `origin:ready` on `window`

### Hook targets (`extension/lib/runtime/resolve.ts`)

| Target | Found by | Used for |
|---|---|---|
| `singletonClass` | class with static `instance` getter and `prodigy` prototype getter | `_.instance`, service discovery |
| `constants` | `.constants` object owning `"GameConstants.Build.VERSION"` | `_.constants`, bypass gate |
| `componentRegistry` | object whose `OpenQuestionInterface` is a class (`EV()` decorator registry) | battle question bypass |
| `baseActionClass` | class whose prototype owns `init`, `execute`, `finish`, `findParameter`, `validateParameters` | `AnswerQuestion` action bypass |
| `towerTownClass` | class owning `openQuestionInterfaceThenEmitNotifications` | Tower Town bypass |

## Related Repos

Expand All @@ -35,17 +41,19 @@

```
extension/
background.ts — Service worker: DNR rules registration
contents/prodigy.ts — Content script (MAIN world): game + mod menu injection
contents/origin-bridge.ts — Bridge script (ISOLATED world): URL communication
background.ts — Service worker: DNR login-art redirects only
contents/runtime.ts — MAIN world, document_start: hook + resolve + bypasses + window._
contents/menu.ts — MAIN world, document_idle: starts packaged originGUI on origin:ready
popup.tsx — Extension popup UI
package.json — Plasmo config + manifest overrides
lib/
patch-urls.ts — MANIFEST_URL + game-URL regex helpers
patches.ts — applyPatchRules + wrapWithPrefixSuffix
manifest.ts — Manifest type + validateManifest
bundle-cache.ts — chrome.storage.local cache wrapper
tests/ — unit + integration tests (node --test)
assets/origin-*.png — Packaged login background and logo (web-accessible)
lib/runtime/
modules.ts — defineProperty hook capturing webpack export objects
resolve.ts — hook target resolvers
bypasses.ts — education bypass prototype wraps
api.ts — window._ API (ported from P-NP wrappers.ts)
ready.ts — origin:ready signal
tests/ — unit tests (node --test)
originGUI/
build.mjs — esbuild build script
src/index.ts — Entry point
Expand Down
4 changes: 3 additions & 1 deletion .claude/workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@ cd extension && pnpm dev
- Load unpacked extension from `extension/build/chrome-mv3-dev/` (dev) or `extension/build/chrome-mv3-prod/` (prod)
- Navigate to https://math.prodigygame.com/ to test
- Check browser console for `[Origin]` log messages
- Verify DNR rules are active: chrome://extensions → service worker → inspect
- Network tab: `code.prodigygame.com/code/*/game.min.js` is 200 (loaded by Prodigy, not blocked)
- Console: `[Origin] packaged runtime active`, three `[Origin] hook installed:` lines, no `hook target missing`, then `[Origin] menu started`
- Console check: `[!!_.instance?.prodigy, _.constants.get("GameConstants.Build.VERSION"), !!_.player?.data, window.__ORIGIN_READY__]`
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,8 @@ extension/firefox/.plasmo/
# MCP debug config
.mcp.json
.worktrees/
.superpowers/

# Generated menu module for the Chrome extension
originGUI/dist/menu.js
originGUI/dist/menu.d.ts
9 changes: 6 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ Monorepo for modding online math games (formerly modding Prodigy Math Game), mai

## Critical Rules

> **Branch `chrome/packaged-runtime` is the Chrome Web Store exclusive line (v4.5.x).** It is never merged into `master`. `master` stays on the v4.4.x P-NP pipeline for Edge and Firefox. CWS listing and privacy answers for this line: `meta/webstores/CHROME.md`, `meta/webstores/JUSTIFICATIONS.md`.

1. Use **pnpm**, never npm
2. **No force pushes**, no history rewrites
3. **esbuild** for originGUI, **Plasmo** for extension — no webpack
4. **MV3 only** — use declarativeNetRequest, not webRequest
5. The **`onreset` injection trick** is intentional and critical — do not replace it with script tags or other methods
6. **Graceful degradation** — if patches fail, set `patchDegraded: true` and open a GitHub issue
7. **Dev bundle guard** — before committing `originGUI/dist/bundle.js`, confirm it does NOT end with `/* DEV BUNDLE */`; if it does, run `cd originGUI && pnpm build` first
5. **No remote code on `chrome/packaged-runtime`** — the Chrome build must never fetch-and-run JavaScript, use `onreset`, `eval`, or `new Function`. Hooks live in `extension/lib/runtime/`; the menu is packaged via `extension/contents/menu.ts`. Master keeps the P-NP `onreset` pipeline for Edge/Firefox.
6. **Graceful degradation** — a hook target that stops resolving logs `[Origin] hook target missing: <names>`; the other hooks keep working. A missing target means a Chrome Web Store resubmission.
7. **Prodigy's CSP stays intact** — the Chrome build does not strip it, so anything the menu or DNR loads (images, fonts, fetches) must come from `*.prodigygame.com` or be packaged and web-accessible.
8. **Dev bundle guard** — before committing `originGUI/dist/bundle.js`, confirm it does NOT end with `/* DEV BUNDLE */`; if it does, run `cd originGUI && pnpm build` first

## Branding (Play Origin / Prodigy Origin)

Expand Down
Loading
Loading