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>
25 lines
1.1 KiB
TypeScript
25 lines
1.1 KiB
TypeScript
/**
|
||
* How big a picture of `w`×`h` units is drawn in a preview of `room` and where its top left lands.
|
||
* `pad` is the room a worn shader asks for around it, as a share of each side (see `quadPadding`).
|
||
* From one device pixel per unit on the zoom is whole device pixels, and the corner sits on one, so
|
||
* pixel art stays sharp; below that the picture only shrinks to fit. `ratio` is device pixels per
|
||
* panel pixel.
|
||
*/
|
||
export function previewFit(
|
||
w: number,
|
||
h: number,
|
||
room: { w: number; h: number },
|
||
options: { margin: number; maxZoom: number; ratio: number; pad?: { u: number; v: number } | null },
|
||
): { zoom: number; x: number; y: number } {
|
||
const { margin, maxZoom, ratio, pad } = options;
|
||
const fits = Math.min(
|
||
(room.w - 2 * margin) / (w * (1 + 2 * (pad?.u ?? 0))),
|
||
(room.h - 2 * margin) / (h * (1 + 2 * (pad?.v ?? 0))),
|
||
maxZoom,
|
||
);
|
||
const device = fits * ratio;
|
||
const zoom = Math.max(0, device >= 1 ? Math.floor(device) / ratio : fits);
|
||
const corner = (space: number, size: number) => Math.round(((space - size * zoom) / 2) * ratio) / ratio;
|
||
return { zoom, x: corner(room.w, w), y: corner(room.h, h) };
|
||
}
|