Costume Management Components
The costume management system in MistWarp consists of containers and components that handle visual assets for sprites and the stage.
Overview
The costume management system allows users to:
- View and select costumes for the current sprite/stage
- Add new costumes from library or files
- Edit costumes using the built-in paint editor
- Manage costume properties and ordering
Container Architecture
CostumeTab (Container)
└── AssetPanel (Component)
├── Selector (for costume list)
│ └── SortableAsset (for each costume)
├── ActionMenu (add/edit/upload)
└── PaintEditorWrapper (when editing)
│ ├── AddCostume │ ├── UploadCostume │ └── PaintCostume └── CostumeEditor (when editing)
## Key Features
### Costume Management
- Display costume thumbnails and names
- Reorder costumes via drag and drop
- Delete costumes with confirmation
- Duplicate existing costumes
- Set costume center points
### Paint Editor Integration
The Costume Tab integrates with MistWarp's paint editor:
```javascript
openPaintEditor = (costumeId) => {
this.props.onEditCostume(costumeId);
// Opens integrated paint editor
};
File Format Support
Supports multiple image formats:
- SVG: Vector graphics (recommended)
- PNG: Raster with transparency
- JPG: Raster without transparency
- GIF: Animated (first frame used)
Props Interface
interface CostumeTabProps {
costumes: Array<CostumeData>;
selectedCostumeId: string;
onSelectCostume: (costumeId: string) => void;
onNewCostume: () => void;
onDeleteCostume: (costumeId: string) => void;
onEditCostume: (costumeId: string) => void;
vm: VirtualMachine;
}
State Management
Connects to Redux for costume state:
const mapStateToProps = state => ({
costumes: state.targets.editingTarget?.costumes || [],
selectedCostumeId: state.targets.editingTarget?.currentCostume,
editingTarget: state.targets.editingTarget
});
const mapDispatchToProps = dispatch => ({
onSelectCostume: id => dispatch(setActiveCostume(id)),
onDeleteCostume: id => dispatch(deleteCostume(id)),
// ... other actions
});
Costume Operations
Adding Costumes
Multiple methods to add costumes:
- From Library: Choose from built-in costume collection
- Upload: Load image files from computer
- Paint: Create new costume in paint editor
- Camera: Capture from webcam (if available)
Costume Properties
Each costume has configurable properties:
- Name: Human-readable identifier
- Center Point: Rotation/scaling origin
- Resolution: Original image dimensions
- Data URI: Base64 encoded image data
Paint Editor Integration
MistWarp includes a sophisticated paint editor:
Vector Tools
- Pen tool for freehand drawing
- Shape tools (rectangle, circle, polygon)
- Text tool with font selection
- Gradient and pattern fills
Bitmap Tools
- Brush with adjustable size and opacity
- Eraser tool
- Fill bucket
- Select and transform tools
Advanced Features
- Layer support
- Undo/redo stack
- Zoom and pan
- Grid and guides
Performance Optimizations
Thumbnail Generation
Costumes are automatically thumbnailed for performance:
generateThumbnail = (costume) => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = 80;
canvas.height = 60;
// Render costume at thumbnail size
this.renderCostumeToCanvas(costume, canvas, ctx);
return canvas.toDataURL();
};
Lazy Loading
- Costumes loaded on-demand
- Thumbnail caching
- Progressive image loading
MistWarp Enhancements
Default Costumes
MistWarp ships with unique default costumes:
- "Misty" sprite with multiple poses
- Enhanced costume library
- Custom vector graphics
Advanced Import
- Batch costume import
- Animated GIF support
- SVG optimization on import
Accessibility
- Keyboard navigation through costume list
- Screen reader descriptions for costumes
- High contrast mode support
- Focus management in paint editor
Testing
describe('CostumeTab', () => {
it('should display costumes for current sprite', () => {
const costumes = [mockCostume1, mockCostume2];
const wrapper = mount(
<CostumeTab costumes={costumes} selectedCostumeId="costume1" />
);
expect(wrapper.find('CostumeListItem')).toHaveLength(2);
});
it('should open paint editor when editing costume', () => {
const onEditCostume = jest.fn();
const wrapper = mount(
<CostumeTab onEditCostume={onEditCostume} />
);
wrapper.find('.edit-button').first().simulate('click');
expect(onEditCostume).toHaveBeenCalled();
});
});