Texture tab: one masked container for everything the view moves (#82)

Only the picture was masked, so the checkerboard, the frame outlines, the
handles and the name plates were drawn over the panel next door once the
sheet was zoomed past the tab. The dark block in the report is the
checkerboard's base: checker.ts fills the whole image rect and clips only
the light squares to the widget.

Everything that pans and zooms now sits in one masked container, the
pattern WorldViewport and AnimationCanvas already use. A check samples
pixels outside the tab and names the frames drawn past it; a guard in
front of it asserts that zooming really pushes the sheet over every edge,
or the pixel probes would measure nothing and stay green forever.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
rootandClaude Opus 5 committed 2026-09-13 21:17:21 +02:00
1 parent fe036db8f2
commit 4f240a50fd
4 files changed
+58 -17

No files matched your search

+6 -15
View File
@@ -61,8 +61,9 @@ interface NewFrame {
*/
export class TextureCanvas extends Widget {
private readonly bg = new Graphics();
/** Everything the view can move: panned or zoomed, all of it reaches past the widget. */
private readonly content = new Container();
private readonly checker = new Graphics();
private readonly imageLayer = new Container();
private readonly image = new Sprite();
private readonly overlay = new Graphics();
private readonly labels = new Map<string, Text>();
@@ -79,20 +80,10 @@ export class TextureCanvas extends Widget {
constructor(private readonly state: EditorState) {
super();
this.imageLayer.addChild(this.image);
this.addChild(
this.bg,
this.checker,
this.imageLayer,
this.overlay,
this.labelLayer,
this.hint,
this.clip,
);
this.imageLayer.mask = this.clip;
this.imageLayer.eventMode = 'none';
this.overlay.eventMode = 'none';
this.labelLayer.eventMode = 'none';
this.content.addChild(this.checker, this.image, this.overlay, this.labelLayer);
this.addChild(this.bg, this.content, this.hint, this.clip);
this.content.mask = this.clip;
this.content.eventMode = 'none';
this.hint.eventMode = 'none';
this.focusable = true;