Skip to content

Commit 8a3ccce

Browse files
author
DavidQ
committed
Add Collision Inspector V2 for manifest object orientation and collision debugging - PR_26139_003-collision-inspector-v2
1 parent 0bf0a54 commit 8a3ccce

12 files changed

Lines changed: 467 additions & 94 deletions

File tree

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# PR_26139_003-collision-inspector-v2 Report
2+
3+
## Summary
4+
5+
Built Collision Inspector V2 into a usable manifest-driven debugging tool for object orientation and collision behavior.
6+
7+
Playwright impacted: Yes.
8+
9+
## Scope Completed
10+
11+
- Added an Asteroids validation load path to Collision Inspector V2.
12+
- Loaded selectable Object A/Object B entries from `tools.object-vector-studio-v2.objects`.
13+
- Added collision modes: Bounds, Vector, Pixel/Sprite, and Hybrid.
14+
- Added mouse drag movement for either selected object.
15+
- Added per-object runtime rotation controls.
16+
- Added live diagnostics for collision state, overlap, bounds, object origins, world origins, rotation, transformed point samples, and debug log output.
17+
- Routed Pixel/Sprite and Hybrid checks through manifest vector shape raster masks generated at runtime from the selected manifest objects.
18+
- Removed synthetic fallback geometry from unsupported shapes; unsupported geometry produces no collision polygon instead of defaulting to a rectangle.
19+
- Added Workspace Manager V2 launch/hydration for Collision Inspector V2 when Object Vector Studio V2 manifest objects are present.
20+
- Kept Asteroids object geometry manifest-owned only; no hardcoded Asteroids geometry or fallback vector maps were added.
21+
22+
## Files Changed
23+
24+
- `tools/collision-inspector-v2/index.html`
25+
- `tools/collision-inspector-v2/js/bootstrap.js`
26+
- `tools/collision-inspector-v2/js/CollisionInspectorV2App.js`
27+
- `tools/collision-inspector-v2/styles/collisionInspectorV2.css`
28+
- `tools/collision-inspector-v2/README.md`
29+
- `tools/toolRegistry.js`
30+
- `tools/workspace-manager-v2/js/services/WorkspaceManagerV2ContextService.js`
31+
- `tools/workspace-manager-v2/js/WorkspaceManagerV2App.js`
32+
- `tools/workspace-manager-v2/js/controls/ToolTilesControl.js`
33+
- `tests/playwright/tools/CollisionInspectorV2.spec.mjs`
34+
- `tests/playwright/tools/WorkspaceManagerV2.spec.mjs`
35+
36+
## Validation
37+
38+
PASS:
39+
40+
- `node --check tools/collision-inspector-v2/js/CollisionInspectorV2App.js`
41+
- `node --check tools/workspace-manager-v2/js/services/WorkspaceManagerV2ContextService.js`
42+
- `node --check tools/workspace-manager-v2/js/WorkspaceManagerV2App.js`
43+
- `npx playwright test tests/playwright/tools/CollisionInspectorV2.spec.mjs --project=playwright --workers=1 --reporter=list`
44+
- 2 passed.
45+
- `npx playwright test tests/playwright/tools/WorkspaceManagerV2.spec.mjs --project=playwright --workers=1 --reporter=list -g "uses header lifecycle controls and launches tools from fixed Workspace Manager V2 tiles"`
46+
- `npx playwright test tests/playwright/tools/WorkspaceManagerV2.spec.mjs --project=playwright --workers=1 --reporter=list -g "syncs Workspace Manager V2 dirty lifecycle buttons and closes clean toolState data"`
47+
- `npx playwright test tests/playwright/tools/WorkspaceManagerV2.spec.mjs --project=playwright --workers=1 --reporter=list -g "registers Workspace Manager V2 from the tools index"`
48+
49+
FAIL, broader existing gate:
50+
51+
- `npm test`
52+
- Fails in `pretest` at `tools/dev/checkSharedExtractionGuard.mjs`.
53+
- Reported `189 unexpected violation(s)` across existing shared-extraction guard categories.
54+
- The failure spans existing game, sample, engine, and tool files; it also flags changed Collision Inspector V2 helper patterns as part of that broader guard.
55+
56+
FAIL, broader existing Workspace V2 suite:
57+
58+
- `npm run test:workspace-v2`
59+
- 54 passed, 2 failed.
60+
- Failing test: `validates optional Text to Speech V2 schema contract through Workspace Manager V2 schema`
61+
- Expected `activeContext.tools` to include `text2speech-V2`; received false.
62+
- Failing test: `tracks Object Vector Studio V2 dirty state through persisted edits and save outcomes`
63+
- Expected a generated manifest schema validation failure; save succeeded instead.
64+
- Collision Inspector V2 launch, tile, hydration, and toolState cleanup coverage passed inside this run.
65+
66+
Advisory coverage:
67+
68+
- `docs/dev/reports/playwright_v8_coverage_report.txt` and `docs/dev/reports/coverage_changed_js_guardrail.txt` list changed runtime JS files.
69+
- Workspace-only coverage reports WARN for Collision Inspector V2 runtime files because the Workspace V2 suite does not collect that page. The targeted Collision Inspector V2 Playwright spec exercises the Collision Inspector V2 page directly.
70+
71+
Full samples smoke test:
72+
73+
- Skipped. This PR is limited to Collision Inspector V2 and Workspace Manager V2 launch wiring, and the current repo instructions say full samples smoke is only for broad shared sample/runtime impact.
74+
75+
## Manual Validation
76+
77+
1. Start the repo server used by Playwright or any local static server for the repo.
78+
2. Open `/tools/collision-inspector-v2/index.html`.
79+
3. Click `Load Asteroids Manifest`.
80+
4. Confirm the summary reports Asteroids and 7 vector objects loaded.
81+
5. Select `object.asteroids.ship` as Object A and `object.asteroids.large-asteroid` as Object B.
82+
6. Drag Object B into Object A.
83+
7. Switch collision mode through Bounds, Vector, Pixel/Sprite, and Hybrid.
84+
8. Change Object A/Object B rotation values and confirm origins, rotation, transformed points, and summary JSON update live.
85+
9. Open Workspace Manager V2, select Asteroids, and launch Collision Inspector V2 from the Utilities group.
86+
10. Confirm the Workspace nav is visible, the tool loads Asteroids objects from workspace context, and Return to Workspace works.
87+
88+
Expected result:
89+
90+
- Collision Inspector V2 only uses Object Vector Studio V2 manifest objects.
91+
- No default vector maps or hardcoded Asteroids geometry appear.
92+
- Missing or invalid manifest object data produces visible/actionable log failures instead of hidden fallback geometry.

tests/playwright/tools/CollisionInspectorV2.spec.mjs

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,31 +39,39 @@ test.describe("Collision Inspector V2", () => {
3939
try {
4040
await page.goto(`${server.baseUrl}/tools/collision-inspector-v2/index.html`, { waitUntil: "networkidle" });
4141
await expect(page.locator("body.tools-platform-tool-page[data-tool-id='collision-inspector-v2']")).toBeVisible();
42-
await expect(page.locator("#collisionModeSelect option")).toHaveText(["Vector", "Sprite", "Bounds", "Pixel", "Hybrid"]);
42+
await expect(page.locator("#collisionModeSelect option")).toHaveText(["Bounds", "Vector", "Pixel/Sprite", "Hybrid"]);
4343

44-
const manifestBuffer = await readFile(join(server.repoRoot, "games", "Asteroids", "game.manifest.json"));
45-
await page.locator("#collisionManifestInput").setInputFiles({
46-
buffer: manifestBuffer,
47-
mimeType: "application/json",
48-
name: "game.manifest.json"
49-
});
44+
await page.locator("#loadAsteroidsManifestButton").click();
5045

5146
await expect(page.locator("#manifestSummary")).toContainText("Asteroids");
5247
await expect(page.locator("#manifestSummary")).toContainText("7 vector objects loaded");
5348
await expect(page.locator("#objectASelect")).toContainText("Asteroids Ship");
5449
await expect(page.locator("#objectBSelect")).toContainText("Large Asteroid");
50+
await page.locator("#objectASelect").selectOption("object.asteroids.ship");
51+
await page.locator("#objectBSelect").selectOption("object.asteroids.large-asteroid");
5552
await expect(page.locator("#collisionResultBadge")).toHaveText("No Collision");
5653
await expect(page.locator("#overlapState")).toHaveText("false");
54+
await expect(page.locator("#originState")).toContainText("A");
55+
await expect(page.locator("#rotationState")).toHaveText("A 0 / B 0");
56+
await expect(page.locator("#collisionSummary")).toContainText('"objectOrigins"');
57+
await expect(page.locator("#collisionSummary")).toContainText('"transformedPoints"');
5758

58-
await dragCanvasPoint(page, { x: 500, y: 320 }, { x: 390, y: 320 });
59+
await page.locator("#objectBRotationInput").fill("180");
60+
await expect(page.locator("#rotationState")).toHaveText("A 0 / B 180");
61+
62+
await dragCanvasPoint(page, { x: 500, y: 320 }, { x: 360, y: 320 });
5963
await expect(page.locator("#collisionResultBadge")).toHaveText("Collision");
6064
await expect(page.locator("#overlapState")).toHaveText("true");
61-
await expect(page.locator("#collisionSummary")).toContainText('"mode": "vector"');
65+
await expect(page.locator("#collisionSummary")).toContainText('"mode": "bounds"');
6266
await expect(page.locator("#collisionLog")).toHaveValue(/Dragged Object B/);
6367

64-
await page.locator("#collisionModeSelect").selectOption("pixel");
68+
await page.locator("#collisionModeSelect").selectOption("vector");
69+
await expect(page.locator("#collisionResultBadge")).toHaveText("Collision");
70+
await expect(page.locator("#collisionSummary")).toContainText('"mode": "vector"');
71+
72+
await page.locator("#collisionModeSelect").selectOption("pixel-sprite");
6573
await expect(page.locator("#collisionResultBadge")).toHaveText("Collision");
66-
await expect(page.locator("#collisionSummary")).toContainText('"mode": "pixel"');
74+
await expect(page.locator("#collisionSummary")).toContainText('"mode": "pixel-sprite"');
6775

6876
await page.locator("#collisionModeSelect").selectOption("bounds");
6977
await expect(page.locator("#boundsState")).toHaveText("overlap");
@@ -75,6 +83,47 @@ test.describe("Collision Inspector V2", () => {
7583

7684
await page.locator("#resetSimulationButton").click();
7785
await expect(page.locator("#collisionResultBadge")).toHaveText("No Collision");
86+
await expect(page.locator("#rotationState")).toHaveText("A 0 / B 0");
87+
expect(pageErrors).toEqual([]);
88+
} finally {
89+
await coverageReporter.stop(page);
90+
await server.close();
91+
}
92+
});
93+
94+
test("loads Asteroids Object Vector objects from a Workspace Manager V2 manifest context", async ({ page }) => {
95+
const server = await startRepoServer();
96+
const pageErrors = [];
97+
page.on("pageerror", (error) => {
98+
pageErrors.push(error.message);
99+
});
100+
101+
await coverageReporter.start(page);
102+
try {
103+
const gameManifest = JSON.parse(await readFile(join(server.repoRoot, "games", "Asteroids", "game.manifest.json"), "utf8"));
104+
const workspaceContext = {
105+
documentKind: "workspace-manifest",
106+
gameId: "Asteroids",
107+
gameRoot: "games/Asteroids/",
108+
name: "Asteroids Workspace Manager V2 Context",
109+
tools: gameManifest.tools
110+
};
111+
await page.addInitScript((context) => {
112+
sessionStorage.setItem("workspace-manager-v2-collision-test", JSON.stringify(context));
113+
}, workspaceContext);
114+
await page.goto(`${server.baseUrl}/tools/collision-inspector-v2/index.html?launch=workspace&hostContextId=workspace-manager-v2-collision-test`, { waitUntil: "networkidle" });
115+
116+
await expect(page.locator('[data-launch-mode-nav="workspace"]')).toBeVisible();
117+
await expect(page.locator('[data-launch-mode-nav="tool"]')).toBeHidden();
118+
await expect(page.locator("#manifestSummary")).toContainText("Asteroids Workspace Manager V2 Context");
119+
await expect(page.locator("#objectASelect")).toContainText("Asteroids Ship");
120+
await expect(page.locator("#objectBSelect")).toContainText("Large Asteroid");
121+
await page.locator("#objectASelect").selectOption("object.asteroids.large-ufo");
122+
await page.locator("#objectBSelect").selectOption("object.asteroids.small-ufo");
123+
await page.locator("#objectARotationInput").fill("180");
124+
await expect(page.locator("#rotationState")).toHaveText("A 180 / B 0");
125+
await expect(page.locator("#collisionSummary")).toContainText('"objectA": "Large UFO (object.asteroids.large-ufo)"');
126+
await expect(page.locator("#collisionSummary")).toContainText('"shapeRotationsA"');
78127
expect(pageErrors).toEqual([]);
79128
} finally {
80129
await coverageReporter.stop(page);

0 commit comments

Comments
 (0)