Preview a sprite at the end of its inspector, placed or as an asset
A sprite's inspector listed its rows but never showed what they add up to. The picture, its frame, nine-slice, tint and shader could only be judged in the scene, often far from the object being edited. - SpritePreview draws the sprite through syncSpriteMesh, the function the scene draws it with. Slices, padding, tint and shader come out the same without a second path. syncSpriteMesh now takes only the three fields of a DrawItem it reads. - The subject is resolved by previewPicture from the Shader tab, so a placed sprite shows its own overrides. - previewFit is the rule for size and place: whole device pixels per unit from 1 on, at most 8, and the corner on a whole device pixel. Pixel art stays sharp. A sprite larger than the group shrinks freely. - A shader with a Time node keeps the preview redrawing once a frame while it is on screen. A folded group or a hidden panel stops it. - New test hook __gm.inspectorSpritePreview(). Finding: the preview redrew on a model change in a microtask at first. A drawn picture whose revision moved on is retried once, in a microtask queued by the scene's synchronous redraw. That retry ran before the preview had let go, and the old pixel art sheet stayed waiting (e2e 48l-iii read waiting [1,1,1]). The preview now redraws at once on a model change, as the scene does. Tests: - unit: 238 files, 3592 tests (+5 in preview-fit.test.ts), and the group list of a placed sprite in sections.test.ts ends in PREVIEW - e2e 48: ALL PASSED, 47 checks (+2: 48l-i asset preview with the frame, 48l-iii placed preview with its shader values) - counter-checks: without whole-pixel zoom 2 unit tests fail; with the microtask redraw 48l-iii fails with waiting [1,1,1] Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1665576fb9
commit
3f12a77aea
10 files changed
+239
-4
No files matched your search
@@ -675,6 +675,26 @@ export async function pixelArt(t) {
|
||||
JSON.stringify({ spriteRed, spriteBlue }),
|
||||
);
|
||||
|
||||
// 48l-i. The inspector previews the selected sprite as the scene draws it, frame and all.
|
||||
const previewSpots = async () => {
|
||||
const rect = await json('__gm.inspectorSpritePreview()');
|
||||
await settle();
|
||||
if (!rect) return null;
|
||||
const at = (px, py) =>
|
||||
json(
|
||||
`__gm.pixelAt(${Math.round(rect.x + ((px + 0.5) / 32) * rect.w)}, ${Math.round(rect.y + ((py + 0.5) / 32) * rect.h)})`,
|
||||
);
|
||||
return { rect, red: await at(5, 2), blue: await at(10, 10) };
|
||||
};
|
||||
const assetPreview = await previewSpots();
|
||||
check(
|
||||
'the inspector previews the sprite asset with the frame it wears',
|
||||
Boolean(assetPreview) &&
|
||||
colourDistance(assetPreview.red, HEX[RED]) < 12 &&
|
||||
colourDistance(assetPreview.blue, HEX[BLUE]) < 12,
|
||||
JSON.stringify(assetPreview),
|
||||
);
|
||||
|
||||
// 48l-ii. Nine-slice on pixel art (#308): 12-pixel borders at scale 2 draw the corner at 2 units a
|
||||
// pixel instead of 4, so red (5, 2) and blue (10, 10) move to units (11, 5) and (21, 21). The same
|
||||
// spots are read before the borders are set, so a sprite that ignored them could not pass.
|
||||
@@ -710,7 +730,8 @@ export async function pixelArt(t) {
|
||||
// once and the cut with it, and Pixi warned for the source and its sampler every time.
|
||||
await mutate(`
|
||||
Object.assign(__gm.state.activeScene.objects.find((o) => o.id === 'pa-object').overrides,
|
||||
{ shader: 'adjust-colors', saturation: 0 })`);
|
||||
{ shader: 'adjust-colors', saturation: 0 });
|
||||
__gm.state.select({ kind: 'object', holderId: __gm.state.activeScene.id, objectId: 'pa-object', objectIds: ['pa-object'] })`);
|
||||
await settle();
|
||||
await sleep(300);
|
||||
const boundLogFrom = t.consoleLog.length;
|
||||
@@ -730,10 +751,22 @@ export async function pixelArt(t) {
|
||||
boundWarnings.length === 0 && waiting.every((n) => n === 0),
|
||||
JSON.stringify({ warnings: boundWarnings.length, waiting }),
|
||||
);
|
||||
// The preview of the placed object wears its shader and its own saturation of 0: no colour left.
|
||||
const objectPreview = await previewSpots();
|
||||
const grey = (c) => {
|
||||
const [r, g, b] = [1, 3, 5].map((i) => parseInt(c.slice(i, i + 2), 16));
|
||||
return Math.max(r, g, b) - Math.min(r, g, b) <= 6;
|
||||
};
|
||||
check(
|
||||
"the preview of a placed sprite draws its shader with the object's own values",
|
||||
Boolean(objectPreview) && grey(objectPreview.red) && grey(objectPreview.blue),
|
||||
JSON.stringify(objectPreview),
|
||||
);
|
||||
await mutate(`
|
||||
const o = __gm.state.activeScene.objects.find((o) => o.id === 'pa-object');
|
||||
delete o.overrides.shader;
|
||||
delete o.overrides.saturation;`);
|
||||
delete o.overrides.saturation;
|
||||
__gm.state.select({ kind: 'asset', assetId: 'pa-sprite' })`);
|
||||
await settle();
|
||||
|
||||
const textureRow = await json("__gm.inspectorField('Texture', true)");
|
||||
|
||||
Reference in new issue
Block a user