Skip to content

Commit d39b3af

Browse files
author
DavidQ
committed
Finish Object Vector Studio V2 runtime cleanup while preserving intentional ship flicker and asteroid scaling - PR_26133_124-object-vector-final-runtime-cleanup
1 parent 587c30a commit d39b3af

8 files changed

Lines changed: 188 additions & 35 deletions

File tree

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# PR_26133_124 Object Vector Final Runtime Cleanup Report
2+
3+
## Summary
4+
5+
- Cleaned final active terminology around Object Vector Studio V2 so current object geometry is documented as `objects[]`, `objects[].tags`, and `objects[].shapes`.
6+
- Marked Vector Map Editor as legacy in the active tool registry while leaving the standalone deprecated compatibility tool available.
7+
- Added a targeted runtime cleanup guard that scans active Asteroids, Workspace Manager V2, Object Vector Studio V2, and Object Vector runtime paths for removed legacy dependencies.
8+
- Refreshed Asteroids targeted geometry assertions to match the current manifest-owned geometry and intentional arcade-scale asteroid sizing.
9+
10+
## Removed Active Legacy Usage
11+
12+
- Removed active-tool framing that implied Vector Map Editor is still part of the current Object Vector geometry migration path.
13+
- Verified active runtime/tool code no longer depends on `objectVectorRoles`, legacy `vectorMaps` payload data, `vector-map-editor` runtime/schema paths, or fallback/default vector maps.
14+
- Verified Asteroids `tools.object-vector-studio-v2` payload uses only `version`, `toolId`, `name`, and `objects`.
15+
16+
## Remaining Intentional Legacy Guards
17+
18+
- `tools/object-vector-studio-v2/js/services/ObjectVectorStudioV2SchemaService.js` keeps the `root.vectorMaps` rejection path as deprecated-input rejection only.
19+
- Object Vector Studio V2 tests keep legacy `vectorMaps` import fixtures/assertions to prove deprecated input fails visibly and actionably.
20+
- Vector Map Editor remains present as a deprecated standalone compatibility tool/schema, not as an Object Vector Studio V2 object-geometry source.
21+
22+
## Preserved Gameplay And Art Decisions
23+
24+
- Preserved duplicated Asteroids ship flame line shapes and the `move` state frame behavior for flicker animation.
25+
- Preserved current asteroid radius ordering and scale tuning: large asteroid > medium asteroid > small asteroid.
26+
- Did not change Asteroids runtime gameplay code or manifest object geometry for this PR.
27+
28+
## Validation
29+
30+
- PASS `node -e "import('./tests/tools/ObjectVectorFinalRuntimeCleanup.test.mjs').then((m)=>m.run()).then(()=>console.log('PASS ObjectVectorFinalRuntimeCleanup'))"`
31+
- PASS `node -e "import('./tests/tools/WorkspaceManagerV2ObjectVectorPayloadCleanup.test.mjs').then((m)=>m.run()).then(()=>console.log('PASS WorkspaceManagerV2ObjectVectorPayloadCleanup'))"`
32+
- PASS `node -e "import('./tests/tools/ObjectVectorStudioV2DeleteCleanup.test.mjs').then((m)=>m.run()).then(()=>console.log('PASS ObjectVectorStudioV2DeleteCleanup'))"`
33+
- PASS `node -e "import('./tests/games/AsteroidsValidation.test.mjs').then((m)=>m.run()).then(()=>console.log('PASS AsteroidsValidation'))"`
34+
- PASS `node -e "import('./tests/games/AsteroidsPlatformDemo.test.mjs').then((m)=>m.run()).then(()=>console.log('PASS AsteroidsPlatformDemo'))"`
35+
- PASS `node -e "import('./tests/games/AsteroidsAssetReferenceAdoption.test.mjs').then((m)=>m.run()).then(()=>console.log('PASS AsteroidsAssetReferenceAdoption'))"`
36+
- PASS `npx playwright test tests/playwright/tools/WorkspaceManagerV2.spec.mjs --project=playwright --workers=1 --reporter=list -g "shows Object Vector Studio V2 layout shell and schema-only palette gate|loads Object Vector Studio V2 runtime assets into Asteroids gameplay rendering|discovers Active Game options from selected repo manifests|uses header lifecycle controls and launches tools from fixed Workspace Manager V2 tiles"`
37+
- PASS `git diff --check` with line-ending warnings only.
38+
39+
Full regression and full samples smoke tests were skipped per PR instructions.

games/Asteroids/game.manifest.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -879,7 +879,7 @@
879879
},
880880
"style": {
881881
"fill": "#00000000",
882-
"stroke": "#FFFFFF",
882+
"stroke": "#F87171",
883883
"strokeWidth": 2,
884884
"fillOpacity": 1,
885885
"strokeOpacity": 1
@@ -1209,7 +1209,7 @@
12091209
},
12101210
"style": {
12111211
"fill": "#00000000",
1212-
"stroke": "#FFFFFF",
1212+
"stroke": "#94A3B8",
12131213
"strokeWidth": 2,
12141214
"fillOpacity": 1,
12151215
"strokeOpacity": 1
@@ -1309,7 +1309,7 @@
13091309
},
13101310
"style": {
13111311
"fill": "#00000000",
1312-
"stroke": "#FFFFFF",
1312+
"stroke": "#78B7FF",
13131313
"strokeWidth": 2,
13141314
"fillOpacity": 1,
13151315
"strokeOpacity": 1

tests/games/AsteroidsPlatformDemo.test.mjs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,11 @@ export async function run() {
8585
assert.equal(geometryProfiles[1].objectId, 'object.asteroids.small-asteroid');
8686
assert.equal(geometryProfiles[2].objectId, 'object.asteroids.medium-asteroid');
8787
assert.equal(geometryProfiles[3].objectId, 'object.asteroids.large-asteroid');
88-
assert.equal(geometryProfiles[1].points.length, 6);
89-
assert.equal(geometryProfiles[2].points.length, 7);
88+
assert.equal(geometryProfiles[1].points.length, 12);
89+
assert.equal(geometryProfiles[2].points.length, 12);
9090
assert.equal(geometryProfiles[3].points.length, 12);
91+
assert.equal(geometryProfiles[3].radius > geometryProfiles[2].radius, true);
92+
assert.equal(geometryProfiles[2].radius > geometryProfiles[1].radius, true);
9193
assert.deepEqual(payload.objects.find((object) => object.id === 'object.asteroids.medium-asteroid').tags, ['asteroid', 'medium']);
9294
const tagValidation = validateAsteroidsRuntimeObjectTags(payload.objects);
9395
assert.equal(tagValidation.ok, true);

tests/games/AsteroidsValidation.test.mjs

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -176,10 +176,10 @@ export async function run() {
176176
assert.deepEqual(
177177
getAsteroidsObjectGeometryPoints(objectGeometry, 'bullet'),
178178
[
179-
{ x: -2, y: -2 },
180-
{ x: 2, y: -2 },
181-
{ x: 2, y: 2 },
182-
{ x: -2, y: 2 },
179+
{ x: -1, y: 0 },
180+
{ x: 0, y: 0 },
181+
{ x: 0, y: 3 },
182+
{ x: -1, y: 5 },
183183
],
184184
);
185185
assert.deepEqual(
@@ -196,24 +196,35 @@ export async function run() {
196196
assert.deepEqual(
197197
getAsteroidsObjectGeometryPoints(objectGeometry, 'asteroidMedium'),
198198
[
199-
{ x: -16, y: -10 },
200-
{ x: -2, y: -18 },
201-
{ x: 16, y: -14 },
202-
{ x: 20, y: 2 },
203-
{ x: 8, y: 18 },
204-
{ x: -10, y: 16 },
205-
{ x: -20, y: 4 },
199+
{ x: 4.779, y: 19.845 },
200+
{ x: 24.219, y: 10.125 },
201+
{ x: 21.789, y: 2.835 },
202+
{ x: 12.069, y: -4.455 },
203+
{ x: 24.219, y: -16.605 },
204+
{ x: 14.499, y: -21.465 },
205+
{ x: 4.779, y: -18.063 },
206+
{ x: -9.801, y: -21.465 },
207+
{ x: -20.979, y: -8.343 },
208+
{ x: -20.979, y: 10.125 },
209+
{ x: -12.231, y: 10.125 },
210+
{ x: -12.231, y: 19.845 },
206211
],
207212
);
208213
assert.deepEqual(
209214
getAsteroidsObjectGeometryPoints(objectGeometry, 'asteroidSmall'),
210215
[
211-
{ x: -10, y: -6 },
212-
{ x: 0, y: -12 },
213-
{ x: 10, y: -6 },
214-
{ x: 8, y: 8 },
215-
{ x: -6, y: 10 },
216-
{ x: -12, y: 0 },
216+
{ x: 1.995, y: 8.925 },
217+
{ x: 10.395, y: 4.725 },
218+
{ x: 9.345, y: 1.575 },
219+
{ x: 5.145, y: -1.575 },
220+
{ x: 10.395, y: -6.825 },
221+
{ x: 6.195, y: -8.925 },
222+
{ x: 1.995, y: -7.455 },
223+
{ x: -4.305, y: -8.925 },
224+
{ x: -9.135, y: -3.255 },
225+
{ x: -9.135, y: 4.725 },
226+
{ x: -5.355, y: 4.725 },
227+
{ x: -5.355, y: 8.925 },
217228
],
218229
);
219230
assert.deepEqual(
@@ -241,13 +252,18 @@ export async function run() {
241252
assert.equal(largeUfoObject.shapes[0].geometry.points.length, 15);
242253
const mediumAsteroidVariant = loadAsteroidsObjectVectorPayload().objects.find((object) => object.id === 'object.asteroids.medium-asteroid');
243254
assert.deepEqual(mediumAsteroidVariant.shapes[0].geometry.points, [
244-
{ x: -16, y: -10 },
245-
{ x: -2, y: -18 },
246-
{ x: 16, y: -14 },
247-
{ x: 20, y: 2 },
248-
{ x: 8, y: 18 },
249-
{ x: -10, y: 16 },
250-
{ x: -20, y: 4 },
255+
{ x: 4.779, y: 19.845 },
256+
{ x: 24.219, y: 10.125 },
257+
{ x: 21.789, y: 2.835 },
258+
{ x: 12.069, y: -4.455 },
259+
{ x: 24.219, y: -16.605 },
260+
{ x: 14.499, y: -21.465 },
261+
{ x: 4.779, y: -18.063 },
262+
{ x: -9.801, y: -21.465 },
263+
{ x: -20.979, y: -8.343 },
264+
{ x: -20.979, y: 10.125 },
265+
{ x: -12.231, y: 10.125 },
266+
{ x: -12.231, y: 19.845 },
251267
]);
252268
const missingBulletManifest = structuredClone(manifestPayload);
253269
missingBulletManifest.tools['object-vector-studio-v2'].objects = missingBulletManifest.tools['object-vector-studio-v2'].objects
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import assert from "node:assert/strict";
2+
import { readFileSync, readdirSync } from "node:fs";
3+
import path from "node:path";
4+
import { fileURLToPath } from "node:url";
5+
import { getToolById } from "../../tools/toolRegistry.js";
6+
7+
const REPO_ROOT = fileURLToPath(new URL("../..", import.meta.url));
8+
const ACTIVE_OBJECT_VECTOR_PATHS = Object.freeze([
9+
"games/Asteroids/game",
10+
"games/Asteroids/entities",
11+
"games/Asteroids/systems",
12+
"games/Asteroids/flow",
13+
"tools/workspace-manager-v2/js",
14+
"tools/object-vector-studio-v2/js",
15+
"src/engine/rendering/ObjectVectorRuntimeAssetService.js"
16+
]);
17+
const DEPRECATED_VECTOR_MAPS_GUARD = "tools/object-vector-studio-v2/js/services/ObjectVectorStudioV2SchemaService.js";
18+
19+
function readRepoFile(repoPath) {
20+
return readFileSync(path.join(REPO_ROOT, repoPath), "utf8");
21+
}
22+
23+
function listSourceFiles(repoPath) {
24+
const absolutePath = path.join(REPO_ROOT, repoPath);
25+
if (repoPath.endsWith(".js") || repoPath.endsWith(".mjs")) {
26+
return [repoPath];
27+
}
28+
return readdirSync(absolutePath, { withFileTypes: true }).flatMap((entry) => {
29+
const childRepoPath = `${repoPath}/${entry.name}`;
30+
if (entry.isDirectory()) {
31+
return listSourceFiles(childRepoPath);
32+
}
33+
return entry.isFile() && (entry.name.endsWith(".js") || entry.name.endsWith(".mjs"))
34+
? [childRepoPath]
35+
: [];
36+
});
37+
}
38+
39+
function asteroidsObjectVectorPayload() {
40+
return JSON.parse(readRepoFile("games/Asteroids/game.manifest.json")).tools["object-vector-studio-v2"];
41+
}
42+
43+
function objectById(payload, objectId) {
44+
return payload.objects.find((object) => object.id === objectId);
45+
}
46+
47+
function maxRadius(points) {
48+
return Math.max(...points.map((point) => Math.hypot(point.x, point.y)));
49+
}
50+
51+
export async function run() {
52+
const activeSourceFiles = ACTIVE_OBJECT_VECTOR_PATHS.flatMap(listSourceFiles);
53+
const disallowedTerms = [
54+
"objectVectorRoles",
55+
"vector-map-editor",
56+
"fallback vector map",
57+
"default vector map",
58+
"defaultVectorMap"
59+
];
60+
activeSourceFiles.forEach((repoPath) => {
61+
const text = readRepoFile(repoPath);
62+
disallowedTerms.forEach((term) => {
63+
assert.equal(text.includes(term), false, `${repoPath} must not depend on ${term}.`);
64+
});
65+
if (repoPath !== DEPRECATED_VECTOR_MAPS_GUARD) {
66+
assert.equal(text.includes("vectorMaps"), false, `${repoPath} must not depend on legacy vectorMaps payload data.`);
67+
}
68+
});
69+
70+
const schemaServiceText = readRepoFile(DEPRECATED_VECTOR_MAPS_GUARD);
71+
assert.match(schemaServiceText, /root\.vectorMaps is deprecated legacy vector-map data/);
72+
assert.match(schemaServiceText, /objects\[\]\.tags and root\.objects\[\]\.shapes only/);
73+
74+
const vectorMapEditor = getToolById("vector-map-editor");
75+
assert.equal(vectorMapEditor.legacy, true, "Vector Map Editor must be marked legacy in the active registry.");
76+
assert.match(vectorMapEditor.shortDescription, /^Deprecated:/);
77+
78+
const objectVectorPayload = asteroidsObjectVectorPayload();
79+
assert.deepEqual(Object.keys(objectVectorPayload).sort(), ["name", "objects", "toolId", "version"]);
80+
assert.equal(Object.hasOwn(objectVectorPayload, "vectorMaps"), false);
81+
82+
const ship = objectById(objectVectorPayload, "object.asteroids.ship");
83+
const flameLines = ship.shapes.filter((shape) => shape.tool === "line" && shape.style?.stroke === "#FFBE64");
84+
assert.equal(flameLines.length, 4, "Asteroids ship flame duplicate line shapes are intentional flicker animation assets.");
85+
const moveState = ship.states.find((state) => state.id === "move");
86+
assert.equal(moveState.frames.length >= 2, true, "Asteroids ship move state must preserve flicker animation frames.");
87+
88+
const largeAsteroid = objectById(objectVectorPayload, "object.asteroids.large-asteroid");
89+
const mediumAsteroid = objectById(objectVectorPayload, "object.asteroids.medium-asteroid");
90+
const smallAsteroid = objectById(objectVectorPayload, "object.asteroids.small-asteroid");
91+
const largeRadius = maxRadius(largeAsteroid.shapes[0].geometry.points);
92+
const mediumRadius = maxRadius(mediumAsteroid.shapes[0].geometry.points);
93+
const smallRadius = maxRadius(smallAsteroid.shapes[0].geometry.points);
94+
assert.equal(largeRadius > mediumRadius && mediumRadius > smallRadius, true, "Asteroids object geometry must preserve arcade-scale large > medium > small proportions.");
95+
}

tools/object-vector-studio-v2/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ Use World Vector Studio V2 instead for terrain, maps, tile/world geometry, layer
2727

2828
## Migration Direction
2929

30-
- SVG Asset Studio functionality moves toward Object Vector Studio V2.
30+
- SVG Asset Studio object-level authoring moves toward Object Vector Studio V2.
3131
- Primitive Skin Editor remains deprecated compatibility during the transition.
32-
- Vector Map Editor remains deprecated compatibility during the transition.
33-
- Old tools remain available until replacement workflows are implemented and validated.
32+
- Vector Map Editor remains deprecated compatibility for older map documents; it is not a current Object Vector object-geometry source.
33+
- Current object geometry lives in Object Vector Studio V2 payloads as `objects[]`, `objects[].tags`, and `objects[].shapes`.
3434

3535
## Examples
3636

tools/object-vector-studio-v2/how_to_use.html

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ <h2>Architectural Split</h2>
2828

2929
<section class="card">
3030
<h2>Migration Direction</h2>
31-
<p>SVG Asset Studio functionality moves toward Object Vector Studio V2. Primitive Skin Editor and Vector Map Editor remain available as deprecated compatibility tools during the transition.</p>
31+
<p>SVG Asset Studio object-level authoring moves toward Object Vector Studio V2. Primitive Skin Editor remains deprecated compatibility during the transition. Vector Map Editor remains deprecated compatibility for older map documents and is not a current Object Vector object-geometry source.</p>
32+
<p>Current object geometry lives in Object Vector Studio V2 payloads as objects, object tags, and object shapes.</p>
3233
</section>
3334

3435
<section class="card">
@@ -40,7 +41,7 @@ <h2>Examples</h2>
4041

4142
<section class="card">
4243
<h2>Current State</h2>
43-
<p>This tool is currently a copied First-Class Tool V2 starter shell with Object Vector Studio V2 naming and documentation. Runtime object editing behavior is planned but not implemented in this documentation PR.</p>
44+
<p>This tool loads and edits schema-valid Object Vector Studio V2 object payloads through the current objects, tags, and shapes contract.</p>
4445
</section>
4546
</main>
4647
<script type="module" src="../../src/engine/theme/mount-shared-header.js"></script>

tools/toolRegistry.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export const TOOL_REGISTRY = Object.freeze([
1414
showcaseTag: "Geometry",
1515
showcaseStatus: "Deprecated",
1616
active: true,
17-
legacy: false,
17+
legacy: true,
1818
order: 1,
1919
sampleEntryPoints: [
2020
{

0 commit comments

Comments
 (0)