Skip to content

Commit 2679cb7

Browse files
author
DavidQ
committed
Finish Object Vector Studio V2 UI control surface for review and preserve World read-only object references - PR_26132_017-object-vector-studio-v2-ui-finish-pass
1 parent d6f2bee commit 2679cb7

11 files changed

Lines changed: 289 additions & 71 deletions

File tree

docs/dev/reports/playwright_v8_coverage.txt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ Exercised tool entry points detected:
2020
(0%) Workspace Manager - not exercised by this Playwright run
2121

2222
Changed runtime JS files covered:
23-
(80%) tools/object-vector-studio-v2/js/bootstrap.js - executed lines 100/100; executed functions 4/5
24-
(92%) tools/object-vector-studio-v2/js/ToolStarterApp.js - executed lines 2805/2805; executed functions 327/355
23+
(80%) tools/object-vector-studio-v2/js/bootstrap.js - executed lines 101/101; executed functions 4/5
24+
(91%) tools/object-vector-studio-v2/js/controls/ActionNavControl.js - executed lines 78/78; executed functions 10/11
25+
(92%) tools/object-vector-studio-v2/js/ToolStarterApp.js - executed lines 2862/2862; executed functions 328/356
2526
(95%) tools/object-vector-studio-v2/js/services/ObjectVectorStudioV2SchemaService.js - executed lines 406/406; executed functions 52/55
2627
(98%) src/engine/rendering/ObjectVectorRuntimeAssetService.js - executed lines 919/919; executed functions 105/107
27-
(100%) src/engine/rendering/index.js - executed lines 12/12; executed functions 1/1
2828

2929
Files with executed line/function counts where available:
3030
(2%) src/engine/input/ActionInputService.js - executed lines 397/397; executed functions 1/51
@@ -170,7 +170,7 @@ Files with executed line/function counts where available:
170170
(80%) src/engine/persistence/StorageService.js - executed lines 49/49; executed functions 4/5
171171
(80%) tools/asset-manager-v2/js/controls/AccordionSection.js - executed lines 27/27; executed functions 4/5
172172
(80%) tools/asset-manager-v2/js/controls/AssetFormControl.js - executed lines 563/563; executed functions 49/61
173-
(80%) tools/object-vector-studio-v2/js/bootstrap.js - executed lines 100/100; executed functions 4/5
173+
(80%) tools/object-vector-studio-v2/js/bootstrap.js - executed lines 101/101; executed functions 4/5
174174
(80%) tools/palette-manager-v2/modules/PaletteHistoryStack.js - executed lines 54/54; executed functions 8/10
175175
(80%) tools/preview-generator-v2/controls/AccordionSection.js - executed lines 31/31; executed functions 4/5
176176
(80%) tools/preview-generator-v2/PreviewGeneratorV2Logger.js - executed lines 19/19; executed functions 4/5
@@ -199,11 +199,11 @@ Files with executed line/function counts where available:
199199
(90%) tools/palette-manager-v2/modules/PaletteValidationService.js - executed lines 88/88; executed functions 9/10
200200
(90%) tools/text2speech-V2/js/controls/ActionNavControl.js - executed lines 117/117; executed functions 19/21
201201
(90%) tools/text2speech-V2/js/TextToSpeechToolApp.js - executed lines 807/807; executed functions 62/69
202-
(91%) tools/object-vector-studio-v2/js/controls/ActionNavControl.js - executed lines 75/75; executed functions 10/11
202+
(91%) tools/object-vector-studio-v2/js/controls/ActionNavControl.js - executed lines 78/78; executed functions 10/11
203203
(91%) tools/toolRegistry.js - executed lines 526/526; executed functions 10/11
204204
(91%) tools/workspace-manager-v2/js/services/WorkspaceManagerV2ContextService.js - executed lines 1598/1598; executed functions 145/159
205205
(92%) tools/object-vector-studio-v2/js/controls/ToolStarterShellControl.js - executed lines 112/112; executed functions 11/12
206-
(92%) tools/object-vector-studio-v2/js/ToolStarterApp.js - executed lines 2805/2805; executed functions 327/355
206+
(92%) tools/object-vector-studio-v2/js/ToolStarterApp.js - executed lines 2862/2862; executed functions 328/356
207207
(93%) tools/asset-manager-v2/js/services/WorkspaceBridge.js - executed lines 305/305; executed functions 25/27
208208
(93%) tools/session-inspector-v2/js/SessionInspectorV2App.js - executed lines 337/337; executed functions 42/45
209209
(93%) tools/text2speech-V2/js/controls/QueueControl.js - executed lines 122/122; executed functions 26/28
@@ -299,7 +299,7 @@ Changed JS files considered:
299299
(50%) games/Asteroids/index.js - changed JS file with browser V8 coverage
300300
(52%) games/Asteroids/game/AsteroidsGameScene.js - changed JS file with browser V8 coverage
301301
(80%) tools/object-vector-studio-v2/js/bootstrap.js - changed JS file with browser V8 coverage
302+
(91%) tools/object-vector-studio-v2/js/controls/ActionNavControl.js - changed JS file with browser V8 coverage
302303
(92%) tools/object-vector-studio-v2/js/ToolStarterApp.js - changed JS file with browser V8 coverage
303304
(95%) tools/object-vector-studio-v2/js/services/ObjectVectorStudioV2SchemaService.js - changed JS file with browser V8 coverage
304305
(98%) src/engine/rendering/ObjectVectorRuntimeAssetService.js - changed JS file with browser V8 coverage
305-
(100%) src/engine/rendering/index.js - changed JS file with browser V8 coverage
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# PR_26132_017-object-vector-studio-v2-ui-finish-pass
2+
3+
## Scope
4+
5+
Finishes Object Vector Studio V2 to a control-reviewable UI state without adding new major feature systems or changing the Object Vector schema. Adds the requested World Vector Studio V2 read-only Object Vector asset reference note.
6+
7+
## Changes
8+
9+
- Grouped Object Vector Studio V2 controls into reviewable Object Actions, Library / Detach, and State Actions sections.
10+
- Added visible disabled-control reason text and per-control disabled titles/data reasons.
11+
- Made selected object, selected shape, selected state, selected frame, and selection count explicit in the center work area.
12+
- Clarified Object Details as read-only object metadata plus schema-valid editable shape fields only.
13+
- Kept JSON Details readable and scrollable and verified Status Log remains the bottom-right scrollable section.
14+
- Clarified palette behavior as read-only session/workspace input; swatches apply color without mutating palette data.
15+
- Added visible tooltips for icon-capable shape/tool controls.
16+
- Added World Vector Studio V2 UI/help/README notes that Object Vector Studio V2 asset references are read-only and must not be mutated there.
17+
- Preserved Duplicate As Local as the only Object Vector detachment path for inherited source data.
18+
19+
## Validation
20+
21+
Playwright impacted: Yes.
22+
23+
Commands run:
24+
25+
- `node --check tools/object-vector-studio-v2/js/ToolStarterApp.js`
26+
- `node --check tools/object-vector-studio-v2/js/bootstrap.js`
27+
- `node --check tools/object-vector-studio-v2/js/controls/ActionNavControl.js`
28+
- `node --check tests/playwright/tools/WorkspaceManagerV2.spec.mjs`
29+
- `npx playwright test tests/playwright/tools/WorkspaceManagerV2.spec.mjs --project=playwright --workers=1 --reporter=list -g "World Vector Studio V2 and Object Vector Studio V2 copied|Object Vector Studio V2 layout shell|Object Vector Studio V2 animation states|Object Vector Studio V2 asset library"`
30+
- `npm run test:workspace-v2`
31+
- `git diff --check`
32+
33+
Result:
34+
35+
- Targeted Object/World Vector UI validation passed: 4 passed.
36+
- Full Workspace Manager V2 suite passed: 45 passed.
37+
- Playwright V8 coverage generated at `docs/dev/reports/playwright_v8_coverage.txt`.
38+
- Full samples smoke test skipped per request.
39+
40+
## Playwright Coverage
41+
42+
Validates:
43+
44+
- Object Vector Studio V2 visible control groups and button grouping.
45+
- Disabled control reason display and disabled reason attributes.
46+
- Selected object, shape, state, and frame visibility.
47+
- Palette read-only session/workspace behavior.
48+
- JSON Details scrollability and Status Log bottom-right scrollability.
49+
- World Vector Studio V2 read-only Object Vector asset reference rule in the tool surface.
50+
51+
Expected pass behavior:
52+
53+
- Controls are visible, grouped, explain disabled states, and show current selections clearly.
54+
- Palette remains read-only runtime/session data.
55+
- World Vector Studio V2 only documents and surfaces read-only Object Vector references.
56+
57+
Expected fail behavior:
58+
59+
- Missing payload, missing palette, missing selection, and invalid state/frame conditions keep relevant controls disabled with visible/actionable reasons.
60+
61+
## Manual Validation
62+
63+
1. Open `tools/object-vector-studio-v2/index.html`.
64+
2. Confirm Object Actions, Library / Detach, and State Actions are visible in the Object accordion.
65+
3. Confirm disabled buttons show a disabled reason and the visible disabled-control message explains the missing payload/selection state.
66+
4. Import a valid Object Vector payload with a runtime palette in session/workspace.
67+
5. Select objects, shapes, states, and frames and confirm the center selection summary updates.
68+
6. Confirm Palette says it is read-only session/workspace input.
69+
7. Open `tools/world-vector-studio-v2/index.html` and confirm the Object Vector asset reference rule is read-only and points users to Duplicate As Local for detachment.
70+
71+
Expected outcome:
72+
73+
- Object Vector Studio V2 is control-reviewable, with clear grouping, current selection visibility, readable JSON/status panels, and no palette mutation claim.
74+
- World Vector Studio V2 makes the read-only Object Vector asset boundary explicit.
75+
76+
## Out Of Scope
77+
78+
- No schema changes.
79+
- No sample JSON changes.
80+
- No new major feature systems.
81+
- No full samples smoke test.

tests/playwright/tools/WorkspaceManagerV2.spec.mjs

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,6 +1152,9 @@ test.describe("Workspace Manager V2 bootstrap", () => {
11521152
await expect(page.locator(".tool-starter__tool__menu")).toBeVisible();
11531153
await expect(page.locator(".tool-starter__workspace__menu")).toBeHidden();
11541154
if (tool.id === "world-vector-studio-v2") {
1155+
await expect(page.locator("#worldVectorStudioV2ObjectReferenceRule")).toContainText("Object Vector Studio V2 asset references are read-only");
1156+
await expect(page.locator("#worldVectorStudioV2ObjectReferenceRule")).toContainText("must not mutate Object Vector Studio V2 source assets");
1157+
await expect(page.locator("#worldVectorStudioV2ObjectReferenceRule")).toContainText("Duplicate As Local");
11551158
await page.locator("#sourceInput").fill(`${tool.name} launch coverage`);
11561159
await page.locator("#toolExportButton").click();
11571160
await expect(page.locator("#inspectorOutput")).toContainText(`"toolId": "${tool.id}"`);
@@ -1196,8 +1199,15 @@ test.describe("Workspace Manager V2 bootstrap", () => {
11961199
await expect(page.locator("#objectVectorStudioV2ObjectTiles")).toContainText("No objects loaded");
11971200
await expect(page.locator("#objectVectorStudioV2ObjectCount")).toHaveValue("0 objects");
11981201
await expect(page.locator("#objectVectorStudioV2RenameObjectButton")).toBeDisabled();
1202+
await expect(page.locator("#objectVectorStudioV2RenameObjectButton")).toHaveAttribute("data-disabled-reason", "Disabled until a schema-valid object is selected.");
11991203
await expect(page.locator("#objectVectorStudioV2DeleteObjectButton")).toBeDisabled();
12001204
await expect(page.locator("#objectVectorStudioV2FlattenObjectButton")).toBeDisabled();
1205+
await expect(page.locator("#objectVectorStudioV2DisabledReason")).toContainText("load a schema-valid payload");
1206+
await expect(page.locator("#objectVectorStudioV2DisabledReason")).toContainText("select an object");
1207+
await expect(page.locator("[data-control-group] > h3")).toHaveText(["Object Actions", "Library / Detach", "State Actions"]);
1208+
await expect(page.locator("[data-control-group='object-actions'] button")).toHaveText(["Add", "Create Template", "Rename", "Duplicate", "Delete", "Flatten"]);
1209+
await expect(page.locator("[data-control-group='library-detach-actions'] button")).toHaveText(["Duplicate As Local", "Create Library Asset"]);
1210+
await expect(page.locator("[data-control-group='library-detach-actions']")).toContainText("Duplicate As Local is the only detachment path");
12011211
await page.locator("#objectVectorStudioV2ObjectNameInput").fill("Blocked Object");
12021212
await page.locator("#objectVectorStudioV2AddObjectButton").click();
12031213
await expect(page.locator("#statusLog")).toHaveValue(/FAIL Add object blocked: load a schema-valid Object Vector Studio V2 payload before adding objects\./);
@@ -1316,7 +1326,8 @@ test.describe("Workspace Manager V2 bootstrap", () => {
13161326
await writeFile(validPayloadPath, JSON.stringify(validPayload, null, 2), "utf8");
13171327
await page.locator("#objectVectorStudioV2ImportJsonInput").setInputFiles(validPayloadPath);
13181328
await expect(page.locator("#objectVectorStudioV2PaletteGate")).toHaveValue("Palette loaded");
1319-
await expect(page.locator("#objectVectorStudioV2PaletteSummary")).toContainText("Palette arcade-primary: 2 swatches.");
1329+
await expect(page.locator("#objectVectorStudioV2PaletteSummary")).toContainText("Palette arcade-primary: 2 read-only swatches.");
1330+
await expect(page.locator("#objectVectorStudioV2PaletteSummary")).toContainText("not stored in Object Vector Studio V2 JSON");
13201331
const swatchState = await page.locator(".object-vector-studio-v2__palette-swatch").evaluateAll((swatches) => swatches.map((swatch) => {
13211332
const rect = swatch.getBoundingClientRect();
13221333
return {
@@ -1335,7 +1346,11 @@ test.describe("Workspace Manager V2 bootstrap", () => {
13351346
await expect(page.locator("#objectVectorStudioV2ObjectCount")).toHaveValue("18 objects");
13361347
await expect(page.locator("#objectVectorStudioV2ObjectDetails")).toContainText("Asteroids Ship");
13371348
await expect(page.locator("#objectVectorStudioV2ObjectDetails")).toContainText("Ship entity metadata framework");
1338-
await expect(page.locator("#objectVectorStudioV2SelectedItemVisibility")).toContainText("Selected item visible: Asteroids Ship");
1349+
await expect(page.locator("#objectVectorStudioV2ObjectDetails")).toContainText("Read-only Object Metadata");
1350+
await expect(page.locator("#objectVectorStudioV2SelectedItemVisibility")).toContainText("Selected Object: Asteroids Ship");
1351+
await expect(page.locator("#objectVectorStudioV2SelectedItemVisibility")).toContainText("Selected Shape: none");
1352+
await expect(page.locator("#objectVectorStudioV2DuplicateAsLocalButton")).toBeDisabled();
1353+
await expect(page.locator("#objectVectorStudioV2DuplicateAsLocalButton")).toHaveAttribute("data-disabled-reason", /inherits from a base object/);
13391354
await expect(page.locator("#objectVectorStudioV2RenderSurface")).toHaveAttribute("viewBox", "-160 -110 320 220");
13401355
await expect(page.locator("#objectVectorStudioV2RenderSurface [data-center-origin='0,0']")).toHaveCount(1);
13411356
await expect(page.locator("#objectVectorStudioV2JsonDetails")).toContainText('"name": "Asteroids Ship"');
@@ -1353,6 +1368,8 @@ test.describe("Workspace Manager V2 bootstrap", () => {
13531368
await expect(page.locator("#objectVectorStudioV2JsonDetails")).toContainText('"selectedShape"');
13541369
await expect(page.locator("#objectVectorStudioV2JsonDetails")).toContainText('"type": "rectangle"');
13551370
await expect(page.locator("#objectVectorStudioV2ObjectDetails")).toContainText("Rectangle primitive metadata");
1371+
await expect(page.locator("#objectVectorStudioV2ObjectDetails")).toContainText("Editable fields below are limited to schema-valid geometry");
1372+
await expect(page.locator("#objectVectorStudioV2SelectedItemVisibility")).toContainText("Selected Shape: rectangle-1 (rectangle)");
13561373
await expect(page.locator("#statusLog")).toHaveValue(/OK Created rectangle shape rectangle-1 on Asteroids Ship\./);
13571374
await expect(page.locator("#statusLog")).toHaveValue(/OK Render mode svg-work-surface: rendered Asteroids Ship with 1 visible shapes; capture mode none\./);
13581375

@@ -1386,10 +1403,26 @@ test.describe("Workspace Manager V2 bootstrap", () => {
13861403
await page.locator("#objectVectorStudioV2RenderSurface [data-shape-id='circle-2']").click({ modifiers: ["Shift"] });
13871404
await expect(page.locator("#objectVectorStudioV2RenderSurface [data-shape-id='rectangle-1']")).toHaveClass(/is-selected/);
13881405
await expect(page.locator("#objectVectorStudioV2RenderSurface [data-shape-id='circle-2']")).toHaveClass(/is-selected/);
1389-
await expect(page.locator("#objectVectorStudioV2SelectedItemVisibility")).toContainText("2 shape selection");
1406+
await expect(page.locator("#objectVectorStudioV2SelectedItemVisibility")).toContainText("Selection Count: 2 shapes");
13901407
await expect(page.locator("#objectVectorStudioV2JsonDetails")).toContainText('"selectedShapeIds"');
13911408
await page.locator("#objectVectorStudioV2RenderSurface [data-shape-id='rectangle-1']").click();
13921409
await expect(page.locator("#objectVectorStudioV2ObjectDetails")).toContainText("Rectangle Geometry");
1410+
const reviewLayoutState = await page.evaluate(() => {
1411+
const jsonContent = document.querySelector("#objectVectorStudioV2JsonDetailsContent");
1412+
const statusSection = document.querySelector("#statusLogContent").closest(".accordion-v2");
1413+
const rightPanel = document.querySelector(".tool-starter__panel--right");
1414+
const rightSections = Array.from(rightPanel.querySelectorAll(":scope > .accordion-v2"));
1415+
return {
1416+
jsonScrollable: getComputedStyle(jsonContent).overflowY === "auto" || getComputedStyle(jsonContent).overflowY === "scroll",
1417+
statusIsBottomRight: rightSections.at(-1) === statusSection,
1418+
statusScrollable: getComputedStyle(document.querySelector("#statusLog")).overflowY === "auto" || getComputedStyle(document.querySelector("#statusLog")).overflowY === "scroll"
1419+
};
1420+
});
1421+
expect(reviewLayoutState).toEqual({
1422+
jsonScrollable: true,
1423+
statusIsBottomRight: true,
1424+
statusScrollable: true
1425+
});
13931426

13941427
await page.locator("#objectVectorStudioV2GridSnapButton").click();
13951428
await expect(page.locator("#objectVectorStudioV2GridSnapButton")).toHaveAttribute("aria-pressed", "true");
@@ -1764,6 +1797,8 @@ test.describe("Workspace Manager V2 bootstrap", () => {
17641797
await expect(page.locator("#objectVectorStudioV2FrameTimeline [data-state-id='idle']")).toHaveCount(1);
17651798
await expect(page.locator("#objectVectorStudioV2FrameTimeline [data-frame-id='idle-frame-1']")).toHaveAttribute("aria-pressed", "true");
17661799
await expect(page.locator("#objectVectorStudioV2JsonDetails")).toContainText('"id": "idle"');
1800+
await expect(page.locator("#objectVectorStudioV2SelectedItemVisibility")).toContainText("Selected State: idle");
1801+
await expect(page.locator("#objectVectorStudioV2SelectedItemVisibility")).toContainText("Selected Frame: idle-frame-1");
17671802
await expect(page.locator("#statusLog")).toHaveValue(/OK Created state Idle with frame idle-frame-1\./);
17681803

17691804
await page.locator("#objectVectorStudioV2DuplicateFrameButton").click();
@@ -1983,6 +2018,8 @@ test.describe("Workspace Manager V2 bootstrap", () => {
19832018
await expect(page.locator("#objectVectorStudioV2ObjectDetails")).toContainText("Base Object");
19842019
await expect(page.locator("#objectVectorStudioV2ObjectDetails")).toContainText("base-ship");
19852020
await expect(page.locator("#objectVectorStudioV2ObjectDetails")).toContainText("Base shapes/states are read-only until Duplicate As Local");
2021+
await expect(page.locator("#objectVectorStudioV2DuplicateAsLocalButton")).toBeEnabled();
2022+
await expect(page.locator("#objectVectorStudioV2DisabledReason")).toContainText("All current Object Vector Studio V2 controls are reviewable");
19862023

19872024
await page.locator("#objectVectorStudioV2RuntimePreviewButton").click();
19882025
await expect(page.locator("#objectVectorStudioV2RenderSurface")).toHaveAttribute("data-runtime-preview", "true");
@@ -5063,7 +5100,8 @@ test.describe("Workspace Manager V2 bootstrap", () => {
50635100
await expect(page.locator(".tool-starter__workspace__menu button")).toHaveText(["Return to Workspace"]);
50645101
await expect(page.locator(".tool-starter__tool__menu")).toBeHidden();
50655102
await expect(page.locator("#objectVectorStudioV2PaletteGate")).toHaveValue("Palette loaded");
5066-
await expect(page.locator("#objectVectorStudioV2PaletteSummary")).toContainText("10 swatches.");
5103+
await expect(page.locator("#objectVectorStudioV2PaletteSummary")).toContainText("10 read-only swatches.");
5104+
await expect(page.locator("#objectVectorStudioV2PaletteSummary")).toContainText("not stored in Object Vector Studio V2 JSON");
50675105
await expect(page.locator("#objectVectorStudioV2ObjectCount")).toHaveValue("6 objects");
50685106
await expect(page.locator("#objectVectorStudioV2ObjectTiles")).toContainText("Asteroids Ship");
50695107
await expect(page.locator("#objectVectorStudioV2ObjectTiles")).toContainText("Large Asteroid");

0 commit comments

Comments
 (0)