From 03c43237945b75ff9922b8d8788551eac27f26cf Mon Sep 17 00:00:00 2001 From: root Date: Sun, 13 Sep 2026 21:17:26 +0200 Subject: [PATCH] Image picker: tiles are containers, not graphics with children The twin of the font picker fixed earlier today: every tile was a Graphics carrying its sprite and caption, which Pixi v8 answers with "addChild: Only Containers will be allowed to add children". The background moves into its own Graphics inside a Container, and the step watches the console while the picker opens, as the font one does. Editor suite: 784 checks. Co-Authored-By: Claude Opus 5 --- README.md | 2 +- src/editor/texture/ImagePicker.ts | 17 ++++++++++------- tools/e2e/12-textures.mjs | 7 +++++++ 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 65c4869f..d643973e 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ npm run build # writes dist/ and regenerates index.html; the folder is wh The browser suite and the three example games need a machine with a GPU: ```bash -node tools/seed-e2e.mjs && node tools/e2e.mjs # the editor, 780 checks (GM_STEPS=20 for one step) +node tools/seed-e2e.mjs && node tools/e2e.mjs # the editor, 784 checks (GM_STEPS=20 for one step) node tools/seed-jumprun.mjs && node tools/smoke-jumprun.mjs node tools/seed-tetris.mjs && node tools/smoke-tetris.mjs node tools/seed-actor.mjs && node tools/smoke-actor.mjs diff --git a/src/editor/texture/ImagePicker.ts b/src/editor/texture/ImagePicker.ts index ada5f0fa..c6494666 100644 --- a/src/editor/texture/ImagePicker.ts +++ b/src/editor/texture/ImagePicker.ts @@ -1,4 +1,4 @@ -import { type FederatedPointerEvent, Graphics, Sprite, Text } from 'pixi.js'; +import { Container, type FederatedPointerEvent, Graphics, Sprite, Text } from 'pixi.js'; import type { StoredTexture } from '../../core/store/TextureStore'; import { Button, @@ -37,7 +37,7 @@ interface PickerItem extends StoredTexture { */ class ImageGrid extends Widget { private items: PickerItem[] = []; - private tiles: { box: Graphics; sprite: Sprite; caption: Text }[] = []; + private tiles: { box: Container; background: Graphics; sprite: Sprite; caption: Text }[] = []; private metrics: GridMetrics = gridMetrics(GRID_WIDTH, 0); private selectedFile: string | null = null; private readonly empty = new Text({ text: '', style: textStyle('muted') }); @@ -57,12 +57,15 @@ class ImageGrid extends Widget { this.items = items; for (const tile of this.tiles) tile.box.destroy({ children: true }); this.tiles = items.map(() => { - const box = new Graphics(); + // A Container holding the background, not a Graphics with children: Pixi v8 only lets + // containers have them (`addChild: Only Containers will be allowed to add children`). + const box = new Container(); + const background = new Graphics(); const sprite = new Sprite(); const caption = new Text({ style: textStyle('small') }); - box.addChild(sprite, caption); + box.addChild(background, sprite, caption); this.addChild(box); - return { box, sprite, caption }; + return { box, background, sprite, caption }; }); if (!items.some((item) => item.file === this.selectedFile)) this.selectedFile = null; this.layout(); @@ -128,8 +131,8 @@ class ImageGrid extends Widget { const item = this.items[index]; if (!item) return; const selected = item.file === this.selectedFile; - node.box.clear(); - drawControlBox(node.box, side, side, { + node.background.clear(); + drawControlBox(node.background, side, side, { fill: selected ? Theme.colors.selection : Theme.colors.control, border: selected ? Theme.colors.accent : Theme.colors.border, }); diff --git a/tools/e2e/12-textures.mjs b/tools/e2e/12-textures.mjs index aa140dd9..4fd7ce3e 100644 --- a/tools/e2e/12-textures.mjs +++ b/tools/e2e/12-textures.mjs @@ -292,6 +292,7 @@ export async function textures(t) { JSON.stringify(afterUndo), ); + await evaluate('__gm.console.clear()'); await clickText('+'); // By position, not by text: the menu entry "Texture" shares its label with the centre tab, and // `locate` would hand back whichever it walked into first. @@ -324,6 +325,12 @@ export async function textures(t) { JSON.stringify({ spare: captionOf(spare), used: captionOf(texture.file), asset: texture.name }), ); await shot('34-image-picker'); + // A tile is a container holding its background, not a Graphics with children: Pixi v8 warns + // about the latter, and the warning is the only sign that the tiles are built the wrong way. + const tileComplaints = (await json('__gm.console.lines()')).filter((line) => + /Deprecation/i.test(JSON.stringify(line)), + ); + check('building the tiles draws no complaint from Pixi', tileComplaints.length === 0, tileComplaints); const tile = await json(`__gm.imagePickerTile(${JSON.stringify(spare)})`); await click(tile.x, tile.y);