Skip to content

Commit d29b93b

Browse files
author
DavidQ
committed
Restore bezel role handling and add preview/background stretch support - PR_26127_008-asset-role-preview-and-background-stretch
1 parent 58584e4 commit d29b93b

9 files changed

Lines changed: 232 additions & 54 deletions

File tree

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# PR_26127_008 Asset Role Preview And Background Stretch
2+
3+
## Scope
4+
- Restored `bezel` as its own Asset Manager V2 image role and kept `preview` as a separate image role.
5+
- Added image background stretch handling with default `uniformEdgeStretchPx: 0`.
6+
- Kept bezel stretch handling with default `uniformEdgeStretchPx: 10`.
7+
- Kept deprecated `tools/workspace-v2` and sample JSON untouched.
8+
9+
## Implementation Notes
10+
- `tools/asset-manager-v2/js/assetManagerMetadata.js`
11+
- Image roles now include `sprite`, `background`, `bezel`, `preview`, and `ui`.
12+
- Filename role suggestion now resolves `bezel` before `preview`, so bezel files are not collapsed into preview.
13+
- `tools/asset-manager-v2/js/controls/AssetFormControl.js`
14+
- Stretch Override is shown only for image `background` and image `bezel`.
15+
- Background stretch defaults to `0`; bezel stretch defaults to `10`.
16+
- Color role `background` does not receive image stretch behavior.
17+
- `tools/asset-manager-v2/js/services/AssetSchemaValidator.js`
18+
- Generated entries add `stretchOverride` only for image `background` and image `bezel`.
19+
- Schema validation rejects `stretchOverride` outside `assets.image.background.*` and `assets.image.bezel.*`.
20+
- `tools/schemas/tools/asset-manager-v2.schema.json`
21+
- Added `bezel` to image role declarations.
22+
- Allows stretch only on background and bezel image asset IDs.
23+
- `games/Asteroids/game.manifest.json`
24+
- Keeps `assets.image.preview.bezel` as the Preview Generator V2 preview selection.
25+
- Adds `assets.image.bezel.bezel` for bezel stretch ownership.
26+
- Adds `stretchOverride.uniformEdgeStretchPx: 0` to the background image asset.
27+
28+
## Validation
29+
- PASS: `node --check tools/asset-manager-v2/js/assetManagerMetadata.js`
30+
- PASS: `node --check tools/asset-manager-v2/js/controls/AssetFormControl.js`
31+
- PASS: `node --check tools/asset-manager-v2/js/services/AssetSchemaValidator.js`
32+
- PASS: JSON parse for `tools/schemas/tools/asset-manager-v2.schema.json` and `games/Asteroids/game.manifest.json`
33+
- PASS: Asset Manager V2 payload validation for `games/Asteroids/game.manifest.json`
34+
- PASS: Workspace Manager V2 manifest validation for `games/Asteroids/game.manifest.json`
35+
- PASS: Workspace Manager V2 manifest validation for `games/_template/workspace-manager-v2-UAT.manifest.json`
36+
- PASS: `npm run test:workspace-v2` completed with 24 passed.
37+
- SKIPPED: full samples smoke test. This PR is scoped to Asset Manager V2 metadata/settings and Workspace V2 tool validation.
38+
39+
## Manual Validation Notes
40+
- Image file `chrome-bezel.png` auto-selects role `bezel`, generates `assets.image.bezel.chrome-bezel`, and shows Bezel Stretch PX with value `10`.
41+
- Image file `preview.png` auto-selects role `preview`, generates `assets.image.preview.preview`, and does not show Stretch Override.
42+
- Image file `nebula-background.png` auto-selects role `background`, generates `assets.image.background.nebula-background`, and shows Background Stretch PX with value `0`.
43+
- Color role `background` remains a palette color usage role and does not show or persist image stretch.
44+
45+
## Coverage
46+
- Playwright/V8 coverage report: `docs/dev/reports/playwright_v8_coverage_report.txt`
47+
- Changed Asset Manager V2 runtime files were collected by browser V8 coverage during `npm run test:workspace-v2`.

games/Asteroids/assets/images/preview.svg

Lines changed: 3 additions & 0 deletions
Loading

games/Asteroids/game.manifest.json

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,17 +163,27 @@
163163
"type": "image",
164164
"kind": "png",
165165
"role": "background",
166-
"source": "manifest"
166+
"source": "manifest",
167+
"stretchOverride": {
168+
"uniformEdgeStretchPx": 0
169+
}
167170
},
168-
"assets.image.preview.bezel": {
171+
"assets.image.bezel.bezel": {
169172
"path": "assets/images/bezel.png",
170173
"type": "image",
171174
"kind": "png",
172-
"role": "preview",
175+
"role": "bezel",
173176
"source": "manifest",
174177
"stretchOverride": {
175178
"uniformEdgeStretchPx": 10
176179
}
180+
},
181+
"assets.image.preview.bezel": {
182+
"path": "assets/images/bezel.png",
183+
"type": "image",
184+
"kind": "png",
185+
"role": "preview",
186+
"source": "manifest"
177187
}
178188
}
179189
},

tests/playwright/tools/AssetManagerV2.spec.mjs

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -422,16 +422,20 @@ test.describe("Asset Manager V2", () => {
422422
await expect(page.locator("#assetRoleSelect")).toHaveValue("music");
423423
await page.locator("#assetKindImage").check();
424424
await expect(page.locator("#assetRoleSelect")).toHaveValue("sprite");
425-
await expect(page.locator("#assetRoleSelect option")).toHaveText(["sprite", "background", "preview", "ui"]);
426-
await expect(page.locator("#assetRoleSelect")).toHaveAttribute("title", "Allowed roles for image: sprite, background, preview, ui");
425+
await expect(page.locator("#assetRoleSelect option")).toHaveText(["sprite", "background", "bezel", "preview", "ui"]);
426+
await expect(page.locator("#assetRoleSelect")).toHaveAttribute("title", "Allowed roles for image: sprite, background, bezel, preview, ui");
427427
await page.locator("#pickAssetFileButton").click();
428428
const pickerOptions = await page.evaluate(() => window.__assetManagerV2PickerOptions.at(-1));
429429
expect(pickerOptions.types[0].description).toBe("Image assets");
430430
expect(Object.keys(pickerOptions.types[0].accept)).toContain("image/png");
431431
await expect(page.locator("#assetRoleSelect")).toHaveValue("background");
432432
await expect(page.locator("#assetIdInput")).toHaveValue("assets.image.background.nebula-background");
433433
await expect(page.locator("#assetPathInput")).toHaveValue("assets/images/nebula-background.png");
434-
await expect(page.locator("#assetStretchOverrideField")).toBeHidden();
434+
await expect(page.locator("#assetStretchOverrideField")).toBeVisible();
435+
await expect(page.locator("#assetStretchOverrideField legend")).toHaveText("Stretch Override");
436+
await expect(page.locator("label[for='assetStretchOverrideInput'] span")).toHaveText("Background Stretch PX");
437+
await expect(page.locator("#assetStretchOverrideInput")).toBeEnabled();
438+
await expect(page.locator("#assetStretchOverrideInput")).toHaveValue("0");
435439
await expect(page.locator("#statusLog")).toHaveValue(/OK Selected file nebula-background\.png validated as type image, kind png, role background\./);
436440
await expect(page.locator("#addAssetButton")).toBeEnabled();
437441
await page.locator("#addAssetButton").click();
@@ -507,7 +511,9 @@ test.describe("Asset Manager V2", () => {
507511
await expect(page.locator("#inspectorOutput")).toContainText("\"kind\": \"png\"");
508512
await expect(page.locator("#inspectorOutput")).not.toContainText("Added assets.image.background.nebula-background");
509513
const backgroundOutput = JSON.parse(await page.locator("#inspectorOutput").textContent());
510-
expect(backgroundOutput.assets.find((asset) => asset.id === "assets.image.background.nebula-background").stretchOverride).toBeUndefined();
514+
expect(backgroundOutput.assets.find((asset) => asset.id === "assets.image.background.nebula-background").stretchOverride).toEqual({
515+
uniformEdgeStretchPx: 0
516+
});
511517
const accordionBottomSpacing = await page.evaluate(() => {
512518
const measureTrailingGap = (contentId) => {
513519
const content = document.getElementById(contentId);
@@ -545,6 +551,7 @@ test.describe("Asset Manager V2", () => {
545551
await page.locator("#pickAssetFileButton").click();
546552
await expect(page.locator("#assetRoleSelect")).toHaveValue("preview");
547553
await expect(page.locator("#assetIdInput")).toHaveValue("assets.image.preview.preview");
554+
await expect(page.locator("#assetStretchOverrideField")).toBeHidden();
548555
await page.locator("#addAssetButton").click();
549556

550557
await queueAssetFile(page, {
@@ -554,10 +561,11 @@ test.describe("Asset Manager V2", () => {
554561
path: "C:\\Users\\davidq\\Documents\\GitHub\\HTML-JavaScript-Gaming\\assets\\images\\chrome-bezel.png"
555562
});
556563
await page.locator("#pickAssetFileButton").click();
557-
await expect(page.locator("#assetRoleSelect")).toHaveValue("preview");
558-
await expect(page.locator("#assetIdInput")).toHaveValue("assets.image.preview.chrome-bezel");
564+
await expect(page.locator("#assetRoleSelect")).toHaveValue("bezel");
565+
await expect(page.locator("#assetIdInput")).toHaveValue("assets.image.bezel.chrome-bezel");
559566
await expect(page.locator("#assetStretchOverrideField")).toBeVisible();
560567
await expect(page.locator("#assetStretchOverrideField legend")).toHaveText("Stretch Override");
568+
await expect(page.locator("label[for='assetStretchOverrideInput'] span")).toHaveText("Bezel Stretch PX");
561569
await expect(page.locator("#assetStretchOverrideInput")).toBeEnabled();
562570
await expect(page.locator("#assetStretchOverrideInput")).toHaveValue("10");
563571
const stretchGroupStyle = await page.locator("#assetStretchOverrideField").evaluate((fieldset) => {
@@ -571,7 +579,7 @@ test.describe("Asset Manager V2", () => {
571579
expect(stretchGroupStyle).toEqual({ borderStyle: "solid", borderWidth: 1, radius: 8 });
572580
await page.locator("#addAssetButton").click();
573581
const previewOutput = JSON.parse(await page.locator("#inspectorOutput").textContent());
574-
expect(previewOutput.assets.find((asset) => asset.id === "assets.image.preview.chrome-bezel").stretchOverride).toEqual({
582+
expect(previewOutput.assets.find((asset) => asset.id === "assets.image.bezel.chrome-bezel").stretchOverride).toEqual({
575583
uniformEdgeStretchPx: 10
576584
});
577585

@@ -674,8 +682,8 @@ test.describe("Asset Manager V2", () => {
674682
},
675683
{
676684
deleteTopRight: true,
677-
typeRole: "image:preview",
678-
id: "assets.image.preview.chrome-bezel",
685+
typeRole: "image:bezel",
686+
id: "assets.image.bezel.chrome-bezel",
679687
textLeftAligned: true,
680688
hasSeparateDeleteButton: false,
681689
hasInlineDelete: true,
@@ -690,8 +698,8 @@ test.describe("Asset Manager V2", () => {
690698
idFontWeight: 500,
691699
typeRoleFontWeight: 800,
692700
rowGap: 2,
693-
text: "X\nimage:preview\nassets.image.preview.chrome-bezel",
694-
tooltip: "id: assets.image.preview.chrome-bezel\ntype: image\nkind: png\nrole: preview\npath: assets/images/chrome-bezel.png"
701+
text: "X\nimage:bezel\nassets.image.bezel.chrome-bezel",
702+
tooltip: "id: assets.image.bezel.chrome-bezel\ntype: image\nkind: png\nrole: bezel\npath: assets/images/chrome-bezel.png"
695703
},
696704
{
697705
deleteTopRight: true,
@@ -1270,14 +1278,14 @@ test.describe("Asset Manager V2", () => {
12701278
await expect(page.locator("#returnToWorkspaceButton")).toBeEnabled();
12711279
await expect(page.locator("#workspaceInsertAssetsButton")).toHaveCount(0);
12721280
await expect(page.locator("#workspaceCopyManifestButton")).toHaveCount(0);
1273-
await expect(page.locator("#statusLog")).toHaveValue(/Workspace Manager V2 loaded 13 validated assets from tools\.asset-manager-v2\.assets/);
1281+
await expect(page.locator("#statusLog")).toHaveValue(/Workspace Manager V2 loaded 14 validated assets from tools\.asset-manager-v2\.assets/);
12741282
await expect(page.locator("#statusLog")).toHaveValue(/Workspace Manager V2 loaded \d+ palette colors from active palette context/);
12751283
const hostContextId = await page.evaluate(() => new URL(window.location.href).searchParams.get("hostContextId"));
12761284
const initialAssetCount = await page.evaluate((id) => {
12771285
const context = JSON.parse(sessionStorage.getItem(id));
12781286
return Object.keys(context.tools["asset-manager-v2"].assets).length;
12791287
}, hostContextId);
1280-
expect(initialAssetCount).toBe(13);
1288+
expect(initialAssetCount).toBe(14);
12811289
const workspacePreviewContext = await page.evaluate(async () => {
12821290
const { WorkspaceBridge } = await import("/tools/asset-manager-v2/js/services/WorkspaceBridge.js");
12831291
return new WorkspaceBridge({ windowRef: window }).readWorkspacePreviewContext();
@@ -1377,7 +1385,7 @@ test.describe("Asset Manager V2", () => {
13771385
await expect(page.locator("#inspectorOutput")).toContainText("\"type\": \"color\"");
13781386
await expect(page.locator("#inspectorOutput")).toContainText("\"kind\": \"hex\"");
13791387
await expect(page.locator("#inspectorOutput")).toContainText("\"name\": \"HUD Blue\"");
1380-
await expect(page.locator("#statusLog")).toHaveValue(/OK Workspace Manager V2 session manifest now has 17 validated assets\./);
1388+
await expect(page.locator("#statusLog")).toHaveValue(/OK Workspace Manager V2 session manifest now has 18 validated assets\./);
13811389

13821390
const storedContext = await page.evaluate((id) => JSON.parse(sessionStorage.getItem(id)), hostContextId);
13831391
expect(storedContext.documentKind).toBe("workspace-manifest");
@@ -1386,7 +1394,7 @@ test.describe("Asset Manager V2", () => {
13861394
expect(storedContext.workspaceManifest).toBeUndefined();
13871395
expect(storedContext.tools["asset-browser"]).toBeUndefined();
13881396
expect(storedContext.tools["palette-browser"]).toBeUndefined();
1389-
expect(Object.keys(storedContext.tools["asset-manager-v2"].assets)).toHaveLength(17);
1397+
expect(Object.keys(storedContext.tools["asset-manager-v2"].assets)).toHaveLength(18);
13901398
expect(storedContext.tools["asset-manager-v2"].previewImagePath).toBeUndefined();
13911399
expect(storedContext.tools["asset-manager-v2"].assets["assets.audio.sound.fire"]).toEqual({
13921400
path: "assets/audio/fire.wav",
@@ -1414,10 +1422,7 @@ test.describe("Asset Manager V2", () => {
14141422
type: "image",
14151423
kind: "png",
14161424
role: "preview",
1417-
source: "asset-manager-v2",
1418-
stretchOverride: {
1419-
uniformEdgeStretchPx: 10
1420-
}
1425+
source: "asset-manager-v2"
14211426
});
14221427
expect(storedContext.tools["asset-manager-v2"].assets["assets.color.hud.primary-hud.hud-blue"]).toEqual({
14231428
path: "palette://workspace/hud-blue",
@@ -1447,7 +1452,7 @@ test.describe("Asset Manager V2", () => {
14471452
const download = await downloadPromise;
14481453
expect(download.suggestedFilename()).toBe("workspace-manager-v2-Asteroids.workspace.manifest.json");
14491454
const savedManifest = JSON.parse(await readFile(await download.path(), "utf8"));
1450-
expect(Object.keys(savedManifest.tools["asset-manager-v2"].assets)).toHaveLength(17);
1455+
expect(Object.keys(savedManifest.tools["asset-manager-v2"].assets)).toHaveLength(18);
14511456
expect(savedManifest.tools["asset-manager-v2"].previewImagePath).toBeUndefined();
14521457
expect(savedManifest.tools["asset-manager-v2"].assets["assets.audio.sound.laser"]).toEqual(storedContext.tools["asset-manager-v2"].assets["assets.audio.sound.laser"]);
14531458
expect(savedManifest.tools["asset-manager-v2"].assets["assets.color.hud.primary-hud.hud-blue"]).toEqual(storedContext.tools["asset-manager-v2"].assets["assets.color.hud.primary-hud.hud-blue"]);

0 commit comments

Comments
 (0)