A frame that keeps its corners can be stretched to any size (#41)
game-maker / suite (push) Successful in 6m21s
game-maker / suite (push) Successful in 6m21s
TextureFrame carries optional `border` (left/right/top/bottom) and `fill` (stretch | repeat); absent keys mean "not sliced", so no format bump and undo restores the plain frame instead of four zeroes. The sliced sprite builds its own geometry instead of the shared UNIT_QUAD: a 4x4 grid, and for `repeat` one quad per tile carrying the frame cell's real UVs -- tiling in the geometry, not in the sampler, so a frame out of a sheet cannot pull its neighbour in. Above 64 tiles per axis it stretches, to bound the buffer. A sprite narrower than left+right scales both borders down together until the middle is exactly 0, so the corners meet at a seam and never overlap. The texture editor gets four draggable border lines plus the same four numbers in the inspector. Hit order is resize handles, then the lines, then the frame body -- handleAt reports 'move' anywhere inside a frame, so lines placed after it were unreachable. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b9f1a9d319
commit
be8f2331de
17 files changed
+1091
-31
No files matched your search
@@ -1,6 +1,9 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import type { FrameRect } from '../../src/core/model/texture';
|
||||
import {
|
||||
borderAt,
|
||||
borderLine,
|
||||
dragBorder,
|
||||
dragFrame,
|
||||
fitView,
|
||||
type FrameHandle,
|
||||
@@ -138,3 +141,33 @@ describe('dragging a frame', () => {
|
||||
expect(dragFrame(dragFrame(RECT, handle, 3, 4), handle, -3, -4)).toEqual(RECT);
|
||||
});
|
||||
});
|
||||
|
||||
describe('nine-slice border lines', () => {
|
||||
const BORDER = { left: 4, top: 6, right: 8, bottom: 10 };
|
||||
|
||||
it('runs each line beside its own edge, the far ones measured from the far side', () => {
|
||||
expect(borderLine(RECT, BORDER, 'left')).toEqual({ x1: 14, y1: 20, x2: 14, y2: 50 });
|
||||
expect(borderLine(RECT, BORDER, 'right')).toEqual({ x1: 42, y1: 20, x2: 42, y2: 50 });
|
||||
expect(borderLine(RECT, BORDER, 'top')).toEqual({ x1: 10, y1: 26, x2: 50, y2: 26 });
|
||||
expect(borderLine(RECT, BORDER, 'bottom')).toEqual({ x1: 10, y1: 40, x2: 50, y2: 40 });
|
||||
});
|
||||
|
||||
it('grabs a line only near it and only within the frame', () => {
|
||||
expect(borderAt(RECT, BORDER, { x: 14, y: 35 }, 2)).toBe('left');
|
||||
expect(borderAt(RECT, BORDER, { x: 30, y: 40 }, 2)).toBe('bottom');
|
||||
expect(borderAt(RECT, BORDER, { x: 30, y: 35 }, 2)).toBeNull();
|
||||
// Far outside the frame the lines are not offered, however close the axis would be.
|
||||
expect(borderAt(RECT, BORDER, { x: 14, y: 200 }, 2)).toBeNull();
|
||||
});
|
||||
|
||||
it('moves the near border with the pointer and the far one against it', () => {
|
||||
// Both grow when the pointer goes towards the middle, which is what the eye expects of a line
|
||||
// that is dragged inwards.
|
||||
expect(dragBorder(BORDER, 'left', 3, 0).left).toBe(7);
|
||||
expect(dragBorder(BORDER, 'right', -3, 0).right).toBe(11);
|
||||
expect(dragBorder(BORDER, 'top', 0, 3).top).toBe(9);
|
||||
expect(dragBorder(BORDER, 'bottom', 0, -3).bottom).toBe(13);
|
||||
// And each line moves only its own border.
|
||||
expect(dragBorder(BORDER, 'left', 3, 3)).toEqual({ ...BORDER, left: 7 });
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user