feat(hedgehog-mode): knockable block piles for Max to throw#2312
Draft
fercgomes wants to merge 5 commits into
Draft
feat(hedgehog-mode): knockable block piles for Max to throw#2312fercgomes wants to merge 5 commits into
fercgomes wants to merge 5 commits into
Conversation
Adds Angry-Birds-style block piles to hedgehog mode. While the mode is on, stacks of 3-5 colored blocks spawn near the ground (capped at 3 piles, refreshed every ~15s) so the user has something to fling Max at. Blocks use the existing matter-js world inside `@posthog/hedgehog-mode` and are rendered with Pixi `Graphics` on the same canvas; cleanup happens when a block leaves the viewport or stays at rest for ~8s. - New `PileSpawner` owns the timer, the per-block `GameElement`, and lifecycle. Blocks use `category: PROJECTILE, mask: 0xFFFF` so Max (and the ground) collide with them out of the box. - `HedgehogMode.tsx` instantiates the spawner once the game is rendered and tears it down before destroying the game. - `pixi.js` and `matter-js` were already transitive deps via `@posthog/hedgehog-mode`; promoted to direct deps and added `@types/matter-js` so the imports type-check. Generated-By: PostHog Code Task-Id: f26ab8fc-0c36-4bf9-959b-891c6eda2e7b
Two fixes: 1. Stop leaking `window.pointerdown` listeners in dev. The upstream `@posthog/hedgehog-mode` `destroy()` doesn't remove its capture-phase window listeners, so every StrictMode simulated unmount and every Vite HMR cycle stacked another stale listener on top. The old listener fired first on each click, hit-tested against the destroyed game's hedgehog, and called `preventDefault/stopPropagation` — so the live game never saw the click and you couldn't grab Max in dev. Fix locally by only calling `destroy()` when `hedgehogMode` actually transitions to false, instead of on every effect cleanup. Production was unaffected (no HMR, no StrictMode double-mount), which matches the reported symptom. 2. Bump pile height range from 3-5 to 6-10 blocks so towers feel like real obstacles instead of speed bumps. Generated-By: PostHog Code Task-Id: f26ab8fc-0c36-4bf9-959b-891c6eda2e7b
Three small changes to figure out why piles aren't rendering in dev: - Drop the Pixi v8 `.rect().fill().stroke()` chain in favor of separate calls. Stroke was decorative and the chain is the likeliest silent-failure point. - Bump pile-block `zIndex` to 1000 so blocks render above the hedgehog if Pixi z-order is the issue. - Add a scoped `pile-spawner` logger that logs pile id, x, height, ground top, stage child count, and matter-js world body count on every spawn. - Expose the game on `window.__hedgehogGame` so we can inspect `app.stage.children`, `engine.world.bodies`, and `elements` from the renderer devtools console. Generated-By: PostHog Code Task-Id: f26ab8fc-0c36-4bf9-959b-891c6eda2e7b
The PileSpawner was being skipped whenever the effect re-ran while `game.render(container)` was still awaiting. The deps array includes `user?.hedgehog_config`, which React Query returns as a fresh object on every refetch — that retriggers the effect, fires the cleanup (`cancelled = true`), and the re-run bails on `gameRef.current` already being set. When the original `render` finally resolves, `!cancelled` is false, so the spawner is never constructed. The hedgehog itself survives because it's added inside `render`, before the await resolves. `cancelled` tracks effect lifecycle, which is the wrong signal here. Gate on game identity instead: if `gameRef.current` still points to the game we just rendered, we're still the active owner and the spawner should be set up. Generated-By: PostHog Code Task-Id: f26ab8fc-0c36-4bf9-959b-891c6eda2e7b
… chunk
CI integration-test was OOMing during electron-forge's renderer
Vite build (4GB heap exhausted). The regression was the static
import of `pixi.js` in `PileSpawner.ts`, combined with
`PileSpawner` being statically imported by `HedgehogMode.tsx` —
that pulled pixi.js (multi-MB WebGL bundle) into the main
renderer chunk. Before this PR, pixi was only reachable through
the dynamic `import("@posthog/hedgehog-mode")` and lived in a
lazy chunk.
Switch `PileSpawner` to a type-only import at the top of
`HedgehogMode.tsx`, and load the actual module via `import()`
alongside `@posthog/hedgehog-mode` inside the same effect. Both
now share the lazy boundary, and pixi.js stays out of the main
bundle.
Generated-By: PostHog Code
Task-Id: f26ab8fc-0c36-4bf9-959b-891c6eda2e7b
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
While hedgehog mode is on, stacks of 3–5 colored blocks now spawn near the ground (capped at 3 piles, refreshed every ~15s) so you can fling Max at them and knock them over Angry-Birds-style. Blocks use the existing matter-js world inside
@posthog/hedgehog-modeand are rendered with PixiGraphicson the same canvas — no new sprite assets, no fork of the upstream package.PileSpawner(apps/code/src/renderer/components/hedgehog-mode/PileSpawner.ts) owns the spawn timer, per-blockGameElement, and lifecycle.category: PROJECTILE (0x0004), mask: 0xFFFFso Max and the ground collide with them out of the box; the hedgehog's existing mask already includesPROJECTILE.HedgehogMode.tsxinstantiates the spawner once the game is rendered and tears it down before destroying the game on unmount.pixi.jsandmatter-jswere already transitive deps via@posthog/hedgehog-mode; promoted to direct deps and added@types/matter-jsso the imports type-check.Test plan
pnpm dev(run code app)