From 7dfe768acebf8371add88fef04130b61fedff01e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 18 Apr 2026 13:33:25 +0000 Subject: [PATCH 1/3] Initial plan From b922bf30e49fc5952bbabd7fca8c0f4a35cfa944 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 18 Apr 2026 13:43:24 +0000 Subject: [PATCH 2/3] fix: keep Panel C targets visible and re-anchor power-up tray on fullscreen lifecycle Agent-Logs-Url: https://github.com/TeacherEvan/MathMasterHTML/sessions/8970ed66-eade-42c9-a1ec-f2e3e6fe5730 Co-authored-by: TeacherEvan <189960447+TeacherEvan@users.noreply.github.com> --- src/scripts/symbol-rain.animation.js | 1 + src/scripts/worm-powerups.ui.js | 7 +++++ tests/powerups.spec.js | 43 ++++++++++++++++++++++++++++ tests/symbol-rain.mobile.spec.js | 28 ++++++++++++++++++ 4 files changed, 79 insertions(+) diff --git a/src/scripts/symbol-rain.animation.js b/src/scripts/symbol-rain.animation.js index 39516afd..863a00ea 100644 --- a/src/scripts/symbol-rain.animation.js +++ b/src/scripts/symbol-rain.animation.js @@ -60,6 +60,7 @@ const symbolObj = state.activeFallingSymbols[readIndex]; const isOffScreen = symbolObj.y > containerHeight + 50; const isStuckAtBottom = + !state.isMobileMode && symbolObj.y > containerHeight - 100 && state.activeFallingSymbols.length > 30; const isTouching = state.symbolsToRemove.has(symbolObj); diff --git a/src/scripts/worm-powerups.ui.js b/src/scripts/worm-powerups.ui.js index 9eeae7c9..d05136b7 100644 --- a/src/scripts/worm-powerups.ui.js +++ b/src/scripts/worm-powerups.ui.js @@ -100,6 +100,13 @@ this._displayLayoutHandler = () => this.syncDisplayLayout(); window.addEventListener("resize", this._displayLayoutHandler); window.addEventListener("orientationchange", this._displayLayoutHandler); + document.addEventListener("fullscreenchange", this._displayLayoutHandler); + const sharedResizeObserver = + window.__ensureSharedResizeObserver?.() || window.SharedResizeObserver; + sharedResizeObserver?.subscribe?.(this._displayLayoutHandler, { + immediate: true, + source: "worm-powerups-ui", + }); } }; diff --git a/tests/powerups.spec.js b/tests/powerups.spec.js index 4c709048..06ddae39 100644 --- a/tests/powerups.spec.js +++ b/tests/powerups.spec.js @@ -463,6 +463,49 @@ test.describe("Power-Up Compact Layout", () => { expect(layout.computedTop).not.toBe("auto"); expect(layout.distanceToTop).toBeLessThan(layout.distanceToBottom); }); + + test("re-anchors the power-up tray after fullscreen lifecycle changes", async ({ + page, + }) => { + await page.evaluate(() => { + const display = document.getElementById("power-up-display"); + if (!display) { + return; + } + + display.dataset.dragged = "false"; + display.style.left = "8px"; + display.style.top = `${Math.round(window.innerHeight * 0.6)}px`; + document.dispatchEvent(new Event("fullscreenchange")); + }); + + await expect + .poll( + async () => + page.evaluate(() => { + const display = document.getElementById("power-up-display"); + const panelB = document.getElementById("panel-b"); + const controls = document.querySelector(".panel-b-controls"); + + if (!display || !panelB || !controls) { + return false; + } + + const rect = display.getBoundingClientRect(); + const panelRect = panelB.getBoundingClientRect(); + const controlsRect = controls.getBoundingClientRect(); + + return ( + rect.left >= panelRect.left && + rect.right <= panelRect.right && + rect.bottom <= controlsRect.top && + rect.top < 80 + ); + }), + { timeout: 5000 }, + ) + .toBe(true); + }); }); test.describe("Power-Up Portrait Rotation Contract", () => { diff --git a/tests/symbol-rain.mobile.spec.js b/tests/symbol-rain.mobile.spec.js index 2e3e31eb..77b853de 100644 --- a/tests/symbol-rain.mobile.spec.js +++ b/tests/symbol-rain.mobile.spec.js @@ -392,6 +392,34 @@ test.describe("Symbol rain mobile interactions", () => { timeout: 10000, }); + await expect + .poll( + async () => + page.evaluate(() => { + const panel = document.getElementById("panel-c"); + const panelRect = panel?.getBoundingClientRect(); + if (!panelRect) { + return 0; + } + + return Array.from( + document.querySelectorAll("#panel-c .falling-symbol:not(.clicked)"), + ).filter((element) => { + const rect = element.getBoundingClientRect(); + const intersectsPanel = + rect.bottom > panelRect.top && + rect.top < panelRect.bottom && + rect.right > panelRect.left && + rect.left < panelRect.right; + const reachesCatchZone = + rect.top >= panelRect.top + panelRect.height * 0.7; + return intersectsPanel && reachesCatchZone; + }).length; + }), + { timeout: 8000 }, + ) + .toBeGreaterThan(0); + await context.close(); }); From aafa3b6dad5dda69d2c5ca5d49eb0fb78df17105 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 18 Apr 2026 13:47:34 +0000 Subject: [PATCH 3/3] test: harden compact tray and panel-c catch-zone regressions Agent-Logs-Url: https://github.com/TeacherEvan/MathMasterHTML/sessions/8970ed66-eade-42c9-a1ec-f2e3e6fe5730 Co-authored-by: TeacherEvan <189960447+TeacherEvan@users.noreply.github.com> --- tests/powerups.spec.js | 8 +++++--- tests/symbol-rain.mobile.spec.js | 9 ++++++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/tests/powerups.spec.js b/tests/powerups.spec.js index 06ddae39..f0e6fa6c 100644 --- a/tests/powerups.spec.js +++ b/tests/powerups.spec.js @@ -6,6 +6,8 @@ import { waitForGameplayInputReady, } from "./utils/onboarding-runtime.js"; +const COMPACT_TRAY_MAX_TOP = 80; + async function pressPowerUp(page, type) { await page .locator(`[data-testid="powerup-${type}"]`) @@ -482,7 +484,7 @@ test.describe("Power-Up Compact Layout", () => { await expect .poll( async () => - page.evaluate(() => { + page.evaluate((maxTop) => { const display = document.getElementById("power-up-display"); const panelB = document.getElementById("panel-b"); const controls = document.querySelector(".panel-b-controls"); @@ -499,9 +501,9 @@ test.describe("Power-Up Compact Layout", () => { rect.left >= panelRect.left && rect.right <= panelRect.right && rect.bottom <= controlsRect.top && - rect.top < 80 + rect.top < maxTop ); - }), + }, COMPACT_TRAY_MAX_TOP), { timeout: 5000 }, ) .toBe(true); diff --git a/tests/symbol-rain.mobile.spec.js b/tests/symbol-rain.mobile.spec.js index 77b853de..a35d1e56 100644 --- a/tests/symbol-rain.mobile.spec.js +++ b/tests/symbol-rain.mobile.spec.js @@ -5,6 +5,8 @@ import { stopEvanHelpIfActive, } from "./utils/onboarding-runtime.js"; +const PANEL_C_CATCH_ZONE_THRESHOLD = 0.7; + test.use({ ...devices["Pixel 7"], viewport: { width: 915, height: 412 }, @@ -395,7 +397,7 @@ test.describe("Symbol rain mobile interactions", () => { await expect .poll( async () => - page.evaluate(() => { + page.evaluate((catchZoneThreshold) => { const panel = document.getElementById("panel-c"); const panelRect = panel?.getBoundingClientRect(); if (!panelRect) { @@ -412,10 +414,11 @@ test.describe("Symbol rain mobile interactions", () => { rect.right > panelRect.left && rect.left < panelRect.right; const reachesCatchZone = - rect.top >= panelRect.top + panelRect.height * 0.7; + rect.top >= + panelRect.top + panelRect.height * catchZoneThreshold; return intersectsPanel && reachesCatchZone; }).length; - }), + }, PANEL_C_CATCH_ZONE_THRESHOLD), { timeout: 8000 }, ) .toBeGreaterThan(0);