Skip to main content

Costume Management Components

The costume management system in RemixWarp 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 RemixWarp'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:

  1. From Library: Choose from built-in costume collection
  2. Upload: Load image files from computer
  3. Paint: Create new costume in paint editor
  4. 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​

RemixWarp 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

RemixWarp Enhancements​

Default Costumes​

RemixWarp 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();
});
});