Create a sprite asset from a texture's context menu
The sprite takes the whole image at its pixel size and the texture's name, numbered like any other clash. CreateAssetCommand now accepts starting properties; they go through the schema in execute, so an unknown key or a bad value is refused before the project is touched, and one undo removes the asset. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1e2285c545
commit
9212e61c4c
9 files changed
+137
-7
No files matched your search
@@ -6,6 +6,7 @@ import {
|
||||
fitAxisToAspect,
|
||||
matchesAspect,
|
||||
matchesPixelSize,
|
||||
spriteFromTexture,
|
||||
texturePixelSize,
|
||||
} from '../../src/core/properties/aspect';
|
||||
import { makeSpriteScene } from '../helpers';
|
||||
@@ -97,3 +98,19 @@ describe('matchesAspect', () => {
|
||||
expect(matchesAspect(size, props({ width: Number.NaN, height: 10 }))).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('spriteFromTexture', () => {
|
||||
it('wears the texture at its pixel size', () => {
|
||||
const sheet = makeSheet();
|
||||
expect(spriteFromTexture(sheet.project, sheet.textureId)).toEqual({
|
||||
texture: sheet.textureId,
|
||||
width: 64,
|
||||
height: 48,
|
||||
});
|
||||
});
|
||||
|
||||
it('leaves the size to the defaults while the image has not been measured', () => {
|
||||
const sheet = makeSheet(0, 0);
|
||||
expect(spriteFromTexture(sheet.project, sheet.textureId)).toEqual({ texture: sheet.textureId });
|
||||
});
|
||||
});
|
||||
@@ -1,8 +1,9 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { CreateTextureCommand } from '../../src/core/commands/assetCommands';
|
||||
import { CreateAssetCommand, CreateTextureCommand } from '../../src/core/commands/assetCommands';
|
||||
import { CommandError } from '../../src/core/commands/Command';
|
||||
import { isTextureAsset } from '../../src/core/model/Asset';
|
||||
import { findAsset } from '../../src/core/model/Project';
|
||||
import { spriteFromTexture } from '../../src/core/properties/aspect';
|
||||
import { makeProject } from '../helpers';
|
||||
|
||||
const FILE = `${'b'.repeat(64)}.webp`;
|
||||
@@ -40,3 +41,38 @@ describe('CreateTextureCommand', () => {
|
||||
expect(new Set(project.assets.map((a) => a.id)).size).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('CreateAssetCommand with starting props', () => {
|
||||
it('creates a sprite wearing the texture at its pixel size, and removes it again', () => {
|
||||
const { project, stack } = makeProject();
|
||||
const texture = new CreateTextureCommand('Hero', { file: FILE, width: 64, height: 32 });
|
||||
stack.execute(texture);
|
||||
const sprite = new CreateAssetCommand('sprite', 'Hero 2', spriteFromTexture(project, texture.asset.id));
|
||||
stack.execute(sprite);
|
||||
|
||||
expect(findAsset(project, sprite.asset.id)?.props).toEqual({
|
||||
enabled: true,
|
||||
width: 64,
|
||||
height: 32,
|
||||
color: 0xffffff,
|
||||
texture: texture.asset.id,
|
||||
});
|
||||
stack.undo();
|
||||
expect(findAsset(project, sprite.asset.id)).toBeUndefined();
|
||||
stack.redo();
|
||||
expect(findAsset(project, sprite.asset.id)?.props.texture).toBe(texture.asset.id);
|
||||
});
|
||||
|
||||
it('passes each value through the schema', () => {
|
||||
const { project, stack } = makeProject();
|
||||
const sprite = new CreateAssetCommand('sprite', 'Tiny', { width: -5 });
|
||||
stack.execute(sprite);
|
||||
expect(findAsset(project, sprite.asset.id)?.props.width).toBe(1);
|
||||
});
|
||||
|
||||
it('rejects a property the type does not have, leaving the project untouched', () => {
|
||||
const { project, stack } = makeProject();
|
||||
expect(() => stack.execute(new CreateAssetCommand('sprite', 'Odd', { zoom: 2 }))).toThrow(CommandError);
|
||||
expect(project.assets).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user