Trim needless comments and fix the picker width
Remove comments that only restate the code, keeping the section banners and the notes that carry a reason, a measured fact or an external contract. ButtonOptions.width claimed to be a fixed width but only set minWidth, so the Graph and Texture pickers grew with the name they showed. It is now what it promises, with a separate minWidth for the buttons that have two forms. Narrow buttons shrink their padding, otherwise a 24px icon button had 8px left for its glyph and truncate dropped it entirely. __gm.labelsDropped() guards that class: the overflow guard only saw text that was too wide, never a label truncated to nothing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f16801aef3
commit
4d84231b9f
115 files changed
+707
-1564
No files matched your search
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* The two pure halves of the `asset` property kind: how a stored id reads, and which assets a
|
||||
* picker may offer for it. Both are used by the inspector row and by the graph node view, so
|
||||
* they are pinned here rather than through a widget.
|
||||
* picker may offer for it. Used by the inspector row and the graph node view alike.
|
||||
*/
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { CreateAssetCommand } from '../../src/core/commands/assetCommands';
|
||||
@@ -11,7 +10,6 @@ import type { Project } from '../../src/core/model/Project';
|
||||
import { assetChoiceLabel, assetRefChoices, assetRefLabel } from '../../src/core/properties/assetRef';
|
||||
import { makeProject, type ProjectFixture } from '../helpers';
|
||||
|
||||
/** Adds an asset and returns its id, so a test can reference it. */
|
||||
function add(fixture: ProjectFixture, type: AssetType, name: string): string {
|
||||
const command = new CreateAssetCommand(type, name);
|
||||
fixture.stack.execute(command);
|
||||
@@ -123,8 +121,8 @@ describe('assetRefChoices', () => {
|
||||
});
|
||||
|
||||
describe('node asset params', () => {
|
||||
// There used to be a second notion of an asset reference: an enum with empty options that the
|
||||
// graph inspector filled in. This keeps the nodes on the real kind.
|
||||
// Guards against the old second notion of an asset reference: an enum with empty options
|
||||
// that the graph inspector filled in.
|
||||
it('use the asset kind and offer every placeable asset', () => {
|
||||
const params = BUILT_IN_NODES.flatMap((def) => def.params).filter((p) => p.key === 'asset');
|
||||
expect(params.length).toBeGreaterThan(0);
|
||||
|
||||
@@ -25,14 +25,12 @@ function makeSheet(width = 64, height = 64) {
|
||||
return { ...fixture, textureId: create.asset.id, asset, frames: () => asset().frames };
|
||||
}
|
||||
|
||||
/** Adds a frame through the command stack and returns its id. */
|
||||
function addFrame(sheet: ReturnType<typeof makeSheet>, rect: FrameRect, name?: string): string {
|
||||
const command = new AddFrameCommand(sheet.textureId, rect, name);
|
||||
sheet.stack.execute(command);
|
||||
return command.frameId;
|
||||
}
|
||||
|
||||
/** A detached copy of the frame list, to compare a state against after an undo. */
|
||||
function snapshot(frames: readonly TextureFrame[]): TextureFrame[] {
|
||||
return frames.map((f) => ({ ...f }));
|
||||
}
|
||||
@@ -113,8 +111,8 @@ describe('SetFrameRectCommand', () => {
|
||||
const id = addFrame(sheet, { x: 0, y: 0, w: 16, h: 16 });
|
||||
const frame = sheet.frames()[0]!;
|
||||
|
||||
// What a live preview does: write into the frame, then hand the command the previewed
|
||||
// rectangle and put the starting one back before executing (see `SceneViewport`).
|
||||
// What a live preview does: hand the command the previewed rectangle, with the starting
|
||||
// one put back before executing (see `SceneViewport`).
|
||||
frame.x = 40;
|
||||
const previewed = { x: frame.x, y: frame.y, w: frame.w, h: frame.h };
|
||||
frame.x = 0;
|
||||
@@ -251,8 +249,7 @@ describe('SliceFramesCommand', () => {
|
||||
});
|
||||
|
||||
it('rejects a slice of an image whose size is unknown rather than doing nothing', () => {
|
||||
// Width 0 is a texture whose upload has not been measured yet; slicing it would silently
|
||||
// produce no frames at all.
|
||||
// Width 0 is an unmeasured upload; slicing it would silently produce no frames at all.
|
||||
const sheet = makeSheet(0, 0);
|
||||
expect(() => sheet.stack.execute(new SliceFramesCommand(sheet.textureId, GRID_2X2, false))).toThrow(
|
||||
CommandError,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* Container assets hold placed objects just like scenes do. Anything that walks "all placed
|
||||
* objects" has to cover both – the tests here pin the places that used to look at scenes only.
|
||||
* The history tests pin that a rejected undo leaves the stacks usable.
|
||||
* Container assets hold placed objects just like scenes do, so anything that walks "all placed
|
||||
* objects" has to cover both. Plus: a rejected undo leaves the stacks usable.
|
||||
*/
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { type Command, CommandError } from '../../src/core/commands/Command';
|
||||
@@ -71,7 +70,6 @@ describe('RenameVariableCommand', () => {
|
||||
});
|
||||
});
|
||||
|
||||
/** Applies a marker to the project; its undo refuses to run. */
|
||||
class RefusingUndo implements Command {
|
||||
readonly label = 'Refusing';
|
||||
execute(project: { name: string }): void {
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/**
|
||||
* One table covering every built-in node that has a `run`, plus a guard that keeps it that way:
|
||||
* adding a node without a case here fails `covers every built-in node`. Nodes without `run`
|
||||
* (the events) are seeded by the interpreter, so they are listed with the test that drives them
|
||||
* and checked in tests/core/behavior-events.test.ts.
|
||||
* One table covering every built-in node that has a `run`: adding a node without a case here
|
||||
* fails `covers every built-in node`. The run-less event nodes are listed in `EVENT_NODES`.
|
||||
*/
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { BUILT_IN_NODES } from '../../src/core/graph/nodes';
|
||||
@@ -29,7 +27,6 @@ const run = (type: string, c: Case): { result: RunResult; ctx: FakeContext } =>
|
||||
return { result: requireNodeDef(type).run!(ctx, c.inputs ?? {}, c.params ?? {}), ctx };
|
||||
};
|
||||
|
||||
/** A handle with a fixed position, for the geometry nodes. */
|
||||
const at = (name: string, x: number, y: number) => ({ ...fakeEntity(name), x, y });
|
||||
|
||||
const pointer = (overrides: Partial<NodeContext['pointer']>): Partial<NodeContext> => ({
|
||||
@@ -38,6 +35,7 @@ const pointer = (overrides: Partial<NodeContext['pointer']>): Partial<NodeContex
|
||||
|
||||
const CASES: Record<string, Case[]> = {
|
||||
// --- flow ------------------------------------------------------------------------------------
|
||||
|
||||
Branch: [
|
||||
{ name: 'true takes then', inputs: { condition: true }, next: 'then' },
|
||||
{ name: 'false takes else', inputs: { condition: false }, next: 'else' },
|
||||
@@ -47,6 +45,7 @@ const CASES: Record<string, Case[]> = {
|
||||
Sequence: [{ name: 'runs all three outputs in order', next: ['a', 'b', 'c'] }],
|
||||
|
||||
// --- variables -------------------------------------------------------------------------------
|
||||
|
||||
GetVariable: [
|
||||
{ name: 'reads a variable', params: { variable: 'speed' }, outputs: { value: 100 } },
|
||||
{ name: 'an unknown variable reads as null', params: { variable: 'nope' }, outputs: { value: null } },
|
||||
@@ -69,6 +68,7 @@ const CASES: Record<string, Case[]> = {
|
||||
],
|
||||
|
||||
// --- references and properties ----------------------------------------------------------------
|
||||
|
||||
Self: [{ name: 'outputs the behavior object', outputs: { object: fakeContext().self } }],
|
||||
Owner: [
|
||||
{ name: 'outputs the object the behavior is parented to', outputs: { object: fakeContext().owner } },
|
||||
@@ -154,6 +154,7 @@ const CASES: Record<string, Case[]> = {
|
||||
],
|
||||
|
||||
// --- literals and math -------------------------------------------------------------------------
|
||||
|
||||
Number: [
|
||||
{ name: 'outputs its setting', params: { value: 7.5 }, outputs: { value: 7.5 } },
|
||||
{ name: 'unset is 0', outputs: { value: 0 } },
|
||||
@@ -210,8 +211,7 @@ const CASES: Record<string, Case[]> = {
|
||||
{ name: 'modulo zero is 0, not NaN', inputs: { a: 125, b: 0 }, outputs: { result: 0 } },
|
||||
],
|
||||
Random: [
|
||||
// The spread is checked in "Random stays inside [min, max)" below; an empty range is the
|
||||
// one case with a single right answer.
|
||||
// The spread is checked in "Random stays inside [min, max)" below.
|
||||
{ name: 'an empty range always yields min', inputs: { min: 3, max: 3 }, outputs: { result: 3 } },
|
||||
],
|
||||
Time: [
|
||||
@@ -223,6 +223,7 @@ const CASES: Record<string, Case[]> = {
|
||||
],
|
||||
|
||||
// --- text and comparison -----------------------------------------------------------------------
|
||||
|
||||
ToText: [
|
||||
{ name: 'formats with decimals', inputs: { value: 12.345, decimals: 1 }, outputs: { text: '12.3' } },
|
||||
{ name: 'text passes through unformatted', inputs: { value: 'x', decimals: 2 }, outputs: { text: 'x' } },
|
||||
@@ -267,6 +268,7 @@ const CASES: Record<string, Case[]> = {
|
||||
],
|
||||
|
||||
// --- vectors and input --------------------------------------------------------------------------
|
||||
|
||||
Length: [
|
||||
{ name: '3-4-5 triangle', inputs: { x: 3, y: 4 }, outputs: { result: 5 } },
|
||||
{ name: 'the zero vector has length 0', inputs: { x: 0, y: 0 }, outputs: { result: 0 } },
|
||||
@@ -390,6 +392,7 @@ const CASES: Record<string, Case[]> = {
|
||||
],
|
||||
|
||||
// --- actions --------------------------------------------------------------------------------------
|
||||
|
||||
Move: [
|
||||
{
|
||||
name: 'moves by (dx, dy) × scale × dt',
|
||||
@@ -479,8 +482,8 @@ function eqNamesakes(): Record<string, Value> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Nodes without a `run`: the interpreter seeds their outputs when the BehaviorSystem fires them,
|
||||
* so they are only observable through a running world. The value says which test drives it.
|
||||
* Nodes without a `run`: only observable through a running world, since the BehaviorSystem
|
||||
* seeds their outputs. The value names the test that drives each one.
|
||||
*/
|
||||
const EVENT_NODES: Record<string, string> = {
|
||||
OnStart: 'graph.test.ts',
|
||||
@@ -513,8 +516,7 @@ describe('node catalog', () => {
|
||||
const keys = [...def.inputs, ...def.outputs].map((p) => p.key);
|
||||
expect(def.label, `${def.type} has a label`).not.toBe('');
|
||||
expect(def.description, `${def.type} has a description`).not.toBe('');
|
||||
// Inputs and outputs are addressed by key within their own side; a key may repeat across
|
||||
// sides (Normalize reads x/y and writes x/y), never within one.
|
||||
// Keys are unique per side, but may repeat across sides (Normalize reads and writes x/y).
|
||||
expect(new Set(def.inputs.map((p) => p.key)).size, `${def.type} input keys unique`).toBe(
|
||||
def.inputs.length,
|
||||
);
|
||||
@@ -545,7 +547,6 @@ for (const [type, cases] of Object.entries(CASES)) {
|
||||
});
|
||||
}
|
||||
|
||||
// Cases whose point is the mutation they cause – stated here rather than squeezed into the table.
|
||||
describe('action nodes write through to the object they are given', () => {
|
||||
it('Move applies dx/dy × scale × dt', () => {
|
||||
const target = at('m', 0, 0);
|
||||
|
||||
@@ -18,7 +18,6 @@ import { makeSpriteScene, place, roundTrip } from '../helpers';
|
||||
const FILE = `${'a1b2c3d4'.repeat(8)}.png`;
|
||||
const OTHER_FILE = `${'0f'.repeat(32)}.webp`;
|
||||
|
||||
/** Adds a texture asset carrying `file` and returns it. */
|
||||
function addTexture(fixture: ReturnType<typeof makeSpriteScene>, file = FILE, name = 'Bricks') {
|
||||
const command = new CreateTextureCommand(name, { file, width: 64, height: 48 });
|
||||
fixture.stack.execute(command);
|
||||
@@ -51,7 +50,7 @@ describe('resolveTexture', () => {
|
||||
const sprite = findAsset(fixture.project, fixture.spriteId)!;
|
||||
sprite.props.texture = texture.id;
|
||||
|
||||
// A whole-texture reference carries no rectangle: the renderer then needs no matrix at all.
|
||||
// A whole-texture reference carries no rectangle.
|
||||
const whole = { file: FILE, rect: null, sourceWidth: 64, sourceHeight: 48 };
|
||||
expect(resolveTexture(fixture.project, sprite.props)).toEqual({ ...whole, smooth: true });
|
||||
texture.props.filter = 'nearest';
|
||||
@@ -64,8 +63,6 @@ describe('resolveTexture', () => {
|
||||
texture.frames.push({ id: 'f1', name: 'Idle', x: 16, y: 8, w: 32, h: 24 });
|
||||
const sprite = findAsset(fixture.project, fixture.spriteId)!;
|
||||
|
||||
// The same property holds either kind of id, which is what keeps sprites written before
|
||||
// frames existed meaning exactly what they meant.
|
||||
sprite.props.texture = 'f1';
|
||||
expect(resolveTexture(fixture.project, sprite.props)).toEqual({
|
||||
file: FILE,
|
||||
@@ -146,8 +143,7 @@ describe('findPropertyUsages', () => {
|
||||
sprite.props.texture = texture.id;
|
||||
const objectId = place(fixture, fixture.spriteId, { x: 0, y: 0 });
|
||||
|
||||
// A texture is never placed, so the "is it used?" question `findUsages` answers is blind
|
||||
// to it – that is exactly the gap this function fills.
|
||||
// A texture is never placed, so `findUsages` is blind to it – hence this function.
|
||||
expect(findUsages(fixture.project, texture.id)).toHaveLength(0);
|
||||
|
||||
const usages = findPropertyUsages(fixture.project, texture.id);
|
||||
@@ -165,8 +161,7 @@ describe('findPropertyUsages', () => {
|
||||
texture.frames.push({ id: 'f1', name: 'Idle', x: 0, y: 0, w: 8, h: 8 });
|
||||
findAsset(fixture.project, fixture.spriteId)!.props.texture = 'f1';
|
||||
|
||||
// Asking by the asset id alone under-reports exactly the sheets that were sliced – the
|
||||
// ones with the most users – which is why deleting one asks about every id it owns.
|
||||
// The asset id alone under-reports sliced sheets, so deleting one asks about every id it owns.
|
||||
expect(findPropertyUsages(fixture.project, texture.id)).toHaveLength(0);
|
||||
expect(findPropertyUsages(fixture.project, textureRefIds(texture))).toHaveLength(1);
|
||||
});
|
||||
|
||||
@@ -22,7 +22,6 @@ describe('sheet view mapping', () => {
|
||||
const view = { panX: 100, panY: 50, zoom: 2 };
|
||||
expect(imageToLocal(view, 0, 0)).toEqual({ x: 100, y: 50 });
|
||||
expect(imageToLocal(view, 8, 4)).toEqual({ x: 116, y: 58 });
|
||||
// Round trip: the two are inverses, which is what lets a drag be computed in either space.
|
||||
expect(localToImage(view, 116, 58)).toEqual({ x: 8, y: 4 });
|
||||
});
|
||||
|
||||
@@ -32,7 +31,7 @@ describe('sheet view mapping', () => {
|
||||
expect(view.zoom).toBeCloseTo(3.6);
|
||||
expect(view.panX).toBeCloseTo((400 - 100 * 3.6) / 2);
|
||||
expect(view.panY).toBeCloseTo((400 - 50 * 3.6) / 2);
|
||||
// The whole picture is inside the widget, which is the only thing "fit" has to guarantee.
|
||||
// Fitting only has to guarantee that the whole picture is inside the widget.
|
||||
const end = imageToLocal(view, 100, 50);
|
||||
expect(view.panX).toBeGreaterThanOrEqual(0);
|
||||
expect(end.x).toBeLessThanOrEqual(400);
|
||||
@@ -77,8 +76,8 @@ describe('grabbing a frame', () => {
|
||||
});
|
||||
|
||||
it('prefers a corner where handles overlap, so a tiny frame stays resizable', () => {
|
||||
// A 4x4 frame with a 6 px tolerance: every handle matches the centre of the frame, and
|
||||
// grabbing it must resize rather than move, or a small frame could never be adjusted.
|
||||
// A 4x4 frame with a 6 px tolerance: every handle matches its centre, and a grab there
|
||||
// must resize, or the frame could never be adjusted.
|
||||
const tiny: FrameRect = { x: 0, y: 0, w: 4, h: 4 };
|
||||
expect(handleAt(tiny, { x: 2, y: 2 }, 6)).toEqual({ hx: -1, hy: -1 });
|
||||
});
|
||||
@@ -98,7 +97,6 @@ describe('dragging a frame', () => {
|
||||
});
|
||||
|
||||
it('pins the opposite edge when a corner is dragged', () => {
|
||||
// Dragging the top-left corner right and down shrinks the frame; the bottom-right stays.
|
||||
const dragged = dragFrame(RECT, { hx: -1, hy: -1 }, 4, 6);
|
||||
expect(dragged).toEqual({ x: 14, y: 26, w: 36, h: 24 });
|
||||
expect(dragged.x + dragged.w).toBe(RECT.x + RECT.w);
|
||||
@@ -111,8 +109,8 @@ describe('dragging a frame', () => {
|
||||
});
|
||||
|
||||
it('is allowed to invert – squaring that up belongs to one place only', () => {
|
||||
// Pulling the left edge past the right one yields a negative width on purpose:
|
||||
// `normalizeFrameRect` corrects it, so a drag and a typed value are corrected identically.
|
||||
// The negative width is on purpose: `normalizeFrameRect` corrects a drag and a typed
|
||||
// value identically.
|
||||
const dragged = dragFrame(RECT, { hx: -1, hy: 0 }, 60, 0);
|
||||
expect(dragged.w).toBeLessThan(0);
|
||||
});
|
||||
@@ -124,8 +122,7 @@ describe('dragging a frame', () => {
|
||||
});
|
||||
|
||||
it('walks a frame through the eight handles back to where it started', () => {
|
||||
// Each handle dragged by (d) and then by (−d) is the identity; a sign error in any one of
|
||||
// the eight branches shows up here without needing eight separate expectations.
|
||||
// A sign error in any of the eight branches breaks the drag-and-back identity.
|
||||
const handles: FrameHandle[] = [
|
||||
'move',
|
||||
{ hx: -1, hy: -1 },
|
||||
|
||||
@@ -52,8 +52,7 @@ describe('formatNumber', () => {
|
||||
});
|
||||
|
||||
it('shows a field of integral values without a decimal point at all', () => {
|
||||
// What `NumberFieldOptions.decimals: 0` buys: a pixel index or a count of tiles reads
|
||||
// "33" and "4" instead of "33.000" and "4.000".
|
||||
// What `NumberFieldOptions.decimals: 0` buys: a pixel index reads "33", not "33.000".
|
||||
expect(formatNumber(33, 0)).toBe('33');
|
||||
expect(formatNumber(-4, 0)).toBe('-4');
|
||||
// The minus-zero rule holds at every precision, not just the default one.
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
/**
|
||||
* The fill matrix is what makes a sprite wear one frame of a sheet, and it is only ever seen
|
||||
* as pixels on a canvas – so it is pinned here against the identity its doc comment states,
|
||||
* `uv = inverse(matrix) ∘ normalise(shapeBounds)`, rather than against the formula it uses.
|
||||
* The checks therefore invert the matrix themselves and ask where the corners of the shape
|
||||
* land in the image; that is an independent statement of what the renderer must achieve.
|
||||
* The fill matrix that makes a sprite wear one frame of a sheet. Pinned against the identity
|
||||
* `uv = inverse(matrix) ∘ normalise(shapeBounds)` rather than against the formula it uses, so
|
||||
* the checks invert the matrix themselves and ask where the shape's corners land in the image.
|
||||
*/
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import type { FrameRect } from '../../src/core/model/texture';
|
||||
import { frameFillMatrix, type MatrixValues } from '../../src/viewport/textureFill';
|
||||
|
||||
/**
|
||||
* Where the shape point `(u, v)` – normalised, so (0,0) is the shape's top-left corner and
|
||||
* (1,1) its bottom-right – samples the image, in UV coordinates over the whole picture.
|
||||
* This is Pixi's `inverse(style.matrix)` applied to the normalised point, written out for a
|
||||
* general affine matrix so the test does not assume the axis-aligned shape of the real one.
|
||||
* Where the normalised shape point `(u, v)` samples the image: Pixi's `inverse(style.matrix)`,
|
||||
* written out for a general affine matrix so the test does not assume an axis-aligned one.
|
||||
*/
|
||||
function sampleAt(m: MatrixValues, u: number, v: number): { u: number; v: number } {
|
||||
const det = m.a * m.d - m.b * m.c;
|
||||
@@ -41,8 +37,8 @@ function expectCovers(m: MatrixValues, rect: FrameRect, sourceWidth: number, sou
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the six numbers one by one instead of the object as a whole: a frame sitting on the
|
||||
* top or left edge produces a negative zero, which `toEqual` counts as a different value.
|
||||
* Number by number rather than `toEqual`: a frame on the top or left edge produces a negative
|
||||
* zero, which `toEqual` counts as a different value.
|
||||
*/
|
||||
function expectMatrix(m: MatrixValues, expected: MatrixValues): void {
|
||||
for (const key of ['a', 'b', 'c', 'd', 'tx', 'ty'] as const) expect(m[key]).toBeCloseTo(expected[key], 12);
|
||||
@@ -66,14 +62,12 @@ describe('frameFillMatrix', () => {
|
||||
const rect = { x: 32, y: 0, w: 32, h: 32 };
|
||||
const m = frameFillMatrix(rect, 64, 64)!;
|
||||
|
||||
// Half the sheet across, so the shape has to be stretched twofold in both directions, and
|
||||
// shifted by one shape-width to start at the sheet's midpoint.
|
||||
// Half the sheet across: stretched twofold, shifted by one shape-width to the midpoint.
|
||||
expectMatrix(m, { a: 2, b: 0, c: 0, d: 2, tx: -1, ty: 0 });
|
||||
expectCovers(m, rect, 64, 64);
|
||||
});
|
||||
|
||||
it('stretches the axes independently for a non-square frame', () => {
|
||||
// A column strip: an eighth of the sheet wide and its full height.
|
||||
const rect = { x: 0, y: 0, w: 16, h: 64 };
|
||||
const m = frameFillMatrix(rect, 128, 64)!;
|
||||
|
||||
@@ -82,9 +76,7 @@ describe('frameFillMatrix', () => {
|
||||
});
|
||||
|
||||
it('offsets in frame-widths, not in pixels or UV', () => {
|
||||
// A small frame well inside a large sheet: three frame-widths from the left, two frame
|
||||
// heights down. This is the case that catches an offset expressed in the wrong unit,
|
||||
// because pixels, UV and frame-widths all differ here.
|
||||
// Pixels, UV and frame-widths all differ here, so an offset in the wrong unit is caught.
|
||||
const rect = { x: 48, y: 16, w: 16, h: 8 };
|
||||
const m = frameFillMatrix(rect, 256, 128)!;
|
||||
|
||||
@@ -93,8 +85,6 @@ describe('frameFillMatrix', () => {
|
||||
});
|
||||
|
||||
it('is the identity for a frame covering the whole sheet', () => {
|
||||
// Which is the reason a whole-image sprite is drawn with no matrix at all: the matrix it
|
||||
// would get says nothing, and an absent one is what Pixi is fastest at.
|
||||
const rect = { x: 0, y: 0, w: 200, h: 100 };
|
||||
const m = frameFillMatrix(rect, 200, 100)!;
|
||||
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
/**
|
||||
* The viewport transforms used to be private methods of a Pixi widget and could only be
|
||||
* checked through the browser. They are plain geometry, so they are pinned here.
|
||||
*/
|
||||
/** The viewport transforms: plain geometry, so pinned here rather than through the browser. */
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import {
|
||||
cameraView,
|
||||
|
||||
Reference in new issue
Block a user