Initial commit
This commit is contained in:
124
skills/README.md
Normal file
124
skills/README.md
Normal file
@@ -0,0 +1,124 @@
|
||||
# Skills
|
||||
|
||||
This directory contains Agent Skills that Claude automatically uses based on context. Skills are model-invoked - you don't call them explicitly like slash commands.
|
||||
|
||||
## Available Skills
|
||||
|
||||
### pixel-art-creator
|
||||
Creates new pixel art sprites with canvas setup, layers, and basic drawing primitives.
|
||||
|
||||
**Triggers when user mentions:**
|
||||
- "create a sprite", "new canvas", "make pixel art"
|
||||
- Dimensions like "64x64", "32x32 sprite"
|
||||
- Basic shapes: "circle", "rectangle", "line"
|
||||
- Color modes: "RGB", "indexed", "grayscale"
|
||||
- Retro systems: "Game Boy", "NES"
|
||||
|
||||
**Capabilities:**
|
||||
- Canvas creation (1-65535 pixels, RGB/Grayscale/Indexed modes)
|
||||
- Layer management (add, delete, organize)
|
||||
- Drawing primitives (pixels, lines, rectangles, circles, polygons, flood fill)
|
||||
- Color palette setup
|
||||
- Batch pixel operations
|
||||
|
||||
**MCP Tools:** `create_canvas`, `add_layer`, `delete_layer`, `draw_pixels`, `draw_line`, `draw_rectangle`, `draw_circle`, `draw_contour`, `fill_area`, `set_palette`, `get_palette`, `get_sprite_info`
|
||||
|
||||
### pixel-art-animator
|
||||
Manages sprite animations with frames, tags, timing, and cel operations.
|
||||
|
||||
**Triggers when user mentions:**
|
||||
- "animate", "animation", "frames", "keyframes"
|
||||
- "walk cycle", "run cycle", "idle animation"
|
||||
- "frame rate", "FPS", "timing", "duration"
|
||||
- "loop", "ping-pong", "forward"
|
||||
|
||||
**Capabilities:**
|
||||
- Frame management (add, delete, duplicate, reorder)
|
||||
- Animation tags for organizing sequences
|
||||
- Frame timing control (per-frame or global)
|
||||
- Linked cels for shared content across frames
|
||||
- Preview and playback control
|
||||
|
||||
**MCP Tools:** `add_frame`, `delete_frame`, `duplicate_frame`, `get_frame_info`, `set_frame_duration`, `create_animation_tag`, `list_animation_tags`, `delete_animation_tag`, `create_linked_cel`
|
||||
|
||||
### pixel-art-professional
|
||||
Applies advanced pixel art techniques like dithering, palette optimization, shading, and antialiasing.
|
||||
|
||||
**Triggers when user mentions:**
|
||||
- "dithering", "dither", "Floyd-Steinberg", "Bayer"
|
||||
- "palette", "colors", "reduce colors", "optimize palette"
|
||||
- "shading", "shadows", "highlights", "gradient"
|
||||
- "antialiasing", "smooth edges", "AA"
|
||||
- "color theory", "hue shift", "saturation"
|
||||
|
||||
**Capabilities:**
|
||||
- Dithering algorithms (Floyd-Steinberg, Atkinson, Bayer 2x2/4x4/8x8)
|
||||
- Palette quantization and optimization
|
||||
- Color reduction with algorithm selection
|
||||
- Shading techniques (light direction, gradient application)
|
||||
- Edge smoothing and antialiasing
|
||||
- Layer flattening
|
||||
|
||||
**MCP Tools:** `apply_dithering`, `quantize_colors`, `get_palette`, `set_palette`, `draw_pixels`, `add_layer`, `flatten_layers`, `get_sprite_info`
|
||||
|
||||
### pixel-art-exporter
|
||||
Exports sprites to PNG, GIF, spritesheets, and JSON metadata for game engines.
|
||||
|
||||
**Triggers when user mentions:**
|
||||
- "export", "save", "output"
|
||||
- File formats: "PNG", "GIF", "spritesheet"
|
||||
- "Unity", "Godot", "Phaser", "game engine"
|
||||
- "scale", "upscale", "2x", "4x"
|
||||
- "metadata", "JSON"
|
||||
|
||||
**Capabilities:**
|
||||
- PNG export (single frame or current frame)
|
||||
- Animated GIF export (with FPS and loop control)
|
||||
- Spritesheet generation (horizontal, vertical, grid, packed layouts)
|
||||
- JSON metadata (Aseprite, TexturePacker, Unity, Godot formats)
|
||||
- Pixel-perfect scaling (1x, 2x, 4x, 8x)
|
||||
- Frame range selection
|
||||
|
||||
**MCP Tools:** `export_sprite`, `get_sprite_info`, `get_frame_info`, `list_animation_tags`
|
||||
|
||||
## Skill Structure
|
||||
|
||||
Each Skill is a directory containing:
|
||||
- `SKILL.md` - Main instructions with YAML frontmatter (required)
|
||||
- `reference.md` - Technical specifications (optional)
|
||||
- `examples.md` - Concrete examples (optional)
|
||||
|
||||
Claude loads additional files only when needed (progressive disclosure).
|
||||
|
||||
## YAML Frontmatter
|
||||
|
||||
```yaml
|
||||
---
|
||||
name: Skill Display Name
|
||||
description: What the Skill does and when Claude should use it. Include trigger keywords.
|
||||
allowed-tools: Read, Bash, mcp__aseprite__*
|
||||
---
|
||||
```
|
||||
|
||||
The `description` field determines when Claude automatically loads the Skill. Include relevant keywords and phrases users might say.
|
||||
|
||||
## Skill Invocation
|
||||
|
||||
Skills are **model-invoked**, not user-invoked:
|
||||
- ✅ Claude decides when to use them based on context
|
||||
- ❌ Users cannot directly call Skills like slash commands
|
||||
- Skills activate automatically when user requests match their description
|
||||
|
||||
## Integration
|
||||
|
||||
Skills work together:
|
||||
- **pixel-art-creator** handles initial sprite creation
|
||||
- **pixel-art-animator** adds animation when user mentions frames
|
||||
- **pixel-art-professional** applies advanced techniques like dithering
|
||||
- **pixel-art-exporter** saves final output to files
|
||||
|
||||
Claude transitions between Skills automatically based on user needs.
|
||||
|
||||
## MCP Server
|
||||
|
||||
All Skills use the bundled pixel-mcp server to communicate with Aseprite. The server provides 40+ tools for pixel art operations. See [pixel-mcp](https://github.com/willibrandon/pixel-mcp) for tool documentation.
|
||||
315
skills/pixel-art-animator/SKILL.md
Normal file
315
skills/pixel-art-animator/SKILL.md
Normal file
@@ -0,0 +1,315 @@
|
||||
---
|
||||
name: Pixel Art Animator
|
||||
description: Create and manage sprite animations with multiple frames, animation tags, frame durations, and linked cels. Use when the user wants to animate a sprite, add animation, create movement, make it move, mentions "animation", "animated", "frames", "keyframes", "frame rate", "FPS", "timing", "duration", "walk cycle", "run cycle", "idle animation", "attack animation", "jump", "movement", "motion", or describes actions like "walking", "running", "jumping", "attacking", "breathing", "bobbing", "bouncing". Trigger on animation tags, loops, playback, sequences, "add frames", "duplicate frame", "frame timing", "ping-pong", "loop", "sequence". Also for linked cels, static backgrounds, and frame optimization.
|
||||
allowed-tools: Read, Bash, mcp__aseprite__add_frame, mcp__aseprite__delete_frame, mcp__aseprite__duplicate_frame, mcp__aseprite__set_frame_duration, mcp__aseprite__create_tag, mcp__aseprite__delete_tag, mcp__aseprite__link_cel, mcp__aseprite__get_sprite_info, mcp__aseprite__draw_pixels, mcp__aseprite__draw_line, mcp__aseprite__draw_rectangle, mcp__aseprite__draw_circle
|
||||
---
|
||||
|
||||
# Pixel Art Animator
|
||||
|
||||
## Overview
|
||||
|
||||
This Skill handles all animation-related tasks for sprites, including frame management, timing, animation tags (sequences), and linked cels for efficient animation.
|
||||
|
||||
## When to Use
|
||||
|
||||
Use this Skill when the user:
|
||||
- Wants to "animate" a sprite or "add animation"
|
||||
- Mentions "frames", "keyframes", or "frame rate"
|
||||
- Describes motion: "walk cycle", "run cycle", "idle animation", "attack animation"
|
||||
- Asks about "animation tags", "loops", or "playback"
|
||||
- Wants to create "sprite sheets" for animation (coordinate with exporter Skill)
|
||||
|
||||
**Trigger Keywords:** animate, animation, frames, walk cycle, run, idle, attack, loop, movement, motion
|
||||
|
||||
## Instructions
|
||||
|
||||
### 1. Understanding Animation Basics
|
||||
|
||||
**Frame**: A single image in an animation sequence. Sprites start with 1 frame.
|
||||
|
||||
**Frame Duration**: How long each frame displays (in milliseconds). Default: 100ms (10 FPS).
|
||||
|
||||
**Animation Tag**: Named sequence of frames (e.g., "walk" frames 1-4, "idle" frames 5-8).
|
||||
|
||||
**Linked Cel**: A cel that shares image data with another cel. Editing one updates all linked cels.
|
||||
|
||||
**Playback Direction**:
|
||||
- **Forward**: Frames play 1 → 2 → 3 → 4, then loop
|
||||
- **Reverse**: Frames play 4 → 3 → 2 → 1, then loop
|
||||
- **Ping-pong**: Frames play 1 → 2 → 3 → 4 → 3 → 2 → 1, then loop
|
||||
|
||||
### 2. Creating Animation Frames
|
||||
|
||||
**Adding Frames:**
|
||||
Use `mcp__aseprite__add_frame` to create new frames:
|
||||
- Frames are numbered starting from 1
|
||||
- New frames start as copies of the current frame (or blank)
|
||||
|
||||
**Common Frame Counts:**
|
||||
- **Idle Animation**: 2-4 frames (subtle movement)
|
||||
- **Walk Cycle**: 4-8 frames (legs alternate)
|
||||
- **Run Cycle**: 6-8 frames (faster, exaggerated)
|
||||
- **Attack Animation**: 3-6 frames (windup, strike, recovery)
|
||||
- **Jump**: 4-6 frames (crouch, ascend, peak, descend, land)
|
||||
|
||||
**Duplicating Frames:**
|
||||
Use `mcp__aseprite__duplicate_frame` to copy existing frames:
|
||||
- Useful for creating variations
|
||||
- Starting point for similar frames
|
||||
|
||||
**Deleting Frames:**
|
||||
Use `mcp__aseprite__delete_frame` to remove frames:
|
||||
- Cannot delete the last remaining frame
|
||||
- Frames are renumbered after deletion
|
||||
|
||||
### 3. Setting Frame Timing
|
||||
|
||||
**Frame Duration:**
|
||||
Use `mcp__aseprite__set_frame_duration`:
|
||||
- Duration in milliseconds (ms)
|
||||
- 100ms = 10 FPS
|
||||
- 50ms = 20 FPS
|
||||
- 33ms ≈ 30 FPS
|
||||
- 16ms ≈ 60 FPS
|
||||
|
||||
**Common Timing Patterns:**
|
||||
|
||||
**Even Timing:**
|
||||
All frames same duration. Simple and predictable.
|
||||
- Walk cycle: all frames 100ms (smooth 10 FPS)
|
||||
|
||||
**Variable Timing:**
|
||||
Different durations for emphasis.
|
||||
- Idle: slow frames (150ms) for breathing effect
|
||||
- Attack: fast strike (30ms), slower recovery (100ms)
|
||||
|
||||
**Hold Frames:**
|
||||
Longer duration for dramatic effect.
|
||||
- Jump peak: 200ms (hang time)
|
||||
- Impact: 50ms (quick flash)
|
||||
|
||||
### 4. Creating Animation Tags
|
||||
|
||||
**Purpose:** Organize frames into named sequences.
|
||||
|
||||
Use `mcp__aseprite__create_tag`:
|
||||
- Name: "walk", "idle", "attack", etc.
|
||||
- From Frame: starting frame (1-indexed)
|
||||
- To Frame: ending frame (inclusive)
|
||||
- Direction: "forward", "reverse", or "ping-pong"
|
||||
|
||||
**Example Tags:**
|
||||
- Tag "idle": frames 1-2, ping-pong direction
|
||||
- Tag "walk": frames 3-6, forward direction
|
||||
- Tag "attack": frames 7-10, forward direction
|
||||
|
||||
**Benefits:**
|
||||
- Export specific animations separately
|
||||
- Organize complex sprite sheets
|
||||
- Game engines can reference tags
|
||||
|
||||
### 5. Using Linked Cels
|
||||
|
||||
**Purpose:** Share image data across frames to save memory and maintain consistency.
|
||||
|
||||
Use `mcp__aseprite__link_cel`:
|
||||
- Useful when frame content doesn't change
|
||||
- Example: background layer stays same across animation
|
||||
- Editing one linked cel updates all
|
||||
|
||||
**When to Use:**
|
||||
- Static background elements
|
||||
- Character face in walk cycle (if body animates separately)
|
||||
- Repeated frames in animation
|
||||
|
||||
**Workflow:**
|
||||
1. Create frames with content
|
||||
2. Link cels that should share data
|
||||
3. Edit once, updates everywhere
|
||||
|
||||
### 6. Animation Workflows
|
||||
|
||||
**Workflow 1: Walk Cycle (4 frames)**
|
||||
|
||||
1. Create base sprite (or use existing)
|
||||
2. Add 3 more frames (total 4)
|
||||
3. Edit each frame for walk positions:
|
||||
- Frame 1: Left foot forward
|
||||
- Frame 2: Contact (both feet touching)
|
||||
- Frame 3: Right foot forward
|
||||
- Frame 4: Contact (both feet touching)
|
||||
4. Set all frames to 100ms duration
|
||||
5. Create tag "walk": frames 1-4, forward direction
|
||||
|
||||
**Workflow 2: Idle Animation (2 frames)**
|
||||
|
||||
1. Create base sprite
|
||||
2. Add 1 more frame (total 2)
|
||||
3. Slight variations:
|
||||
- Frame 1: Normal stance
|
||||
- Frame 2: Subtle movement (breathing, blinking)
|
||||
4. Set frames to 500ms duration (slow, subtle)
|
||||
5. Create tag "idle": frames 1-2, ping-pong direction
|
||||
|
||||
**Workflow 3: Complex Multi-Animation Sprite**
|
||||
|
||||
1. Create base sprite
|
||||
2. Add enough frames for all animations:
|
||||
- Idle: 2 frames
|
||||
- Walk: 4 frames
|
||||
- Jump: 4 frames
|
||||
- Total: 10 frames
|
||||
3. Arrange frames sequentially
|
||||
4. Create separate tags:
|
||||
- Tag "idle": frames 1-2
|
||||
- Tag "walk": frames 3-6
|
||||
- Tag "jump": frames 7-10
|
||||
5. Set appropriate frame durations per animation
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Simple 2-Frame Idle
|
||||
|
||||
**User Request:**
|
||||
> "Add a simple idle animation to this sprite"
|
||||
|
||||
**Approach:**
|
||||
1. Add 1 frame (now have frame 1 and 2)
|
||||
2. On frame 2, make subtle change (move pixels up/down 1-2 pixels)
|
||||
3. Set both frames to 500ms duration
|
||||
4. Create tag "idle": frames 1-2, ping-pong direction
|
||||
5. Result: gentle back-and-forth idle motion
|
||||
|
||||
### Example 2: 4-Frame Walk Cycle
|
||||
|
||||
**User Request:**
|
||||
> "Create a walk cycle animation for this character"
|
||||
|
||||
**Approach:**
|
||||
1. Add 3 frames (now have 1, 2, 3, 4)
|
||||
2. Edit each frame for walk poses
|
||||
3. Set all frames to 100ms duration
|
||||
4. Create tag "walk": frames 1-4, forward direction
|
||||
5. Result: looping walk animation at 10 FPS
|
||||
|
||||
### Example 3: Variable Timing Attack
|
||||
|
||||
**User Request:**
|
||||
> "Add an attack animation with a fast strike"
|
||||
|
||||
**Approach:**
|
||||
1. Add 5 frames (total 6 frames, assuming frame 1 exists)
|
||||
2. Frame sequence:
|
||||
- Frame 2: Windup (slow)
|
||||
- Frame 3: Prepare (slow)
|
||||
- Frame 4: Strike (fast)
|
||||
- Frame 5: Follow-through (medium)
|
||||
- Frame 6: Recovery (slow)
|
||||
3. Set durations:
|
||||
- Frames 2-3: 150ms (slow windup)
|
||||
- Frame 4: 30ms (fast strike)
|
||||
- Frame 5: 80ms (medium follow-through)
|
||||
- Frame 6: 120ms (slow recovery)
|
||||
4. Create tag "attack": frames 2-6, forward direction
|
||||
|
||||
### Example 4: Linked Background
|
||||
|
||||
**User Request:**
|
||||
> "Animate the character but keep the background static"
|
||||
|
||||
**Approach:**
|
||||
1. Assume 2 layers: "Background", "Character"
|
||||
2. Add frames for animation
|
||||
3. Edit "Character" layer on each frame for animation
|
||||
4. Link all cels on "Background" layer:
|
||||
- Link frame 2's background to frame 1
|
||||
- Link frame 3's background to frame 1
|
||||
- Link frame 4's background to frame 1
|
||||
5. Background stays identical, character animates
|
||||
|
||||
## Technical Details
|
||||
|
||||
### Frame Numbering
|
||||
- Frames are 1-indexed (first frame is frame 1)
|
||||
- Adding frame at position N inserts at that position
|
||||
- Deleting frame N renumbers subsequent frames
|
||||
|
||||
### Frame Duration Limits
|
||||
- Minimum: 1ms (not recommended, too fast)
|
||||
- Maximum: 65535ms (65.5 seconds)
|
||||
- Practical range: 16ms (60 FPS) to 500ms (2 FPS)
|
||||
|
||||
### Animation Tag Limits
|
||||
- No hard limit on number of tags
|
||||
- Tags can overlap frames
|
||||
- Tag names should be unique and descriptive
|
||||
|
||||
### Linked Cel Behavior
|
||||
- Editing one linked cel updates all linked instances
|
||||
- Unlinking creates independent copy
|
||||
- Useful for memory optimization in large animations
|
||||
|
||||
### Performance
|
||||
- Adding frame: <20ms
|
||||
- Duplicating frame: <30ms
|
||||
- Setting frame duration: <10ms
|
||||
- Creating tag: <15ms
|
||||
- Linking cel: <25ms
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Pattern: Breathing Idle
|
||||
2 frames, ping-pong, slow timing (400-500ms)
|
||||
- Frame 1: Normal
|
||||
- Frame 2: Slight vertical shift (1-2 pixels)
|
||||
|
||||
### Pattern: Basic Walk
|
||||
4 frames, forward, even timing (100ms)
|
||||
- Frame 1: Left foot forward, right foot back
|
||||
- Frame 2: Both feet together (contact)
|
||||
- Frame 3: Right foot forward, left foot back
|
||||
- Frame 4: Both feet together (contact)
|
||||
|
||||
### Pattern: Run Cycle
|
||||
6-8 frames, forward, faster timing (60-80ms)
|
||||
- More exaggerated poses than walk
|
||||
- Longer strides
|
||||
- Leaning forward
|
||||
|
||||
### Pattern: Jump Sequence
|
||||
5-6 frames, forward, variable timing
|
||||
- Frame 1: Crouch (100ms)
|
||||
- Frame 2: Launch (50ms)
|
||||
- Frame 3: Ascend (80ms)
|
||||
- Frame 4: Peak (200ms) - hang time
|
||||
- Frame 5: Descend (80ms)
|
||||
- Frame 6: Land (100ms)
|
||||
|
||||
## Integration with Other Skills
|
||||
|
||||
- **Start with pixel-art-creator** to create base sprite before animating
|
||||
- **Use pixel-art-professional** for polish (shading, antialiasing) after animation
|
||||
- **Hand off to pixel-art-exporter** when user wants to export spritesheet or GIF
|
||||
|
||||
## Error Handling
|
||||
|
||||
**Cannot delete last frame:**
|
||||
- Sprites must have at least 1 frame
|
||||
- Inform user if they try to delete last frame
|
||||
|
||||
**Invalid frame numbers:**
|
||||
- Frame numbers must be 1 to N (where N is total frames)
|
||||
- Check bounds before operations
|
||||
|
||||
**Tag frame range errors:**
|
||||
- "From" frame must be ≤ "To" frame
|
||||
- Both must be valid frame numbers
|
||||
|
||||
## Success Indicators
|
||||
|
||||
You've successfully used this Skill when:
|
||||
- Frames added/modified correctly
|
||||
- Frame durations set appropriately for desired FPS
|
||||
- Animation tags created with correct ranges
|
||||
- User understands animation will loop or play as specified
|
||||
- Animation is ready for export or further refinement
|
||||
847
skills/pixel-art-animator/examples.md
Normal file
847
skills/pixel-art-animator/examples.md
Normal file
@@ -0,0 +1,847 @@
|
||||
# Pixel Art Animator Examples
|
||||
|
||||
This document provides concrete examples of how the pixel-art-animator skill handles animation tasks in Aseprite. Each example shows the user's request, step-by-step approach, actual MCP tool calls with parameters, and expected results.
|
||||
|
||||
Examples are organized by animation complexity, from simple idle animations to complex multi-tag sequences.
|
||||
|
||||
---
|
||||
|
||||
## Simple Idle Animations
|
||||
|
||||
### Example 1: Basic 2-Frame Breathing Animation
|
||||
|
||||
**User Request:**
|
||||
> "Create a simple breathing animation for a character, just 2 frames, 32x32"
|
||||
|
||||
**Approach:**
|
||||
1. Create 32x32 canvas
|
||||
2. Draw base character on frame 1
|
||||
3. Create frame 2 with slight body movement
|
||||
4. Set frame durations for smooth breathing
|
||||
5. Loop animation
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// Create canvas with initial frame
|
||||
mcp__aseprite__create_canvas({
|
||||
width: 32,
|
||||
height: 32,
|
||||
colorMode: "rgb",
|
||||
name: "breathing-idle"
|
||||
})
|
||||
|
||||
// Draw character on frame 1 (base pose)
|
||||
mcp__aseprite__draw_pixels({
|
||||
frame: 1,
|
||||
pixels: [
|
||||
// Head
|
||||
{ x: 14, y: 8, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 15, y: 8, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 16, y: 8, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 17, y: 8, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
// Body (lower position - inhale)
|
||||
{ x: 15, y: 12, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 16, y: 12, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 14, y: 13, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 15, y: 13, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 16, y: 13, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 17, y: 13, color: { r: 50, g: 100, b: 200, a: 255 } }
|
||||
]
|
||||
})
|
||||
|
||||
// Add frame 2
|
||||
mcp__aseprite__add_frame({
|
||||
duration: 500 // 500ms
|
||||
})
|
||||
|
||||
// Draw slightly raised body on frame 2 (exhale)
|
||||
mcp__aseprite__draw_pixels({
|
||||
frame: 2,
|
||||
pixels: [
|
||||
// Head (same position)
|
||||
{ x: 14, y: 8, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 15, y: 8, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 16, y: 8, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 17, y: 8, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
// Body (raised 1 pixel - exhale)
|
||||
{ x: 15, y: 11, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 16, y: 11, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 14, y: 12, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 15, y: 12, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 16, y: 12, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 17, y: 12, color: { r: 50, g: 100, b: 200, a: 255 } }
|
||||
]
|
||||
})
|
||||
|
||||
// Set frame durations for breathing rhythm
|
||||
mcp__aseprite__set_frame_duration({
|
||||
frame: 1,
|
||||
duration: 500 // Hold inhale
|
||||
})
|
||||
|
||||
mcp__aseprite__set_frame_duration({
|
||||
frame: 2,
|
||||
duration: 500 // Hold exhale
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A simple 2-frame breathing animation where the character's body rises and falls subtly.
|
||||
|
||||
**Visual Description:**
|
||||
When played, the animation shows a gentle breathing effect. Frame 1 shows the body in a lower position (inhaled), frame 2 shows it raised slightly (exhaled). The loop creates a continuous, calm breathing rhythm.
|
||||
|
||||
---
|
||||
|
||||
### Example 2: Bobbing Coin Animation
|
||||
|
||||
**User Request:**
|
||||
> "Make a collectible coin that bobs up and down, 3 frames, 16x16"
|
||||
|
||||
**Approach:**
|
||||
1. Create 16x16 indexed canvas
|
||||
2. Draw coin at middle height (frame 1)
|
||||
3. Draw coin at top position (frame 2)
|
||||
4. Draw coin at bottom position (frame 3)
|
||||
5. Set smooth frame timing
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
mcp__aseprite__create_canvas({
|
||||
width: 16,
|
||||
height: 16,
|
||||
colorMode: "indexed",
|
||||
name: "bobbing-coin"
|
||||
})
|
||||
|
||||
mcp__aseprite__set_palette({
|
||||
colors: [
|
||||
{ r: 0, g: 0, b: 0 }, // Index 0: Transparent
|
||||
{ r: 180, g: 140, b: 0 }, // Index 1: Gold
|
||||
{ r: 255, g: 215, b: 0 }, // Index 2: Bright gold
|
||||
{ r: 255, g: 255, b: 200 } // Index 3: Highlight
|
||||
]
|
||||
})
|
||||
|
||||
// Frame 1: Middle position
|
||||
mcp__aseprite__draw_pixels({
|
||||
frame: 1,
|
||||
pixels: [
|
||||
{ x: 6, y: 7, colorIndex: 2 }, { x: 7, y: 7, colorIndex: 2 },
|
||||
{ x: 8, y: 7, colorIndex: 2 }, { x: 9, y: 7, colorIndex: 2 },
|
||||
{ x: 5, y: 8, colorIndex: 2 }, { x: 6, y: 8, colorIndex: 3 },
|
||||
{ x: 7, y: 8, colorIndex: 2 }, { x: 8, y: 8, colorIndex: 2 },
|
||||
{ x: 9, y: 8, colorIndex: 1 }, { x: 10, y: 8, colorIndex: 1 }
|
||||
]
|
||||
})
|
||||
|
||||
// Frame 2: Top position (2 pixels up)
|
||||
mcp__aseprite__add_frame({ duration: 150 })
|
||||
|
||||
mcp__aseprite__draw_pixels({
|
||||
frame: 2,
|
||||
pixels: [
|
||||
{ x: 6, y: 5, colorIndex: 2 }, { x: 7, y: 5, colorIndex: 2 },
|
||||
{ x: 8, y: 5, colorIndex: 2 }, { x: 9, y: 5, colorIndex: 2 },
|
||||
{ x: 5, y: 6, colorIndex: 2 }, { x: 6, y: 6, colorIndex: 3 },
|
||||
{ x: 7, y: 6, colorIndex: 2 }, { x: 8, y: 6, colorIndex: 2 },
|
||||
{ x: 9, y: 6, colorIndex: 1 }, { x: 10, y: 6, colorIndex: 1 }
|
||||
]
|
||||
})
|
||||
|
||||
// Frame 3: Bottom position (2 pixels down)
|
||||
mcp__aseprite__add_frame({ duration: 150 })
|
||||
|
||||
mcp__aseprite__draw_pixels({
|
||||
frame: 3,
|
||||
pixels: [
|
||||
{ x: 6, y: 9, colorIndex: 2 }, { x: 7, y: 9, colorIndex: 2 },
|
||||
{ x: 8, y: 9, colorIndex: 2 }, { x: 9, y: 9, colorIndex: 2 },
|
||||
{ x: 5, y: 10, colorIndex: 2 }, { x: 6, y: 10, colorIndex: 3 },
|
||||
{ x: 7, y: 10, colorIndex: 2 }, { x: 8, y: 10, colorIndex: 2 },
|
||||
{ x: 9, y: 10, colorIndex: 1 }, { x: 10, y: 10, colorIndex: 1 }
|
||||
]
|
||||
})
|
||||
|
||||
// Set consistent frame timing
|
||||
mcp__aseprite__set_frame_duration({ frame: 1, duration: 150 })
|
||||
mcp__aseprite__set_frame_duration({ frame: 2, duration: 150 })
|
||||
mcp__aseprite__set_frame_duration({ frame: 3, duration: 150 })
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A 3-frame bobbing animation where the coin floats up and down smoothly.
|
||||
|
||||
**Visual Description:**
|
||||
The coin appears to float in midair with a smooth up-down motion. The animation cycles through middle → top → bottom → middle, creating a continuous hovering effect typical of collectible items in games.
|
||||
|
||||
---
|
||||
|
||||
### Example 3: Blinking Character
|
||||
|
||||
**User Request:**
|
||||
> "Add a blinking animation to my character sprite, eyes should close for one frame"
|
||||
|
||||
**Approach:**
|
||||
1. Assume canvas exists with character
|
||||
2. Frame 1: Eyes open (existing)
|
||||
3. Frame 2: Same as frame 1 (hold open eyes)
|
||||
4. Frame 3: Eyes closed
|
||||
5. Frame 4: Eyes open again
|
||||
6. Set longer duration for open eyes, short for blink
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// Add frame 2 (duplicate frame 1 to hold open eyes)
|
||||
mcp__aseprite__duplicate_frame({
|
||||
sourceFrame: 1,
|
||||
duration: 2000 // Hold eyes open for 2 seconds
|
||||
})
|
||||
|
||||
// Add frame 3 (blink - eyes closed)
|
||||
mcp__aseprite__add_frame({ duration: 100 })
|
||||
|
||||
mcp__aseprite__draw_pixels({
|
||||
frame: 3,
|
||||
pixels: [
|
||||
// Draw closed eyes (horizontal lines instead of dots)
|
||||
{ x: 12, y: 9, color: { r: 0, g: 0, b: 0, a: 255 } },
|
||||
{ x: 13, y: 9, color: { r: 0, g: 0, b: 0, a: 255 } },
|
||||
{ x: 18, y: 9, color: { r: 0, g: 0, b: 0, a: 255 } },
|
||||
{ x: 19, y: 9, color: { r: 0, g: 0, b: 0, a: 255 } }
|
||||
]
|
||||
})
|
||||
|
||||
// Add frame 4 (duplicate frame 1 for eyes open again)
|
||||
mcp__aseprite__duplicate_frame({
|
||||
sourceFrame: 1,
|
||||
duration: 100 // Brief open before loop
|
||||
})
|
||||
|
||||
// Create animation tag for blinking cycle
|
||||
mcp__aseprite__create_tag({
|
||||
name: "blink_cycle",
|
||||
fromFrame: 1,
|
||||
toFrame: 4,
|
||||
direction: "forward"
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A 4-frame blinking animation with natural timing - eyes stay open long, blink quickly, return to open.
|
||||
|
||||
**Visual Description:**
|
||||
The character's eyes remain open for most of the animation (frames 1-2), quickly close (frame 3), then immediately reopen (frame 4). The timing creates a natural blink that doesn't interrupt the character's idle state.
|
||||
|
||||
---
|
||||
|
||||
## Walk Cycles
|
||||
|
||||
### Example 4: Basic 4-Frame Walk Cycle
|
||||
|
||||
**User Request:**
|
||||
> "Create a simple side-view walk cycle for a character, 4 frames, 32x32"
|
||||
|
||||
**Approach:**
|
||||
1. Create canvas
|
||||
2. Frame 1: Contact pose (left foot forward)
|
||||
3. Frame 2: Passing pose (legs together, body high)
|
||||
4. Frame 3: Contact pose (right foot forward)
|
||||
5. Frame 4: Passing pose (return)
|
||||
6. Set frame durations for walk speed
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
mcp__aseprite__create_canvas({
|
||||
width: 32,
|
||||
height: 32,
|
||||
colorMode: "rgb",
|
||||
name: "walk-cycle"
|
||||
})
|
||||
|
||||
// Frame 1: Left foot forward contact
|
||||
mcp__aseprite__draw_pixels({
|
||||
frame: 1,
|
||||
pixels: [
|
||||
// Head
|
||||
{ x: 15, y: 6, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 16, y: 6, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
// Body
|
||||
{ x: 15, y: 10, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 16, y: 10, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 15, y: 11, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 16, y: 11, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
// Left leg forward
|
||||
{ x: 13, y: 12, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 13, y: 13, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 12, y: 14, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
// Right leg back
|
||||
{ x: 18, y: 12, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 18, y: 13, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 19, y: 14, color: { r: 101, g: 67, b: 33, a: 255 } }
|
||||
]
|
||||
})
|
||||
|
||||
// Frame 2: Passing pose (legs together, body raised)
|
||||
mcp__aseprite__add_frame({ duration: 100 })
|
||||
|
||||
mcp__aseprite__draw_pixels({
|
||||
frame: 2,
|
||||
pixels: [
|
||||
// Head (raised 1 pixel)
|
||||
{ x: 15, y: 5, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 16, y: 5, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
// Body (raised)
|
||||
{ x: 15, y: 9, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 16, y: 9, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 15, y: 10, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 16, y: 10, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
// Legs together, vertical
|
||||
{ x: 15, y: 11, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 15, y: 12, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 15, y: 13, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 16, y: 11, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 16, y: 12, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 16, y: 13, color: { r: 101, g: 67, b: 33, a: 255 } }
|
||||
]
|
||||
})
|
||||
|
||||
// Frame 3: Right foot forward contact
|
||||
mcp__aseprite__add_frame({ duration: 100 })
|
||||
|
||||
mcp__aseprite__draw_pixels({
|
||||
frame: 3,
|
||||
pixels: [
|
||||
// Head
|
||||
{ x: 15, y: 6, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 16, y: 6, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
// Body
|
||||
{ x: 15, y: 10, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 16, y: 10, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 15, y: 11, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 16, y: 11, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
// Right leg forward (mirrored from frame 1)
|
||||
{ x: 18, y: 12, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 18, y: 13, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 19, y: 14, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
// Left leg back
|
||||
{ x: 13, y: 12, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 13, y: 13, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 12, y: 14, color: { r: 101, g: 67, b: 33, a: 255 } }
|
||||
]
|
||||
})
|
||||
|
||||
// Frame 4: Passing pose again (duplicate frame 2)
|
||||
mcp__aseprite__duplicate_frame({
|
||||
sourceFrame: 2,
|
||||
duration: 100
|
||||
})
|
||||
|
||||
// Set consistent walk timing
|
||||
mcp__aseprite__set_frame_duration({ frame: 1, duration: 100 })
|
||||
mcp__aseprite__set_frame_duration({ frame: 2, duration: 100 })
|
||||
mcp__aseprite__set_frame_duration({ frame: 3, duration: 100 })
|
||||
mcp__aseprite__set_frame_duration({ frame: 4, duration: 100 })
|
||||
|
||||
// Create walk cycle tag
|
||||
mcp__aseprite__create_tag({
|
||||
name: "walk",
|
||||
fromFrame: 1,
|
||||
toFrame: 4,
|
||||
direction: "forward"
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A smooth 4-frame walk cycle with proper contact and passing poses.
|
||||
|
||||
**Visual Description:**
|
||||
The character walks smoothly from left to right. Frame 1 shows left foot forward, frame 2 shows legs together with body raised, frame 3 shows right foot forward, frame 4 returns to legs together. The cycle creates natural walking motion.
|
||||
|
||||
---
|
||||
|
||||
### Example 5: 8-Frame Smooth Walk
|
||||
|
||||
**User Request:**
|
||||
> "Create a more detailed walk cycle with 8 frames for smoother animation"
|
||||
|
||||
**Approach:**
|
||||
1. Create canvas
|
||||
2. Add breakdown frames between contact and passing poses
|
||||
3. Include anticipation and follow-through
|
||||
4. Add subtle body bounce and arm swing
|
||||
5. Set faster frame rate for smoothness
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
mcp__aseprite__create_canvas({
|
||||
width: 48,
|
||||
height: 48,
|
||||
colorMode: "rgb",
|
||||
name: "smooth-walk"
|
||||
})
|
||||
|
||||
// Frame 1: Contact - left foot forward
|
||||
mcp__aseprite__draw_pixels({
|
||||
frame: 1,
|
||||
pixels: [
|
||||
// Character at lowest point, left foot planted
|
||||
{ x: 23, y: 10, color: { r: 139, g: 90, b: 43, a: 255 } }, // Head
|
||||
{ x: 24, y: 10, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 23, y: 16, color: { r: 50, g: 100, b: 200, a: 255 } }, // Body
|
||||
{ x: 24, y: 16, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
// Left arm back, right arm forward
|
||||
{ x: 21, y: 17, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 26, y: 17, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
// Left leg forward, right leg back extended
|
||||
{ x: 20, y: 20, color: { r: 101, g: 67, b: 33, a: 255 } }, // Left
|
||||
{ x: 27, y: 21, color: { r: 101, g: 67, b: 33, a: 255 } } // Right
|
||||
]
|
||||
})
|
||||
|
||||
// Frame 2: Recoil - absorbing impact
|
||||
mcp__aseprite__add_frame({ duration: 75 })
|
||||
// ... (slight compression, legs slightly bent)
|
||||
|
||||
// Frame 3: Passing 1 - beginning to rise
|
||||
mcp__aseprite__add_frame({ duration: 75 })
|
||||
// ... (body starting to rise, legs coming together)
|
||||
|
||||
// Frame 4: High point - apex of motion
|
||||
mcp__aseprite__add_frame({ duration: 75 })
|
||||
// ... (body at highest, legs nearly together, vertical)
|
||||
|
||||
// Frame 5: Contact - right foot forward
|
||||
mcp__aseprite__add_frame({ duration: 75 })
|
||||
// ... (mirror of frame 1, right foot now forward)
|
||||
|
||||
// Frame 6: Recoil - absorbing impact (right side)
|
||||
mcp__aseprite__add_frame({ duration: 75 })
|
||||
// ... (slight compression on right side)
|
||||
|
||||
// Frame 7: Passing 2 - beginning to rise
|
||||
mcp__aseprite__add_frame({ duration: 75 })
|
||||
// ... (body rising again, legs coming together)
|
||||
|
||||
// Frame 8: High point - apex returning to start
|
||||
mcp__aseprite__add_frame({ duration: 75 })
|
||||
// ... (body at high point, completing cycle)
|
||||
|
||||
// Set consistent smooth timing
|
||||
for (let i = 1; i <= 8; i++) {
|
||||
mcp__aseprite__set_frame_duration({ frame: i, duration: 75 })
|
||||
}
|
||||
|
||||
mcp__aseprite__create_tag({
|
||||
name: "smooth_walk",
|
||||
fromFrame: 1,
|
||||
toFrame: 8,
|
||||
direction: "forward"
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A fluid 8-frame walk cycle with smooth weight transfer and natural body movement.
|
||||
|
||||
**Visual Description:**
|
||||
The animation shows detailed walking mechanics with the body rising and falling naturally. Arms swing opposite to legs, the torso compresses slightly on foot contact, and rises smoothly during passing poses. The extra frames create very smooth motion at 75ms per frame.
|
||||
|
||||
---
|
||||
|
||||
## Complex Animations
|
||||
|
||||
### Example 6: Jump Sequence
|
||||
|
||||
**User Request:**
|
||||
> "Create a jump animation - anticipation, takeoff, air, landing"
|
||||
|
||||
**Approach:**
|
||||
1. Frame 1-2: Crouch (anticipation)
|
||||
2. Frame 3: Takeoff push
|
||||
3. Frame 4-6: Rising (different heights)
|
||||
4. Frame 7-8: Falling
|
||||
5. Frame 9: Land (compression)
|
||||
6. Frame 10: Return to idle
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
mcp__aseprite__create_canvas({
|
||||
width: 32,
|
||||
height: 48,
|
||||
colorMode: "rgb",
|
||||
name: "jump-animation"
|
||||
})
|
||||
|
||||
// Frame 1: Start crouch anticipation
|
||||
mcp__aseprite__draw_pixels({
|
||||
frame: 1,
|
||||
pixels: [
|
||||
// Character in normal standing position
|
||||
{ x: 15, y: 20, color: { r: 139, g: 90, b: 43, a: 255 } }, // Head
|
||||
{ x: 16, y: 20, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 15, y: 24, color: { r: 50, g: 100, b: 200, a: 255 } }, // Body
|
||||
{ x: 16, y: 24, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 15, y: 28, color: { r: 101, g: 67, b: 33, a: 255 } }, // Legs
|
||||
{ x: 16, y: 28, color: { r: 101, g: 67, b: 33, a: 255 } }
|
||||
]
|
||||
})
|
||||
|
||||
// Frame 2: Deep crouch
|
||||
mcp__aseprite__add_frame({ duration: 150 })
|
||||
|
||||
mcp__aseprite__draw_pixels({
|
||||
frame: 2,
|
||||
pixels: [
|
||||
// Character crouched lower (head down 4 pixels, legs compressed)
|
||||
{ x: 15, y: 24, color: { r: 139, g: 90, b: 43, a: 255 } }, // Head lower
|
||||
{ x: 16, y: 24, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 15, y: 27, color: { r: 50, g: 100, b: 200, a: 255 } }, // Body lower
|
||||
{ x: 16, y: 27, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 14, y: 30, color: { r: 101, g: 67, b: 33, a: 255 } }, // Legs bent wide
|
||||
{ x: 15, y: 30, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 16, y: 30, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 17, y: 30, color: { r: 101, g: 67, b: 33, a: 255 } }
|
||||
]
|
||||
})
|
||||
|
||||
// Frame 3: Takeoff extension
|
||||
mcp__aseprite__add_frame({ duration: 100 })
|
||||
|
||||
mcp__aseprite__draw_pixels({
|
||||
frame: 3,
|
||||
pixels: [
|
||||
// Character extending upward, arms down
|
||||
{ x: 15, y: 22, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 16, y: 22, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 15, y: 25, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 16, y: 25, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
// Legs extended downward, pushing off
|
||||
{ x: 15, y: 28, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 16, y: 28, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 15, y: 29, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 16, y: 29, color: { r: 101, g: 67, b: 33, a: 255 } }
|
||||
]
|
||||
})
|
||||
|
||||
// Frame 4: Rising - low air
|
||||
mcp__aseprite__add_frame({ duration: 100 })
|
||||
|
||||
mcp__aseprite__draw_pixels({
|
||||
frame: 4,
|
||||
pixels: [
|
||||
// Character rising, arms starting to go up
|
||||
{ x: 15, y: 16, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 16, y: 16, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 15, y: 19, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 16, y: 19, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
// Arms raised halfway
|
||||
{ x: 13, y: 19, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 18, y: 19, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
// Legs tucked
|
||||
{ x: 15, y: 22, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 16, y: 22, color: { r: 101, g: 67, b: 33, a: 255 } }
|
||||
]
|
||||
})
|
||||
|
||||
// Frame 5: Apex - highest point
|
||||
mcp__aseprite__add_frame({ duration: 150 })
|
||||
|
||||
mcp__aseprite__draw_pixels({
|
||||
frame: 5,
|
||||
pixels: [
|
||||
// Character at peak, arms fully raised
|
||||
{ x: 15, y: 10, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 16, y: 10, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 15, y: 13, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 16, y: 13, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
// Arms up
|
||||
{ x: 14, y: 9, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 17, y: 9, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
// Legs tucked compact
|
||||
{ x: 15, y: 16, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 16, y: 16, color: { r: 101, g: 67, b: 33, a: 255 } }
|
||||
]
|
||||
})
|
||||
|
||||
// Frame 6: Falling - beginning descent
|
||||
mcp__aseprite__add_frame({ duration: 100 })
|
||||
|
||||
// Frame 7: Falling - mid descent
|
||||
mcp__aseprite__add_frame({ duration: 100 })
|
||||
|
||||
// Frame 8: Landing preparation
|
||||
mcp__aseprite__add_frame({ duration: 100 })
|
||||
|
||||
// Frame 9: Impact compression
|
||||
mcp__aseprite__add_frame({ duration: 100 })
|
||||
|
||||
// Frame 10: Recovery to idle
|
||||
mcp__aseprite__add_frame({ duration: 150 })
|
||||
|
||||
// Create jump animation tag
|
||||
mcp__aseprite__create_tag({
|
||||
name: "jump",
|
||||
fromFrame: 1,
|
||||
toFrame: 10,
|
||||
direction: "forward"
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A complete jump animation with anticipation, aerial phase, and landing recovery.
|
||||
|
||||
**Visual Description:**
|
||||
The character crouches down in preparation (frames 1-2), explosively extends upward (frame 3), rises into the air with arms moving up (frames 4-5), hangs at the apex (frame 5), falls back down (frames 6-7), prepares for landing (frame 8), compresses on impact (frame 9), and recovers to standing (frame 10).
|
||||
|
||||
---
|
||||
|
||||
## Linked Cels
|
||||
|
||||
### Example 7: Walking with Static Background
|
||||
|
||||
**User Request:**
|
||||
> "Create a walk cycle but keep the background layer the same across all frames"
|
||||
|
||||
**Approach:**
|
||||
1. Create background layer
|
||||
2. Draw static background on frame 1
|
||||
3. Link background cel across all frames
|
||||
4. Create character layer
|
||||
5. Animate character walk on character layer only
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
mcp__aseprite__create_canvas({
|
||||
width: 64,
|
||||
height: 48,
|
||||
colorMode: "rgb",
|
||||
name: "walk-with-background"
|
||||
})
|
||||
|
||||
// Create background layer
|
||||
mcp__aseprite__add_layer({
|
||||
name: "background"
|
||||
})
|
||||
|
||||
// Draw static background on frame 1
|
||||
mcp__aseprite__draw_pixels({
|
||||
layer: "background",
|
||||
frame: 1,
|
||||
pixels: [
|
||||
// Sky - fill top half with blue
|
||||
...Array.from({ length: 64 * 20 }, (_, i) => ({
|
||||
x: i % 64,
|
||||
y: Math.floor(i / 64),
|
||||
color: { r: 135, g: 206, b: 235, a: 255 }
|
||||
})),
|
||||
// Ground - fill bottom with green
|
||||
...Array.from({ length: 64 * 28 }, (_, i) => ({
|
||||
x: i % 64,
|
||||
y: 20 + Math.floor(i / 64),
|
||||
color: { r: 34, g: 139, b: 34, a: 255 }
|
||||
}))
|
||||
]
|
||||
})
|
||||
|
||||
// Add frames for walk cycle
|
||||
mcp__aseprite__add_frame({ duration: 100 })
|
||||
mcp__aseprite__add_frame({ duration: 100 })
|
||||
mcp__aseprite__add_frame({ duration: 100 })
|
||||
|
||||
// Link background cel across all frames (background stays static)
|
||||
mcp__aseprite__link_cel({
|
||||
layer: "background",
|
||||
frame: 1,
|
||||
targetFrames: [2, 3, 4]
|
||||
})
|
||||
|
||||
// Create character layer for animation
|
||||
mcp__aseprite__add_layer({
|
||||
name: "character"
|
||||
})
|
||||
|
||||
// Animate character walk on character layer
|
||||
// Frame 1: Contact
|
||||
mcp__aseprite__draw_pixels({
|
||||
layer: "character",
|
||||
frame: 1,
|
||||
pixels: [/* character pose 1 */]
|
||||
})
|
||||
|
||||
// Frame 2: Passing
|
||||
mcp__aseprite__draw_pixels({
|
||||
layer: "character",
|
||||
frame: 2,
|
||||
pixels: [/* character pose 2 */]
|
||||
})
|
||||
|
||||
// Frame 3: Contact
|
||||
mcp__aseprite__draw_pixels({
|
||||
layer: "character",
|
||||
frame: 3,
|
||||
pixels: [/* character pose 3 */]
|
||||
})
|
||||
|
||||
// Frame 4: Passing
|
||||
mcp__aseprite__draw_pixels({
|
||||
layer: "character",
|
||||
frame: 4,
|
||||
pixels: [/* character pose 4 */]
|
||||
})
|
||||
|
||||
mcp__aseprite__create_tag({
|
||||
name: "walk_with_bg",
|
||||
fromFrame: 1,
|
||||
toFrame: 4,
|
||||
direction: "forward"
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A walk cycle animation where the background remains static while the character animates.
|
||||
|
||||
**Visual Description:**
|
||||
The background layer (sky and ground) remains identical across all frames thanks to linked cels. Only the character layer changes, showing the walk cycle. This is memory-efficient and typical for game animations.
|
||||
|
||||
---
|
||||
|
||||
## Multiple Animation Tags
|
||||
|
||||
### Example 8: Character with Idle, Walk, and Attack
|
||||
|
||||
**User Request:**
|
||||
> "Create a character spritesheet with separate idle, walk, and attack animations"
|
||||
|
||||
**Approach:**
|
||||
1. Create canvas
|
||||
2. Frames 1-4: Idle animation
|
||||
3. Frames 5-8: Walk animation
|
||||
4. Frames 9-14: Attack animation
|
||||
5. Tag each animation sequence
|
||||
6. Set appropriate durations
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
mcp__aseprite__create_canvas({
|
||||
width: 32,
|
||||
height: 32,
|
||||
colorMode: "rgb",
|
||||
name: "character-animations"
|
||||
})
|
||||
|
||||
// === IDLE ANIMATION (Frames 1-4) ===
|
||||
// Frame 1: Idle base
|
||||
mcp__aseprite__draw_pixels({
|
||||
frame: 1,
|
||||
pixels: [/* idle pose 1 */]
|
||||
})
|
||||
|
||||
// Frame 2: Idle breath
|
||||
mcp__aseprite__add_frame({ duration: 500 })
|
||||
mcp__aseprite__draw_pixels({
|
||||
frame: 2,
|
||||
pixels: [/* idle pose 2 - slight body rise */]
|
||||
})
|
||||
|
||||
// Frame 3: Hold
|
||||
mcp__aseprite__duplicate_frame({ sourceFrame: 2, duration: 300 })
|
||||
|
||||
// Frame 4: Return
|
||||
mcp__aseprite__duplicate_frame({ sourceFrame: 1, duration: 200 })
|
||||
|
||||
// Tag idle animation
|
||||
mcp__aseprite__create_tag({
|
||||
name: "idle",
|
||||
fromFrame: 1,
|
||||
toFrame: 4,
|
||||
direction: "forward"
|
||||
})
|
||||
|
||||
// === WALK ANIMATION (Frames 5-8) ===
|
||||
// Frame 5: Left foot forward
|
||||
mcp__aseprite__add_frame({ duration: 100 })
|
||||
mcp__aseprite__draw_pixels({
|
||||
frame: 5,
|
||||
pixels: [/* walk pose 1 */]
|
||||
})
|
||||
|
||||
// Frame 6: Passing
|
||||
mcp__aseprite__add_frame({ duration: 100 })
|
||||
mcp__aseprite__draw_pixels({
|
||||
frame: 6,
|
||||
pixels: [/* walk pose 2 */]
|
||||
})
|
||||
|
||||
// Frame 7: Right foot forward
|
||||
mcp__aseprite__add_frame({ duration: 100 })
|
||||
mcp__aseprite__draw_pixels({
|
||||
frame: 7,
|
||||
pixels: [/* walk pose 3 */]
|
||||
})
|
||||
|
||||
// Frame 8: Passing
|
||||
mcp__aseprite__add_frame({ duration: 100 })
|
||||
mcp__aseprite__draw_pixels({
|
||||
frame: 8,
|
||||
pixels: [/* walk pose 4 */]
|
||||
})
|
||||
|
||||
// Tag walk animation
|
||||
mcp__aseprite__create_tag({
|
||||
name: "walk",
|
||||
fromFrame: 5,
|
||||
toFrame: 8,
|
||||
direction: "forward"
|
||||
})
|
||||
|
||||
// === ATTACK ANIMATION (Frames 9-14) ===
|
||||
// Frame 9: Wind up
|
||||
mcp__aseprite__add_frame({ duration: 150 })
|
||||
mcp__aseprite__draw_pixels({
|
||||
frame: 9,
|
||||
pixels: [/* attack windup */]
|
||||
})
|
||||
|
||||
// Frame 10: Anticipation
|
||||
mcp__aseprite__add_frame({ duration: 100 })
|
||||
|
||||
// Frame 11: Strike start
|
||||
mcp__aseprite__add_frame({ duration: 50 })
|
||||
|
||||
// Frame 12: Strike peak
|
||||
mcp__aseprite__add_frame({ duration: 50 })
|
||||
|
||||
// Frame 13: Follow through
|
||||
mcp__aseprite__add_frame({ duration: 100 })
|
||||
|
||||
// Frame 14: Recovery
|
||||
mcp__aseprite__add_frame({ duration: 150 })
|
||||
|
||||
// Tag attack animation
|
||||
mcp__aseprite__create_tag({
|
||||
name: "attack",
|
||||
fromFrame: 9,
|
||||
toFrame: 14,
|
||||
direction: "forward"
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A complete character animation set with three distinct, tagged animations that can be called independently.
|
||||
|
||||
**Visual Description:**
|
||||
The sprite file contains three separate animation sequences: frames 1-4 show idle breathing, frames 5-8 show walking, frames 9-14 show an attack. Each animation is tagged so game engines can play "idle", "walk", or "attack" on demand.
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
This examples collection demonstrates the pixel-art-animator skill's capabilities:
|
||||
|
||||
- **Simple idle animations** (Examples 1-3): Basic 2-3 frame loops for breathing, bobbing, blinking
|
||||
- **Walk cycles** (Examples 4-5): Both simple 4-frame and detailed 8-frame walks
|
||||
- **Complex animations** (Example 6): Multi-phase sequences like jumping
|
||||
- **Linked cels** (Example 7): Efficient background management
|
||||
- **Multiple animations** (Example 8): Complete character animation sets with tags
|
||||
|
||||
Each example shows complete MCP tool call syntax with frame-by-frame breakdowns, timing considerations, and tagging strategies for game-ready animations.
|
||||
270
skills/pixel-art-animator/reference.md
Normal file
270
skills/pixel-art-animator/reference.md
Normal file
@@ -0,0 +1,270 @@
|
||||
# Pixel Art Animator - Technical Reference
|
||||
|
||||
## Frame Rate Conversions
|
||||
|
||||
| FPS | Frame Duration (ms) | Use Case |
|
||||
|-----|-------------------|----------|
|
||||
| 60 | 16-17 | Smooth modern games, very fast animation |
|
||||
| 30 | 33 | Standard modern animation |
|
||||
| 24 | 42 | Film-like animation |
|
||||
| 20 | 50 | Smooth retro animation |
|
||||
| 15 | 67 | Retro game animation |
|
||||
| 12 | 83 | Traditional animation (on twos) |
|
||||
| 10 | 100 | Classic pixel art animation |
|
||||
| 8 | 125 | Slower animation |
|
||||
| 6 | 167 | Very slow animation |
|
||||
| 4 | 250 | Idle/breathing animations |
|
||||
| 2 | 500 | Very slow idle effects |
|
||||
|
||||
## Classic Animation Cycles
|
||||
|
||||
### Walk Cycle (4 frames)
|
||||
```
|
||||
Frame 1: Contact (right foot forward)
|
||||
Frame 2: Down (compression)
|
||||
Frame 3: Pass (left foot passing)
|
||||
Frame 4: Up (right foot pushes off)
|
||||
```
|
||||
|
||||
### Run Cycle (8 frames)
|
||||
```
|
||||
Frame 1: Contact right
|
||||
Frame 2: Down right
|
||||
Frame 3: Pass
|
||||
Frame 4: Up left
|
||||
Frame 5: Contact left
|
||||
Frame 6: Down left
|
||||
Frame 7: Pass
|
||||
Frame 8: Up right
|
||||
```
|
||||
|
||||
### Idle Breathing (2-4 frames)
|
||||
```
|
||||
2-frame:
|
||||
- Frame 1: Normal
|
||||
- Frame 2: Slight rise (+1-2 pixels vertically)
|
||||
|
||||
4-frame:
|
||||
- Frame 1: Normal
|
||||
- Frame 2: Inhale (expand)
|
||||
- Frame 3: Hold (peak)
|
||||
- Frame 4: Exhale (contract)
|
||||
```
|
||||
|
||||
## Animation Principles (applied to pixel art)
|
||||
|
||||
### 1. Timing
|
||||
- Slow movements: more frames, longer durations
|
||||
- Fast movements: fewer frames, shorter durations
|
||||
- Impacts: very short duration (30-50ms)
|
||||
|
||||
### 2. Anticipation
|
||||
- Windup before action (crouch before jump)
|
||||
- 1-2 frames of preparation
|
||||
- Makes action feel more powerful
|
||||
|
||||
### 3. Follow-through
|
||||
- Continuation after main action
|
||||
- Hair, clothes continue moving after body stops
|
||||
- 1-2 frames of settling
|
||||
|
||||
### 4. Ease In/Ease Out
|
||||
- Slow start, fast middle, slow end
|
||||
- Variable frame durations:
|
||||
- Start: 150ms
|
||||
- Middle: 50ms
|
||||
- End: 150ms
|
||||
|
||||
### 5. Arcs
|
||||
- Natural motion follows arcs, not straight lines
|
||||
- Jumping: arc trajectory
|
||||
- Swinging arms: arc motion
|
||||
|
||||
### 6. Squash and Stretch
|
||||
- Exaggeration for impact
|
||||
- Ball bouncing: squash on impact, stretch in air
|
||||
- 1-2 pixels of deformation
|
||||
|
||||
## Retro Console Frame Limitations
|
||||
|
||||
### NES (Nintendo Entertainment System)
|
||||
- Typical: 60 FPS engine, animations at 10-15 FPS
|
||||
- Sprite flicker for >8 sprites/scanline
|
||||
- Limited sprite sizes influenced animation
|
||||
|
||||
### Game Boy
|
||||
- 60 FPS capability, animations at 8-15 FPS
|
||||
- Simple animations due to small sprites
|
||||
- 2-4 frame cycles common
|
||||
|
||||
### SNES (Super Nintendo)
|
||||
- 60 FPS capable, smoother animations possible
|
||||
- 8-16 frame animations for characters
|
||||
- More detailed animation than NES
|
||||
|
||||
## Frame Count Guidelines
|
||||
|
||||
| Animation Type | Frame Count | Typical FPS | Notes |
|
||||
|----------------|-------------|-------------|-------|
|
||||
| Idle | 2-4 | 4-6 | Subtle, looping |
|
||||
| Walk | 4-8 | 10-12 | Even, rhythmic |
|
||||
| Run | 6-12 | 12-15 | Faster than walk |
|
||||
| Jump | 4-8 | 12-15 | Arc motion |
|
||||
| Attack | 3-8 | 12-20 | Fast strike, slow recovery |
|
||||
| Death | 5-10 | 8-12 | Dramatic, doesn't loop |
|
||||
| Spell Cast | 4-10 | 10-15 | Buildup, release, recovery |
|
||||
| Item Use | 3-6 | 12-15 | Quick action |
|
||||
|
||||
## Animation Tag Best Practices
|
||||
|
||||
### Naming Conventions
|
||||
- Lowercase, descriptive names
|
||||
- Examples: "idle", "walk", "run", "attack", "jump", "death"
|
||||
- Variations: "walk_left", "walk_right", "attack_1", "attack_2"
|
||||
|
||||
### Organization Strategies
|
||||
|
||||
**Sequential Layout:**
|
||||
```
|
||||
Frames 1-2: idle
|
||||
Frames 3-6: walk
|
||||
Frames 7-12: run
|
||||
Frames 13-17: attack
|
||||
```
|
||||
|
||||
**Grouped Layout:**
|
||||
```
|
||||
Frames 1-10: Player character animations
|
||||
Frames 11-20: Enemy character animations
|
||||
Frames 21-30: Special effects
|
||||
```
|
||||
|
||||
### Playback Directions
|
||||
|
||||
**Forward:**
|
||||
- Most animations (walk, run, attack)
|
||||
- Plays once through, then loops
|
||||
|
||||
**Reverse:**
|
||||
- Rare, for special effects
|
||||
- Rewinding animations
|
||||
|
||||
**Ping-pong:**
|
||||
- Idle breathing
|
||||
- Flickering effects
|
||||
- Oscillating animations
|
||||
- Plays forward, then backward, then repeats
|
||||
|
||||
## Linked Cel Strategies
|
||||
|
||||
### When to Use
|
||||
1. **Static backgrounds** across animated character
|
||||
2. **Unchanged parts** of character (e.g., hat while body animates)
|
||||
3. **Repeated frames** in cycle (exact duplicates)
|
||||
4. **Memory optimization** for large sprites
|
||||
|
||||
### When NOT to Use
|
||||
1. **Every frame is different** (no shared data)
|
||||
2. **Small sprites** (minimal memory saved)
|
||||
3. **Experimental animations** (may need to edit each frame)
|
||||
|
||||
### Workflow
|
||||
1. Create frames
|
||||
2. Identify repeated/static content
|
||||
3. Link cels for that content
|
||||
4. Edit linked cel once, updates all
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Efficient Animation
|
||||
- **Batch operations:** Add multiple frames at once when possible
|
||||
- **Duplicate then edit:** Faster than creating from scratch
|
||||
- **Link static content:** Saves memory and editing time
|
||||
|
||||
### Large Sprites
|
||||
- 128x128+ sprites with many frames can be slow
|
||||
- Consider breaking into smaller parts
|
||||
- Use layers and linked cels strategically
|
||||
|
||||
## Common Timing Patterns
|
||||
|
||||
### Even Timing (simplest)
|
||||
```
|
||||
All frames: 100ms
|
||||
```
|
||||
Predictable, easy to edit.
|
||||
|
||||
### Hold First Frame
|
||||
```
|
||||
Frame 1: 200ms (starting pose)
|
||||
Frames 2-4: 100ms (action)
|
||||
```
|
||||
Emphasizes starting position.
|
||||
|
||||
### Hold Last Frame
|
||||
```
|
||||
Frames 1-3: 100ms (action)
|
||||
Frame 4: 200ms (ending pose)
|
||||
```
|
||||
Emphasizes ending position.
|
||||
|
||||
### Fast Action
|
||||
```
|
||||
Frame 1: 150ms (anticipation)
|
||||
Frame 2: 30ms (strike)
|
||||
Frame 3: 100ms (follow-through)
|
||||
```
|
||||
Creates snappy, impactful feel.
|
||||
|
||||
### Slow Buildup
|
||||
```
|
||||
Frame 1: 200ms
|
||||
Frame 2: 150ms
|
||||
Frame 3: 100ms
|
||||
Frame 4: 50ms
|
||||
```
|
||||
Accelerating motion.
|
||||
|
||||
## Sprite Sheet Export Considerations
|
||||
|
||||
When planning animations for export:
|
||||
|
||||
1. **Frame Layout:**
|
||||
- Horizontal strip: all frames in one row
|
||||
- Vertical strip: all frames in one column
|
||||
- Grid: frames arranged in rows/columns
|
||||
|
||||
2. **Frame Dimensions:**
|
||||
- Keep all frames same size for easy parsing
|
||||
- Padding between frames if needed
|
||||
|
||||
3. **Animation Tags:**
|
||||
- Export tags separately or together
|
||||
- Game engines can reference tag names
|
||||
|
||||
4. **File Format:**
|
||||
- GIF for simple web animations (256 colors max)
|
||||
- PNG sequence for high quality
|
||||
- Sprite sheet for game engines
|
||||
|
||||
## Integration with Game Engines
|
||||
|
||||
### Unity
|
||||
- Import sprite sheet
|
||||
- Use Unity's animation system
|
||||
- Reference animation tags (if exported in metadata)
|
||||
|
||||
### Godot
|
||||
- SpriteFrames resource
|
||||
- AnimationPlayer node
|
||||
- Import PNG sequences or sprite sheets
|
||||
|
||||
### Phaser (JavaScript)
|
||||
- Load sprite sheet
|
||||
- Define animations with frame ranges
|
||||
- Play animations by name
|
||||
|
||||
### GameMaker
|
||||
- Import sprite strip
|
||||
- Set frames per second
|
||||
- Automatic loop on last frame
|
||||
277
skills/pixel-art-creator/SKILL.md
Normal file
277
skills/pixel-art-creator/SKILL.md
Normal file
@@ -0,0 +1,277 @@
|
||||
---
|
||||
name: Pixel Art Creator
|
||||
description: Create new pixel art sprites from scratch with canvas creation, layer management, and basic drawing primitives. Use when the user wants to create a sprite, draw pixel art, make a new canvas, start a new image, begin a new project, or mentions pixel dimensions like "64x64", "32x32 sprite", "128 by 128", "16 pixel icon". Trigger on: "create", "new", "make", "draw", "sprite", "canvas", "image", "icon", "tile", "character", "background", dimensions (WxH), "from scratch", "blank canvas", "empty sprite", "Game Boy", "NES", "retro", color mode mentions ("RGB", "indexed", "grayscale"). Also use for drawing basic shapes like "circle", "rectangle", "line", "pixel", "fill", "outline".
|
||||
allowed-tools: Read, Bash, mcp__aseprite__create_canvas, mcp__aseprite__add_layer, mcp__aseprite__delete_layer, mcp__aseprite__get_sprite_info, mcp__aseprite__draw_pixels, mcp__aseprite__draw_line, mcp__aseprite__draw_rectangle, mcp__aseprite__draw_circle, mcp__aseprite__draw_contour, mcp__aseprite__fill_area, mcp__aseprite__set_palette, mcp__aseprite__get_palette
|
||||
---
|
||||
|
||||
# Pixel Art Creator
|
||||
|
||||
## Overview
|
||||
|
||||
This Skill enables creation of new pixel art sprites with full control over canvas properties, layers, and basic drawing operations. It's the foundational Skill for all pixel art workflows.
|
||||
|
||||
## When to Use
|
||||
|
||||
Use this Skill when the user:
|
||||
- Wants to "create a sprite" or "make pixel art"
|
||||
- Mentions sprite dimensions (e.g., "64x64", "32 by 32", "128 pixels wide")
|
||||
- Asks to "draw" basic shapes (pixels, lines, rectangles, circles)
|
||||
- Needs to set up a canvas or layers
|
||||
- Mentions color modes (RGB, Grayscale, Indexed)
|
||||
|
||||
**Trigger Keywords:** create, sprite, canvas, draw, pixel art, dimensions, layer, new sprite
|
||||
|
||||
## Instructions
|
||||
|
||||
### 1. Creating a Canvas
|
||||
|
||||
When the user requests a sprite, create the canvas first:
|
||||
|
||||
**Color Modes:**
|
||||
- **RGB**: Full color (24-bit), best for modern pixel art
|
||||
- **Grayscale**: Shades of gray only, for monochrome art
|
||||
- **Indexed**: Limited palette (1-256 colors), for retro game art
|
||||
|
||||
**Recommended Sizes:**
|
||||
- **Icons**: 16x16, 24x24, 32x32
|
||||
- **Characters**: 32x32, 48x48, 64x64
|
||||
- **Tiles**: 16x16, 32x32, 64x64
|
||||
- **Scenes**: 128x128, 256x256, 320x240 (retro resolution)
|
||||
|
||||
Use `mcp__aseprite__create_canvas` with parameters:
|
||||
- `width`: 1-65535 pixels
|
||||
- `height`: 1-65535 pixels
|
||||
- `color_mode`: "RGB", "Grayscale", or "Indexed"
|
||||
|
||||
### 2. Managing Layers
|
||||
|
||||
**Adding Layers:**
|
||||
Use `mcp__aseprite__add_layer` to organize sprite elements:
|
||||
- Background layer for solid colors or backgrounds
|
||||
- Character layer for main subject
|
||||
- Effects layer for highlights, shadows, outlines
|
||||
- Detail layer for accessories or fine details
|
||||
|
||||
**Layer Workflow:**
|
||||
1. Create canvas
|
||||
2. Add named layers (e.g., "Background", "Character", "Effects")
|
||||
3. Draw on specific layers
|
||||
4. Use layers for organization and editing flexibility
|
||||
|
||||
**Important:** Cannot delete the last layer in a sprite.
|
||||
|
||||
### 3. Drawing Primitives
|
||||
|
||||
**Draw Individual Pixels:**
|
||||
Use `mcp__aseprite__draw_pixels` for precise pixel placement:
|
||||
- Supports batch operations (multiple pixels at once)
|
||||
- Accepts colors in hex format (#RRGGBB) or palette indices
|
||||
- Can snap to nearest palette color (for Indexed mode)
|
||||
|
||||
Example:
|
||||
```
|
||||
Draw pixels at coordinates:
|
||||
- (10, 10) in red (#FF0000)
|
||||
- (11, 10) in red (#FF0000)
|
||||
- (12, 10) in red (#FF0000)
|
||||
```
|
||||
|
||||
**Draw Lines:**
|
||||
Use `mcp__aseprite__draw_line`:
|
||||
- Straight lines between two points
|
||||
- Useful for outlines, edges, connecting points
|
||||
|
||||
**Draw Rectangles:**
|
||||
Use `mcp__aseprite__draw_rectangle`:
|
||||
- Filled or outline mode
|
||||
- Perfect for backgrounds, UI elements, platforms
|
||||
|
||||
**Draw Circles/Ellipses:**
|
||||
Use `mcp__aseprite__draw_circle`:
|
||||
- Filled or outline mode
|
||||
- For round objects, planets, effects
|
||||
|
||||
**Draw Contours (Polylines/Polygons):**
|
||||
Use `mcp__aseprite__draw_contour`:
|
||||
- Connect multiple points
|
||||
- Useful for complex shapes, terrain, irregular outlines
|
||||
|
||||
**Flood Fill:**
|
||||
Use `mcp__aseprite__fill_area`:
|
||||
- Fill connected pixels of the same color
|
||||
- Like a paint bucket tool
|
||||
- Great for filling large areas quickly
|
||||
|
||||
### 4. Working with Colors
|
||||
|
||||
**Setting Colors:**
|
||||
- **Hex Format**: #RRGGBB (e.g., #FF0000 for red)
|
||||
- **RGB**: Specify red, green, blue values (0-255)
|
||||
- **Palette Index**: For Indexed mode (0-255)
|
||||
|
||||
**Common Colors:**
|
||||
- Red: #FF0000
|
||||
- Green: #00FF00
|
||||
- Blue: #0000FF
|
||||
- Yellow: #FFFF00
|
||||
- Cyan: #00FFFF
|
||||
- Magenta: #FF00FF
|
||||
- Black: #000000
|
||||
- White: #FFFFFF
|
||||
|
||||
**Color Palettes:**
|
||||
For Indexed color mode, set the palette first:
|
||||
- Use `mcp__aseprite__set_palette` with array of hex colors
|
||||
- Example: ["#000000", "#FFFFFF", "#FF0000", "#00FF00"]
|
||||
|
||||
### 5. Workflow Best Practices
|
||||
|
||||
**Typical Creation Workflow:**
|
||||
1. **Understand Requirements**
|
||||
- What size sprite?
|
||||
- What color mode?
|
||||
- What style (modern vs retro)?
|
||||
|
||||
2. **Create Canvas**
|
||||
- Choose appropriate dimensions
|
||||
- Select color mode (RGB for modern, Indexed for retro)
|
||||
|
||||
3. **Set Up Layers** (optional but recommended)
|
||||
- Add layers for organization
|
||||
- Name layers descriptively
|
||||
|
||||
4. **Set Palette** (for Indexed mode)
|
||||
- Define limited color palette
|
||||
- Use retro-appropriate palettes (NES: 16 colors, Game Boy: 4 colors)
|
||||
|
||||
5. **Draw Basic Shapes**
|
||||
- Start with outline
|
||||
- Fill with colors
|
||||
- Add details
|
||||
|
||||
6. **Verify Result**
|
||||
- Use `mcp__aseprite__get_sprite_info` to check properties
|
||||
- Describe what was created to user
|
||||
|
||||
7. **Prepare for Export** (if requested)
|
||||
- Hand off to pixel-art-exporter Skill
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Simple Sprite
|
||||
|
||||
**User Request:** "Create a 32x32 sprite with a red circle"
|
||||
|
||||
**Approach:**
|
||||
1. Create 32x32 RGB canvas
|
||||
2. Draw filled circle in center (radius 12) in red
|
||||
3. Confirm creation
|
||||
|
||||
### Example 2: Layered Sprite
|
||||
|
||||
**User Request:** "Make a 64x64 sprite with a blue background and a yellow character"
|
||||
|
||||
**Approach:**
|
||||
1. Create 64x64 RGB canvas
|
||||
2. Add layer "Background"
|
||||
3. Fill entire canvas with blue (#0000FF) on Background layer
|
||||
4. Add layer "Character"
|
||||
5. Draw yellow (#FFFF00) rectangle or shape on Character layer
|
||||
6. Confirm layers and contents
|
||||
|
||||
### Example 3: Indexed Color Sprite
|
||||
|
||||
**User Request:** "Create a 48x48 Game Boy style sprite"
|
||||
|
||||
**Approach:**
|
||||
1. Create 48x48 Indexed canvas
|
||||
2. Set Game Boy palette: ["#0F380F", "#306230", "#8BAC0F", "#9BBC0F"]
|
||||
3. Draw using 4-color palette
|
||||
4. Use pixel-perfect drawing
|
||||
|
||||
### Example 4: Complex Shape
|
||||
|
||||
**User Request:** "Draw a pixelated tree on a 64x64 canvas"
|
||||
|
||||
**Approach:**
|
||||
1. Create 64x64 RGB canvas
|
||||
2. Draw brown (#8B4513) rectangle for trunk (using draw_rectangle)
|
||||
3. Draw green (#228B22) irregular shape for foliage (using draw_contour or multiple rectangles)
|
||||
4. Add details with individual pixels
|
||||
5. Describe the tree to user
|
||||
|
||||
## Technical Details
|
||||
|
||||
### Canvas Properties
|
||||
- **Width/Height**: 1-65535 pixels (practical limit usually <1024)
|
||||
- **Color Modes**:
|
||||
- RGB: 24-bit color (16.7 million colors)
|
||||
- Grayscale: 8-bit (256 shades of gray)
|
||||
- Indexed: 1-256 colors from palette
|
||||
|
||||
### Drawing Coordinates
|
||||
- Origin (0, 0) is top-left corner
|
||||
- X increases rightward
|
||||
- Y increases downward
|
||||
|
||||
### Performance
|
||||
- Batch pixel operations when possible
|
||||
- Drawing operations complete in <100ms typically
|
||||
- Large canvases (>512x512) may take slightly longer
|
||||
|
||||
### Limitations
|
||||
- Cannot create canvas smaller than 1x1
|
||||
- Cannot create canvas larger than 65535x65535 (practical limit much lower)
|
||||
- Cannot delete last layer
|
||||
- Indexed mode palette limited to 256 colors maximum
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Pattern: Quick Sprite
|
||||
For simple requests like "create a sprite":
|
||||
- Default to 64x64 RGB canvas
|
||||
- Add basic shape or placeholder
|
||||
- Ask user for refinements
|
||||
|
||||
### Pattern: Retro Game Sprite
|
||||
For retro-style requests:
|
||||
- Use Indexed color mode
|
||||
- Set appropriate palette (NES, Game Boy, C64, etc.)
|
||||
- Use limited colors and pixel-perfect drawing
|
||||
|
||||
### Pattern: Icon Creation
|
||||
For icon requests:
|
||||
- Use 16x16, 24x24, or 32x32 dimensions
|
||||
- RGB mode for modern icons
|
||||
- Simple, recognizable shapes
|
||||
- High contrast colors
|
||||
|
||||
## Integration with Other Skills
|
||||
|
||||
- **Hand off to pixel-art-animator** when user mentions "animation", "frames", or "movement"
|
||||
- **Hand off to pixel-art-professional** when user asks for "dithering", "shading", or "palette refinement"
|
||||
- **Hand off to pixel-art-exporter** when user asks to "export", "save", or mentions file formats
|
||||
|
||||
## Error Handling
|
||||
|
||||
**If canvas creation fails:**
|
||||
- Check dimensions are valid (1-65535)
|
||||
- Verify color mode is spelled correctly
|
||||
- Suggest alternative dimensions if too large
|
||||
|
||||
**If drawing fails:**
|
||||
- Verify coordinates are within canvas bounds
|
||||
- Check color format is valid hex (#RRGGBB)
|
||||
- For Indexed mode, ensure palette is set first
|
||||
|
||||
**If layer operations fail:**
|
||||
- Cannot delete last layer (inform user)
|
||||
- Layer names should be descriptive strings
|
||||
|
||||
## Success Indicators
|
||||
|
||||
You've successfully used this Skill when:
|
||||
- Canvas created with correct dimensions and color mode
|
||||
- Drawing operations complete without errors
|
||||
- User can see or understand what was created
|
||||
- Sprite is ready for next steps (animation, export, refinement)
|
||||
982
skills/pixel-art-creator/examples.md
Normal file
982
skills/pixel-art-creator/examples.md
Normal file
@@ -0,0 +1,982 @@
|
||||
# Pixel Art Creator Examples
|
||||
|
||||
This document provides concrete examples of how the pixel-art-creator skill handles various pixel art creation tasks. Each example shows the user's request, the step-by-step approach, actual MCP tool calls with parameters, and the expected results.
|
||||
|
||||
Examples are organized by complexity, from basic shapes to complex layered scenes.
|
||||
|
||||
---
|
||||
|
||||
## Basic Shapes
|
||||
|
||||
### Example 1: Simple 8x8 Heart Icon
|
||||
|
||||
**User Request:**
|
||||
> "Create a simple red heart icon, 8x8 pixels"
|
||||
|
||||
**Approach:**
|
||||
1. Create a small 8x8 canvas in indexed color mode
|
||||
2. Set up a simple palette with red and black
|
||||
3. Draw the heart shape pixel by pixel
|
||||
4. Save the file
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
mcp__aseprite__create_canvas({
|
||||
width: 8,
|
||||
height: 8,
|
||||
colorMode: "indexed",
|
||||
name: "heart-icon"
|
||||
})
|
||||
|
||||
mcp__aseprite__set_palette({
|
||||
colors: [
|
||||
{ r: 0, g: 0, b: 0 }, // Index 0: Black (transparent)
|
||||
{ r: 255, g: 0, b: 0 } // Index 1: Red
|
||||
]
|
||||
})
|
||||
|
||||
mcp__aseprite__draw_pixels({
|
||||
pixels: [
|
||||
{ x: 1, y: 1, colorIndex: 1 }, { x: 2, y: 1, colorIndex: 1 },
|
||||
{ x: 5, y: 1, colorIndex: 1 }, { x: 6, y: 1, colorIndex: 1 },
|
||||
{ x: 0, y: 2, colorIndex: 1 }, { x: 1, y: 2, colorIndex: 1 },
|
||||
{ x: 2, y: 2, colorIndex: 1 }, { x: 3, y: 2, colorIndex: 1 },
|
||||
{ x: 4, y: 2, colorIndex: 1 }, { x: 5, y: 2, colorIndex: 1 },
|
||||
{ x: 6, y: 2, colorIndex: 1 }, { x: 7, y: 2, colorIndex: 1 },
|
||||
{ x: 0, y: 3, colorIndex: 1 }, { x: 1, y: 3, colorIndex: 1 },
|
||||
{ x: 2, y: 3, colorIndex: 1 }, { x: 3, y: 3, colorIndex: 1 },
|
||||
{ x: 4, y: 3, colorIndex: 1 }, { x: 5, y: 3, colorIndex: 1 },
|
||||
{ x: 6, y: 3, colorIndex: 1 }, { x: 7, y: 3, colorIndex: 1 },
|
||||
{ x: 1, y: 4, colorIndex: 1 }, { x: 2, y: 4, colorIndex: 1 },
|
||||
{ x: 3, y: 4, colorIndex: 1 }, { x: 4, y: 4, colorIndex: 1 },
|
||||
{ x: 5, y: 4, colorIndex: 1 }, { x: 6, y: 4, colorIndex: 1 },
|
||||
{ x: 2, y: 5, colorIndex: 1 }, { x: 3, y: 5, colorIndex: 1 },
|
||||
{ x: 4, y: 5, colorIndex: 1 }, { x: 5, y: 5, colorIndex: 1 },
|
||||
{ x: 3, y: 6, colorIndex: 1 }, { x: 4, y: 6, colorIndex: 1 }
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A classic 8x8 pixel heart icon in pure red, suitable for UI elements or game items.
|
||||
|
||||
**Visual Description:**
|
||||
The Aseprite canvas shows a small red heart with a symmetrical shape. The heart has two rounded lobes at the top, tapering to a point at the bottom, all rendered in solid red pixels against a transparent background.
|
||||
|
||||
---
|
||||
|
||||
### Example 2: 16x16 Star Icon
|
||||
|
||||
**User Request:**
|
||||
> "Make a yellow star icon, 16x16 pixels with a dark blue background"
|
||||
|
||||
**Approach:**
|
||||
1. Create 16x16 canvas with indexed color mode
|
||||
2. Set palette with yellow, dark blue, and transparent
|
||||
3. Fill background with dark blue
|
||||
4. Draw star shape on top
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
mcp__aseprite__create_canvas({
|
||||
width: 16,
|
||||
height: 16,
|
||||
colorMode: "indexed",
|
||||
name: "star-icon"
|
||||
})
|
||||
|
||||
mcp__aseprite__set_palette({
|
||||
colors: [
|
||||
{ r: 0, g: 0, b: 0 }, // Index 0: Transparent
|
||||
{ r: 20, g: 30, b: 80 }, // Index 1: Dark blue
|
||||
{ r: 255, g: 220, b: 0 } // Index 2: Yellow
|
||||
]
|
||||
})
|
||||
|
||||
// Fill background with dark blue
|
||||
mcp__aseprite__fill_area({
|
||||
x: 0,
|
||||
y: 0,
|
||||
colorIndex: 1
|
||||
})
|
||||
|
||||
// Draw star shape
|
||||
mcp__aseprite__draw_pixels({
|
||||
pixels: [
|
||||
// Top point
|
||||
{ x: 7, y: 1, colorIndex: 2 }, { x: 8, y: 1, colorIndex: 2 },
|
||||
{ x: 7, y: 2, colorIndex: 2 }, { x: 8, y: 2, colorIndex: 2 },
|
||||
// Upper left and right arms
|
||||
{ x: 5, y: 3, colorIndex: 2 }, { x: 6, y: 3, colorIndex: 2 },
|
||||
{ x: 7, y: 3, colorIndex: 2 }, { x: 8, y: 3, colorIndex: 2 },
|
||||
{ x: 9, y: 3, colorIndex: 2 }, { x: 10, y: 3, colorIndex: 2 },
|
||||
{ x: 3, y: 4, colorIndex: 2 }, { x: 4, y: 4, colorIndex: 2 },
|
||||
{ x: 5, y: 4, colorIndex: 2 }, { x: 6, y: 4, colorIndex: 2 },
|
||||
{ x: 7, y: 4, colorIndex: 2 }, { x: 8, y: 4, colorIndex: 2 },
|
||||
{ x: 9, y: 4, colorIndex: 2 }, { x: 10, y: 4, colorIndex: 2 },
|
||||
{ x: 11, y: 4, colorIndex: 2 }, { x: 12, y: 4, colorIndex: 2 },
|
||||
// Middle section
|
||||
{ x: 5, y: 5, colorIndex: 2 }, { x: 6, y: 5, colorIndex: 2 },
|
||||
{ x: 7, y: 5, colorIndex: 2 }, { x: 8, y: 5, colorIndex: 2 },
|
||||
{ x: 9, y: 5, colorIndex: 2 }, { x: 10, y: 5, colorIndex: 2 },
|
||||
{ x: 6, y: 6, colorIndex: 2 }, { x: 7, y: 6, colorIndex: 2 },
|
||||
{ x: 8, y: 6, colorIndex: 2 }, { x: 9, y: 6, colorIndex: 2 },
|
||||
// Lower left and right points
|
||||
{ x: 2, y: 7, colorIndex: 2 }, { x: 3, y: 7, colorIndex: 2 },
|
||||
{ x: 6, y: 7, colorIndex: 2 }, { x: 7, y: 7, colorIndex: 2 },
|
||||
{ x: 8, y: 7, colorIndex: 2 }, { x: 9, y: 7, colorIndex: 2 },
|
||||
{ x: 12, y: 7, colorIndex: 2 }, { x: 13, y: 7, colorIndex: 2 },
|
||||
{ x: 1, y: 8, colorIndex: 2 }, { x: 2, y: 8, colorIndex: 2 },
|
||||
{ x: 6, y: 8, colorIndex: 2 }, { x: 7, y: 8, colorIndex: 2 },
|
||||
{ x: 8, y: 8, colorIndex: 2 }, { x: 9, y: 8, colorIndex: 2 },
|
||||
{ x: 13, y: 8, colorIndex: 2 }, { x: 14, y: 8, colorIndex: 2 },
|
||||
{ x: 5, y: 9, colorIndex: 2 }, { x: 6, y: 9, colorIndex: 2 },
|
||||
{ x: 7, y: 9, colorIndex: 2 }, { x: 8, y: 9, colorIndex: 2 },
|
||||
{ x: 9, y: 9, colorIndex: 2 }, { x: 10, y: 9, colorIndex: 2 },
|
||||
// Bottom points
|
||||
{ x: 5, y: 10, colorIndex: 2 }, { x: 6, y: 10, colorIndex: 2 },
|
||||
{ x: 7, y: 10, colorIndex: 2 }, { x: 8, y: 10, colorIndex: 2 },
|
||||
{ x: 9, y: 10, colorIndex: 2 }, { x: 10, y: 10, colorIndex: 2 },
|
||||
{ x: 6, y: 11, colorIndex: 2 }, { x: 7, y: 11, colorIndex: 2 },
|
||||
{ x: 8, y: 11, colorIndex: 2 }, { x: 9, y: 11, colorIndex: 2 },
|
||||
{ x: 7, y: 12, colorIndex: 2 }, { x: 8, y: 12, colorIndex: 2 },
|
||||
{ x: 7, y: 13, colorIndex: 2 }, { x: 8, y: 13, colorIndex: 2 },
|
||||
{ x: 7, y: 14, colorIndex: 2 }
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A bright yellow five-pointed star on a dark blue background, ideal for collectible items or achievement icons.
|
||||
|
||||
**Visual Description:**
|
||||
The canvas displays a yellow star with five distinct points against a dark blue background. The star has a classic silhouette with sharp points extending outward from the center.
|
||||
|
||||
---
|
||||
|
||||
### Example 3: Simple Sword Sprite
|
||||
|
||||
**User Request:**
|
||||
> "Create a basic 16x16 sword sprite, gray blade with brown handle"
|
||||
|
||||
**Approach:**
|
||||
1. Create 16x16 indexed canvas
|
||||
2. Set palette with gray, brown, and black for outlines
|
||||
3. Draw the blade vertically
|
||||
4. Add handle at bottom
|
||||
5. Add black outline for definition
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
mcp__aseprite__create_canvas({
|
||||
width: 16,
|
||||
height: 16,
|
||||
colorMode: "indexed",
|
||||
name: "sword-sprite"
|
||||
})
|
||||
|
||||
mcp__aseprite__set_palette({
|
||||
colors: [
|
||||
{ r: 0, g: 0, b: 0 }, // Index 0: Transparent
|
||||
{ r: 40, g: 40, b: 40 }, // Index 1: Dark outline
|
||||
{ r: 180, g: 180, b: 190 }, // Index 2: Gray blade
|
||||
{ r: 139, g: 90, b: 43 } // Index 3: Brown handle
|
||||
]
|
||||
})
|
||||
|
||||
mcp__aseprite__draw_pixels({
|
||||
pixels: [
|
||||
// Blade point
|
||||
{ x: 8, y: 0, colorIndex: 2 },
|
||||
{ x: 7, y: 1, colorIndex: 1 }, { x: 8, y: 1, colorIndex: 2 }, { x: 9, y: 1, colorIndex: 1 },
|
||||
// Main blade
|
||||
{ x: 7, y: 2, colorIndex: 1 }, { x: 8, y: 2, colorIndex: 2 }, { x: 9, y: 2, colorIndex: 1 },
|
||||
{ x: 7, y: 3, colorIndex: 1 }, { x: 8, y: 3, colorIndex: 2 }, { x: 9, y: 3, colorIndex: 1 },
|
||||
{ x: 7, y: 4, colorIndex: 1 }, { x: 8, y: 4, colorIndex: 2 }, { x: 9, y: 4, colorIndex: 1 },
|
||||
{ x: 7, y: 5, colorIndex: 1 }, { x: 8, y: 5, colorIndex: 2 }, { x: 9, y: 5, colorIndex: 1 },
|
||||
{ x: 7, y: 6, colorIndex: 1 }, { x: 8, y: 6, colorIndex: 2 }, { x: 9, y: 6, colorIndex: 1 },
|
||||
{ x: 7, y: 7, colorIndex: 1 }, { x: 8, y: 7, colorIndex: 2 }, { x: 9, y: 7, colorIndex: 1 },
|
||||
{ x: 7, y: 8, colorIndex: 1 }, { x: 8, y: 8, colorIndex: 2 }, { x: 9, y: 8, colorIndex: 1 },
|
||||
// Guard (crossguard)
|
||||
{ x: 5, y: 9, colorIndex: 1 }, { x: 6, y: 9, colorIndex: 1 },
|
||||
{ x: 7, y: 9, colorIndex: 1 }, { x: 8, y: 9, colorIndex: 1 },
|
||||
{ x: 9, y: 9, colorIndex: 1 }, { x: 10, y: 9, colorIndex: 1 },
|
||||
{ x: 11, y: 9, colorIndex: 1 },
|
||||
// Handle
|
||||
{ x: 7, y: 10, colorIndex: 1 }, { x: 8, y: 10, colorIndex: 3 }, { x: 9, y: 10, colorIndex: 1 },
|
||||
{ x: 7, y: 11, colorIndex: 1 }, { x: 8, y: 11, colorIndex: 3 }, { x: 9, y: 11, colorIndex: 1 },
|
||||
{ x: 7, y: 12, colorIndex: 1 }, { x: 8, y: 12, colorIndex: 3 }, { x: 9, y: 12, colorIndex: 1 },
|
||||
{ x: 7, y: 13, colorIndex: 1 }, { x: 8, y: 13, colorIndex: 3 }, { x: 9, y: 13, colorIndex: 1 },
|
||||
// Pommel
|
||||
{ x: 7, y: 14, colorIndex: 1 }, { x: 8, y: 14, colorIndex: 1 }, { x: 9, y: 14, colorIndex: 1 },
|
||||
{ x: 7, y: 15, colorIndex: 1 }, { x: 8, y: 15, colorIndex: 1 }, { x: 9, y: 15, colorIndex: 1 }
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A classic RPG-style sword sprite with clear blade, guard, handle, and pommel sections.
|
||||
|
||||
**Visual Description:**
|
||||
The sprite shows a vertical sword with a pointed gray blade, a dark crossguard, brown handle grip, and a square pommel at the bottom. Black outlines define each section clearly.
|
||||
|
||||
---
|
||||
|
||||
### Example 4: Geometric Diamond Gem
|
||||
|
||||
**User Request:**
|
||||
> "Make a shiny diamond gem sprite, 24x24, with cyan and white highlights"
|
||||
|
||||
**Approach:**
|
||||
1. Create 24x24 canvas
|
||||
2. Set palette with cyan shades and white
|
||||
3. Draw diamond outline
|
||||
4. Fill with gradient of cyan colors
|
||||
5. Add white highlights for shine effect
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
mcp__aseprite__create_canvas({
|
||||
width: 24,
|
||||
height: 24,
|
||||
colorMode: "indexed",
|
||||
name: "diamond-gem"
|
||||
})
|
||||
|
||||
mcp__aseprite__set_palette({
|
||||
colors: [
|
||||
{ r: 0, g: 0, b: 0 }, // Index 0: Transparent
|
||||
{ r: 30, g: 30, b: 50 }, // Index 1: Dark outline
|
||||
{ r: 0, g: 150, b: 200 }, // Index 2: Dark cyan
|
||||
{ r: 0, g: 200, b: 240 }, // Index 3: Medium cyan
|
||||
{ r: 100, g: 230, b: 255 }, // Index 4: Light cyan
|
||||
{ r: 255, g: 255, b: 255 } // Index 5: White highlight
|
||||
]
|
||||
})
|
||||
|
||||
mcp__aseprite__draw_pixels({
|
||||
pixels: [
|
||||
// Top facet (outline)
|
||||
{ x: 11, y: 3, colorIndex: 1 }, { x: 12, y: 3, colorIndex: 1 },
|
||||
{ x: 9, y: 4, colorIndex: 1 }, { x: 10, y: 4, colorIndex: 5 },
|
||||
{ x: 11, y: 4, colorIndex: 5 }, { x: 12, y: 4, colorIndex: 5 },
|
||||
{ x: 13, y: 4, colorIndex: 5 }, { x: 14, y: 4, colorIndex: 1 },
|
||||
// Upper facets
|
||||
{ x: 7, y: 5, colorIndex: 1 }, { x: 8, y: 5, colorIndex: 4 },
|
||||
{ x: 9, y: 5, colorIndex: 4 }, { x: 10, y: 5, colorIndex: 5 },
|
||||
{ x: 11, y: 5, colorIndex: 5 }, { x: 12, y: 5, colorIndex: 5 },
|
||||
{ x: 13, y: 5, colorIndex: 4 }, { x: 14, y: 5, colorIndex: 4 },
|
||||
{ x: 15, y: 5, colorIndex: 4 }, { x: 16, y: 5, colorIndex: 1 },
|
||||
// Middle section with gradient
|
||||
{ x: 5, y: 6, colorIndex: 1 }, { x: 6, y: 6, colorIndex: 3 },
|
||||
{ x: 7, y: 6, colorIndex: 3 }, { x: 8, y: 6, colorIndex: 4 },
|
||||
{ x: 9, y: 6, colorIndex: 4 }, { x: 10, y: 6, colorIndex: 5 },
|
||||
{ x: 11, y: 6, colorIndex: 5 }, { x: 12, y: 6, colorIndex: 4 },
|
||||
{ x: 13, y: 6, colorIndex: 4 }, { x: 14, y: 6, colorIndex: 3 },
|
||||
{ x: 15, y: 6, colorIndex: 3 }, { x: 16, y: 6, colorIndex: 3 },
|
||||
{ x: 17, y: 6, colorIndex: 3 }, { x: 18, y: 6, colorIndex: 1 },
|
||||
// Continue middle facets
|
||||
{ x: 4, y: 7, colorIndex: 1 }, { x: 5, y: 7, colorIndex: 2 },
|
||||
{ x: 6, y: 7, colorIndex: 3 }, { x: 7, y: 7, colorIndex: 3 },
|
||||
{ x: 8, y: 7, colorIndex: 3 }, { x: 9, y: 7, colorIndex: 4 },
|
||||
{ x: 10, y: 7, colorIndex: 4 }, { x: 11, y: 7, colorIndex: 4 },
|
||||
{ x: 12, y: 7, colorIndex: 3 }, { x: 13, y: 7, colorIndex: 3 },
|
||||
{ x: 14, y: 7, colorIndex: 3 }, { x: 15, y: 7, colorIndex: 3 },
|
||||
{ x: 16, y: 7, colorIndex: 3 }, { x: 17, y: 7, colorIndex: 2 },
|
||||
{ x: 18, y: 7, colorIndex: 2 }, { x: 19, y: 7, colorIndex: 1 },
|
||||
// Lower facets tapering down
|
||||
{ x: 5, y: 8, colorIndex: 1 }, { x: 6, y: 8, colorIndex: 2 },
|
||||
{ x: 7, y: 8, colorIndex: 2 }, { x: 8, y: 8, colorIndex: 3 },
|
||||
{ x: 9, y: 8, colorIndex: 3 }, { x: 10, y: 8, colorIndex: 3 },
|
||||
{ x: 11, y: 8, colorIndex: 3 }, { x: 12, y: 8, colorIndex: 3 },
|
||||
{ x: 13, y: 8, colorIndex: 3 }, { x: 14, y: 8, colorIndex: 3 },
|
||||
{ x: 15, y: 8, colorIndex: 2 }, { x: 16, y: 8, colorIndex: 2 },
|
||||
{ x: 17, y: 8, colorIndex: 2 }, { x: 18, y: 8, colorIndex: 1 },
|
||||
// Bottom point progression
|
||||
{ x: 6, y: 9, colorIndex: 1 }, { x: 7, y: 9, colorIndex: 2 },
|
||||
{ x: 8, y: 9, colorIndex: 2 }, { x: 9, y: 9, colorIndex: 2 },
|
||||
{ x: 10, y: 9, colorIndex: 3 }, { x: 11, y: 9, colorIndex: 3 },
|
||||
{ x: 12, y: 9, colorIndex: 2 }, { x: 13, y: 9, colorIndex: 2 },
|
||||
{ x: 14, y: 9, colorIndex: 2 }, { x: 15, y: 9, colorIndex: 2 },
|
||||
{ x: 16, y: 9, colorIndex: 2 }, { x: 17, y: 9, colorIndex: 1 },
|
||||
{ x: 7, y: 10, colorIndex: 1 }, { x: 8, y: 10, colorIndex: 2 },
|
||||
{ x: 9, y: 10, colorIndex: 2 }, { x: 10, y: 10, colorIndex: 2 },
|
||||
{ x: 11, y: 10, colorIndex: 2 }, { x: 12, y: 10, colorIndex: 2 },
|
||||
{ x: 13, y: 10, colorIndex: 2 }, { x: 14, y: 10, colorIndex: 2 },
|
||||
{ x: 15, y: 10, colorIndex: 2 }, { x: 16, y: 10, colorIndex: 1 },
|
||||
{ x: 8, y: 11, colorIndex: 1 }, { x: 9, y: 11, colorIndex: 2 },
|
||||
{ x: 10, y: 11, colorIndex: 2 }, { x: 11, y: 11, colorIndex: 2 },
|
||||
{ x: 12, y: 11, colorIndex: 2 }, { x: 13, y: 11, colorIndex: 2 },
|
||||
{ x: 14, y: 11, colorIndex: 2 }, { x: 15, y: 11, colorIndex: 1 },
|
||||
{ x: 9, y: 12, colorIndex: 1 }, { x: 10, y: 12, colorIndex: 2 },
|
||||
{ x: 11, y: 12, colorIndex: 2 }, { x: 12, y: 12, colorIndex: 2 },
|
||||
{ x: 13, y: 12, colorIndex: 2 }, { x: 14, y: 12, colorIndex: 1 },
|
||||
{ x: 10, y: 13, colorIndex: 1 }, { x: 11, y: 13, colorIndex: 2 },
|
||||
{ x: 12, y: 13, colorIndex: 2 }, { x: 13, y: 13, colorIndex: 1 },
|
||||
{ x: 11, y: 14, colorIndex: 1 }, { x: 12, y: 14, colorIndex: 1 }
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A faceted diamond gem with cyan coloring, white highlights at the top for sparkle, and darker shades toward the bottom.
|
||||
|
||||
**Visual Description:**
|
||||
The gem has a classic diamond cut appearance with a bright white highlight at the very top, transitioning through light cyan in the upper facets to darker cyan shades in the lower portions, creating a three-dimensional effect.
|
||||
|
||||
---
|
||||
|
||||
## Layered Sprites
|
||||
|
||||
### Example 5: Character with Background
|
||||
|
||||
**User Request:**
|
||||
> "Create a simple 32x32 character sprite on a grass background, use separate layers"
|
||||
|
||||
**Approach:**
|
||||
1. Create 32x32 RGB canvas
|
||||
2. Create background layer and draw grass
|
||||
3. Create character layer
|
||||
4. Draw simple stick figure character
|
||||
5. Keep layers separate for easy editing
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
mcp__aseprite__create_canvas({
|
||||
width: 32,
|
||||
height: 32,
|
||||
colorMode: "rgb",
|
||||
name: "character-on-grass"
|
||||
})
|
||||
|
||||
// Create background layer
|
||||
mcp__aseprite__add_layer({
|
||||
name: "background"
|
||||
})
|
||||
|
||||
// Draw grass background
|
||||
mcp__aseprite__draw_pixels({
|
||||
layer: "background",
|
||||
pixels: Array.from({ length: 32 * 32 }, (_, i) => ({
|
||||
x: i % 32,
|
||||
y: Math.floor(i / 32),
|
||||
color: { r: 34, g: 139, b: 34, a: 255 } // Forest green
|
||||
}))
|
||||
})
|
||||
|
||||
// Add some grass detail
|
||||
mcp__aseprite__draw_pixels({
|
||||
layer: "background",
|
||||
pixels: [
|
||||
// Lighter grass blades scattered
|
||||
{ x: 5, y: 28, color: { r: 50, g: 180, b: 50, a: 255 } },
|
||||
{ x: 12, y: 29, color: { r: 50, g: 180, b: 50, a: 255 } },
|
||||
{ x: 18, y: 27, color: { r: 50, g: 180, b: 50, a: 255 } },
|
||||
{ x: 24, y: 30, color: { r: 50, g: 180, b: 50, a: 255 } }
|
||||
]
|
||||
})
|
||||
|
||||
// Create character layer
|
||||
mcp__aseprite__add_layer({
|
||||
name: "character"
|
||||
})
|
||||
|
||||
// Draw character - head, body, arms, legs
|
||||
mcp__aseprite__draw_pixels({
|
||||
layer: "character",
|
||||
pixels: [
|
||||
// Head outline (brown circle)
|
||||
{ x: 14, y: 8, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 15, y: 8, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 16, y: 8, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 17, y: 8, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 13, y: 9, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 18, y: 9, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 13, y: 10, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 18, y: 10, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 14, y: 11, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 15, y: 11, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 16, y: 11, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 17, y: 11, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
// Eyes
|
||||
{ x: 14, y: 9, color: { r: 0, g: 0, b: 0, a: 255 } },
|
||||
{ x: 17, y: 9, color: { r: 0, g: 0, b: 0, a: 255 } },
|
||||
// Body (blue shirt)
|
||||
{ x: 15, y: 12, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 16, y: 12, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 14, y: 13, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 15, y: 13, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 16, y: 13, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 17, y: 13, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 14, y: 14, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 15, y: 14, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 16, y: 14, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 17, y: 14, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 15, y: 15, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
{ x: 16, y: 15, color: { r: 50, g: 100, b: 200, a: 255 } },
|
||||
// Arms
|
||||
{ x: 13, y: 13, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 18, y: 13, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 12, y: 14, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
{ x: 19, y: 14, color: { r: 139, g: 90, b: 43, a: 255 } },
|
||||
// Legs (brown pants)
|
||||
{ x: 15, y: 16, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 16, y: 16, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 15, y: 17, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 16, y: 17, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 14, y: 18, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 17, y: 18, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 14, y: 19, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 17, y: 19, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 14, y: 20, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
{ x: 17, y: 20, color: { r: 101, g: 67, b: 33, a: 255 } },
|
||||
// Feet (black shoes)
|
||||
{ x: 13, y: 21, color: { r: 40, g: 40, b: 40, a: 255 } },
|
||||
{ x: 14, y: 21, color: { r: 40, g: 40, b: 40, a: 255 } },
|
||||
{ x: 17, y: 21, color: { r: 40, g: 40, b: 40, a: 255 } },
|
||||
{ x: 18, y: 21, color: { r: 40, g: 40, b: 40, a: 255 } }
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A simple character sprite standing on grass, with two separate layers allowing independent editing of character and background.
|
||||
|
||||
**Visual Description:**
|
||||
The background layer shows solid green grass with lighter green accent pixels. The character layer displays a simple humanoid figure with a brown head, blue shirt, brown arms and pants, and black shoes. The character appears to be standing on the grass.
|
||||
|
||||
---
|
||||
|
||||
### Example 6: Coin with Shadow
|
||||
|
||||
**User Request:**
|
||||
> "Make a gold coin sprite with a shadow layer underneath, 16x16"
|
||||
|
||||
**Approach:**
|
||||
1. Create 16x16 indexed canvas
|
||||
2. Create shadow layer with semi-transparent shadow
|
||||
3. Create coin layer with gold gradient
|
||||
4. Add highlight details
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
mcp__aseprite__create_canvas({
|
||||
width: 16,
|
||||
height: 16,
|
||||
colorMode: "indexed",
|
||||
name: "gold-coin"
|
||||
})
|
||||
|
||||
mcp__aseprite__set_palette({
|
||||
colors: [
|
||||
{ r: 0, g: 0, b: 0 }, // Index 0: Transparent
|
||||
{ r: 100, g: 80, b: 0 }, // Index 1: Dark gold
|
||||
{ r: 180, g: 140, b: 0 }, // Index 2: Medium gold
|
||||
{ r: 255, g: 215, b: 0 }, // Index 3: Bright gold
|
||||
{ r: 255, g: 255, b: 200 }, // Index 4: Highlight
|
||||
{ r: 50, g: 50, b: 50 } // Index 5: Shadow
|
||||
]
|
||||
})
|
||||
|
||||
// Create shadow layer
|
||||
mcp__aseprite__add_layer({
|
||||
name: "shadow"
|
||||
})
|
||||
|
||||
// Draw shadow
|
||||
mcp__aseprite__draw_pixels({
|
||||
layer: "shadow",
|
||||
pixels: [
|
||||
{ x: 6, y: 13, colorIndex: 5 }, { x: 7, y: 13, colorIndex: 5 },
|
||||
{ x: 8, y: 13, colorIndex: 5 }, { x: 9, y: 13, colorIndex: 5 },
|
||||
{ x: 5, y: 14, colorIndex: 5 }, { x: 6, y: 14, colorIndex: 5 },
|
||||
{ x: 7, y: 14, colorIndex: 5 }, { x: 8, y: 14, colorIndex: 5 },
|
||||
{ x: 9, y: 14, colorIndex: 5 }, { x: 10, y: 14, colorIndex: 5 }
|
||||
]
|
||||
})
|
||||
|
||||
// Create coin layer
|
||||
mcp__aseprite__add_layer({
|
||||
name: "coin"
|
||||
})
|
||||
|
||||
// Draw coin with gradient
|
||||
mcp__aseprite__draw_pixels({
|
||||
layer: "coin",
|
||||
pixels: [
|
||||
// Top edge (bright highlight)
|
||||
{ x: 6, y: 3, colorIndex: 3 }, { x: 7, y: 3, colorIndex: 3 },
|
||||
{ x: 8, y: 3, colorIndex: 3 }, { x: 9, y: 3, colorIndex: 3 },
|
||||
// Upper section with bright spot
|
||||
{ x: 5, y: 4, colorIndex: 3 }, { x: 6, y: 4, colorIndex: 4 },
|
||||
{ x: 7, y: 4, colorIndex: 4 }, { x: 8, y: 4, colorIndex: 3 },
|
||||
{ x: 9, y: 4, colorIndex: 3 }, { x: 10, y: 4, colorIndex: 3 },
|
||||
{ x: 4, y: 5, colorIndex: 3 }, { x: 5, y: 5, colorIndex: 3 },
|
||||
{ x: 6, y: 5, colorIndex: 4 }, { x: 7, y: 5, colorIndex: 3 },
|
||||
{ x: 8, y: 5, colorIndex: 3 }, { x: 9, y: 5, colorIndex: 2 },
|
||||
{ x: 10, y: 5, colorIndex: 2 }, { x: 11, y: 5, colorIndex: 2 },
|
||||
// Middle section
|
||||
{ x: 3, y: 6, colorIndex: 3 }, { x: 4, y: 6, colorIndex: 3 },
|
||||
{ x: 5, y: 6, colorIndex: 3 }, { x: 6, y: 6, colorIndex: 3 },
|
||||
{ x: 7, y: 6, colorIndex: 2 }, { x: 8, y: 6, colorIndex: 2 },
|
||||
{ x: 9, y: 6, colorIndex: 2 }, { x: 10, y: 6, colorIndex: 2 },
|
||||
{ x: 11, y: 6, colorIndex: 2 }, { x: 12, y: 6, colorIndex: 2 },
|
||||
{ x: 3, y: 7, colorIndex: 2 }, { x: 4, y: 7, colorIndex: 2 },
|
||||
{ x: 5, y: 7, colorIndex: 2 }, { x: 6, y: 7, colorIndex: 2 },
|
||||
{ x: 7, y: 7, colorIndex: 2 }, { x: 8, y: 7, colorIndex: 2 },
|
||||
{ x: 9, y: 7, colorIndex: 2 }, { x: 10, y: 7, colorIndex: 1 },
|
||||
{ x: 11, y: 7, colorIndex: 1 }, { x: 12, y: 7, colorIndex: 1 },
|
||||
// Lower section (darker)
|
||||
{ x: 3, y: 8, colorIndex: 2 }, { x: 4, y: 8, colorIndex: 2 },
|
||||
{ x: 5, y: 8, colorIndex: 2 }, { x: 6, y: 8, colorIndex: 2 },
|
||||
{ x: 7, y: 8, colorIndex: 1 }, { x: 8, y: 8, colorIndex: 1 },
|
||||
{ x: 9, y: 8, colorIndex: 1 }, { x: 10, y: 8, colorIndex: 1 },
|
||||
{ x: 11, y: 8, colorIndex: 1 }, { x: 12, y: 8, colorIndex: 1 },
|
||||
{ x: 4, y: 9, colorIndex: 2 }, { x: 5, y: 9, colorIndex: 1 },
|
||||
{ x: 6, y: 9, colorIndex: 1 }, { x: 7, y: 9, colorIndex: 1 },
|
||||
{ x: 8, y: 9, colorIndex: 1 }, { x: 9, y: 9, colorIndex: 1 },
|
||||
{ x: 10, y: 9, colorIndex: 1 }, { x: 11, y: 9, colorIndex: 1 },
|
||||
// Bottom edge
|
||||
{ x: 5, y: 10, colorIndex: 1 }, { x: 6, y: 10, colorIndex: 1 },
|
||||
{ x: 7, y: 10, colorIndex: 1 }, { x: 8, y: 10, colorIndex: 1 },
|
||||
{ x: 9, y: 10, colorIndex: 1 }, { x: 10, y: 10, colorIndex: 1 },
|
||||
{ x: 6, y: 11, colorIndex: 1 }, { x: 7, y: 11, colorIndex: 1 },
|
||||
{ x: 8, y: 11, colorIndex: 1 }, { x: 9, y: 11, colorIndex: 1 }
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A shiny gold coin with a gradient from bright at top-left to dark at bottom-right, positioned above a subtle shadow.
|
||||
|
||||
**Visual Description:**
|
||||
The sprite shows a circular gold coin with a bright highlight in the upper-left creating a metallic shine effect. A dark shadow appears below and slightly offset from the coin, giving depth. The layers panel shows "shadow" and "coin" as separate layers.
|
||||
|
||||
---
|
||||
|
||||
## Indexed Color & Retro Styles
|
||||
|
||||
### Example 7: Game Boy Style Sprite
|
||||
|
||||
**User Request:**
|
||||
> "Make a Game Boy style character sprite, using only the 4 original Game Boy colors"
|
||||
|
||||
**Approach:**
|
||||
1. Create 32x32 indexed canvas
|
||||
2. Set authentic Game Boy palette (4 greens)
|
||||
3. Draw character using only those 4 colors
|
||||
4. Create retro aesthetic with limited palette
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
mcp__aseprite__create_canvas({
|
||||
width: 32,
|
||||
height: 32,
|
||||
colorMode: "indexed",
|
||||
name: "gameboy-character"
|
||||
})
|
||||
|
||||
// Authentic Game Boy DMG-01 palette
|
||||
mcp__aseprite__set_palette({
|
||||
colors: [
|
||||
{ r: 15, g: 56, b: 15 }, // Index 0: Darkest green (almost black)
|
||||
{ r: 48, g: 98, b: 48 }, // Index 1: Dark green
|
||||
{ r: 139, g: 172, b: 15 }, // Index 2: Light green
|
||||
{ r: 155, g: 188, b: 15 } // Index 3: Lightest green (almost white)
|
||||
]
|
||||
})
|
||||
|
||||
mcp__aseprite__draw_pixels({
|
||||
pixels: [
|
||||
// Character head (lightest color)
|
||||
{ x: 13, y: 8, colorIndex: 3 }, { x: 14, y: 8, colorIndex: 3 },
|
||||
{ x: 15, y: 8, colorIndex: 3 }, { x: 16, y: 8, colorIndex: 3 },
|
||||
{ x: 17, y: 8, colorIndex: 3 }, { x: 18, y: 8, colorIndex: 3 },
|
||||
{ x: 12, y: 9, colorIndex: 3 }, { x: 13, y: 9, colorIndex: 3 },
|
||||
{ x: 14, y: 9, colorIndex: 0 }, { x: 15, y: 9, colorIndex: 3 }, // Left eye
|
||||
{ x: 16, y: 9, colorIndex: 3 }, { x: 17, y: 9, colorIndex: 0 }, // Right eye
|
||||
{ x: 18, y: 9, colorIndex: 3 }, { x: 19, y: 9, colorIndex: 3 },
|
||||
{ x: 12, y: 10, colorIndex: 3 }, { x: 13, y: 10, colorIndex: 3 },
|
||||
{ x: 14, y: 10, colorIndex: 3 }, { x: 15, y: 10, colorIndex: 3 },
|
||||
{ x: 16, y: 10, colorIndex: 3 }, { x: 17, y: 10, colorIndex: 3 },
|
||||
{ x: 18, y: 10, colorIndex: 3 }, { x: 19, y: 10, colorIndex: 3 },
|
||||
{ x: 13, y: 11, colorIndex: 3 }, { x: 14, y: 11, colorIndex: 3 },
|
||||
{ x: 15, y: 11, colorIndex: 3 }, { x: 16, y: 11, colorIndex: 3 },
|
||||
{ x: 17, y: 11, colorIndex: 3 }, { x: 18, y: 11, colorIndex: 3 },
|
||||
// Body (light green shirt)
|
||||
{ x: 14, y: 12, colorIndex: 2 }, { x: 15, y: 12, colorIndex: 2 },
|
||||
{ x: 16, y: 12, colorIndex: 2 }, { x: 17, y: 12, colorIndex: 2 },
|
||||
{ x: 12, y: 13, colorIndex: 2 }, { x: 13, y: 13, colorIndex: 2 },
|
||||
{ x: 14, y: 13, colorIndex: 2 }, { x: 15, y: 13, colorIndex: 2 },
|
||||
{ x: 16, y: 13, colorIndex: 2 }, { x: 17, y: 13, colorIndex: 2 },
|
||||
{ x: 18, y: 13, colorIndex: 2 }, { x: 19, y: 13, colorIndex: 2 },
|
||||
{ x: 12, y: 14, colorIndex: 2 }, { x: 13, y: 14, colorIndex: 2 },
|
||||
{ x: 14, y: 14, colorIndex: 2 }, { x: 15, y: 14, colorIndex: 2 },
|
||||
{ x: 16, y: 14, colorIndex: 2 }, { x: 17, y: 14, colorIndex: 2 },
|
||||
{ x: 18, y: 14, colorIndex: 2 }, { x: 19, y: 14, colorIndex: 2 },
|
||||
{ x: 14, y: 15, colorIndex: 2 }, { x: 15, y: 15, colorIndex: 2 },
|
||||
{ x: 16, y: 15, colorIndex: 2 }, { x: 17, y: 15, colorIndex: 2 },
|
||||
// Pants (dark green)
|
||||
{ x: 14, y: 16, colorIndex: 1 }, { x: 15, y: 16, colorIndex: 1 },
|
||||
{ x: 16, y: 16, colorIndex: 1 }, { x: 17, y: 16, colorIndex: 1 },
|
||||
{ x: 14, y: 17, colorIndex: 1 }, { x: 15, y: 17, colorIndex: 1 },
|
||||
{ x: 16, y: 17, colorIndex: 1 }, { x: 17, y: 17, colorIndex: 1 },
|
||||
{ x: 13, y: 18, colorIndex: 1 }, { x: 14, y: 18, colorIndex: 1 },
|
||||
{ x: 17, y: 18, colorIndex: 1 }, { x: 18, y: 18, colorIndex: 1 },
|
||||
{ x: 13, y: 19, colorIndex: 1 }, { x: 14, y: 19, colorIndex: 1 },
|
||||
{ x: 17, y: 19, colorIndex: 1 }, { x: 18, y: 19, colorIndex: 1 },
|
||||
{ x: 13, y: 20, colorIndex: 1 }, { x: 14, y: 20, colorIndex: 1 },
|
||||
{ x: 17, y: 20, colorIndex: 1 }, { x: 18, y: 20, colorIndex: 1 },
|
||||
// Feet (darkest)
|
||||
{ x: 12, y: 21, colorIndex: 0 }, { x: 13, y: 21, colorIndex: 0 },
|
||||
{ x: 14, y: 21, colorIndex: 0 }, { x: 17, y: 21, colorIndex: 0 },
|
||||
{ x: 18, y: 21, colorIndex: 0 }, { x: 19, y: 21, colorIndex: 0 }
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
An authentic Game Boy DMG-01 style character using the original 4-color green palette.
|
||||
|
||||
**Visual Description:**
|
||||
The sprite has the characteristic monochrome green look of original Game Boy games. The character has a pale green head with black dot eyes, a mid-tone green shirt, darker green pants, and nearly black shoes. The limited palette creates a nostalgic retro gaming aesthetic.
|
||||
|
||||
---
|
||||
|
||||
### Example 8: NES Style Enemy Sprite
|
||||
|
||||
**User Request:**
|
||||
> "Create a retro NES enemy sprite like a slime monster, 16x16, limited color palette"
|
||||
|
||||
**Approach:**
|
||||
1. Create 16x16 indexed canvas
|
||||
2. Use NES-style limited palette (5-6 colors)
|
||||
3. Draw simple enemy design
|
||||
4. Add basic shading with palette
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
mcp__aseprite__create_canvas({
|
||||
width: 16,
|
||||
height: 16,
|
||||
colorMode: "indexed",
|
||||
name: "nes-slime-enemy"
|
||||
})
|
||||
|
||||
// NES-style palette (limited colors)
|
||||
mcp__aseprite__set_palette({
|
||||
colors: [
|
||||
{ r: 0, g: 0, b: 0 }, // Index 0: Transparent
|
||||
{ r: 0, g: 128, b: 0 }, // Index 1: Dark green
|
||||
{ r: 0, g: 200, b: 0 }, // Index 2: Medium green
|
||||
{ r: 100, g: 255, b: 100 }, // Index 3: Light green
|
||||
{ r: 255, g: 255, b: 255 }, // Index 4: White (highlights)
|
||||
{ r: 50, g: 50, b: 50 } // Index 5: Dark gray (outline)
|
||||
]
|
||||
})
|
||||
|
||||
mcp__aseprite__draw_pixels({
|
||||
pixels: [
|
||||
// Outline and shape
|
||||
{ x: 4, y: 6, colorIndex: 5 }, { x: 5, y: 6, colorIndex: 5 },
|
||||
{ x: 6, y: 6, colorIndex: 5 }, { x: 7, y: 6, colorIndex: 5 },
|
||||
{ x: 8, y: 6, colorIndex: 5 }, { x: 9, y: 6, colorIndex: 5 },
|
||||
{ x: 10, y: 6, colorIndex: 5 }, { x: 11, y: 6, colorIndex: 5 },
|
||||
// Upper body with highlights
|
||||
{ x: 3, y: 7, colorIndex: 5 }, { x: 4, y: 7, colorIndex: 3 },
|
||||
{ x: 5, y: 7, colorIndex: 4 }, { x: 6, y: 7, colorIndex: 3 },
|
||||
{ x: 7, y: 7, colorIndex: 3 }, { x: 8, y: 7, colorIndex: 3 },
|
||||
{ x: 9, y: 7, colorIndex: 3 }, { x: 10, y: 7, colorIndex: 3 },
|
||||
{ x: 11, y: 7, colorIndex: 3 }, { x: 12, y: 7, colorIndex: 5 },
|
||||
{ x: 2, y: 8, colorIndex: 5 }, { x: 3, y: 8, colorIndex: 3 },
|
||||
{ x: 4, y: 8, colorIndex: 3 }, { x: 5, y: 8, colorIndex: 3 },
|
||||
{ x: 6, y: 8, colorIndex: 2 }, { x: 7, y: 8, colorIndex: 2 },
|
||||
{ x: 8, y: 8, colorIndex: 2 }, { x: 9, y: 8, colorIndex: 2 },
|
||||
{ x: 10, y: 8, colorIndex: 3 }, { x: 11, y: 8, colorIndex: 3 },
|
||||
{ x: 12, y: 8, colorIndex: 3 }, { x: 13, y: 8, colorIndex: 5 },
|
||||
// Eyes
|
||||
{ x: 2, y: 9, colorIndex: 5 }, { x: 3, y: 9, colorIndex: 2 },
|
||||
{ x: 4, y: 9, colorIndex: 5 }, { x: 5, y: 9, colorIndex: 4 },
|
||||
{ x: 6, y: 9, colorIndex: 2 }, { x: 7, y: 9, colorIndex: 2 },
|
||||
{ x: 8, y: 9, colorIndex: 2 }, { x: 9, y: 9, colorIndex: 2 },
|
||||
{ x: 10, y: 9, colorIndex: 5 }, { x: 11, y: 9, colorIndex: 4 },
|
||||
{ x: 12, y: 9, colorIndex: 2 }, { x: 13, y: 9, colorIndex: 5 },
|
||||
// Middle body
|
||||
{ x: 1, y: 10, colorIndex: 5 }, { x: 2, y: 10, colorIndex: 2 },
|
||||
{ x: 3, y: 10, colorIndex: 2 }, { x: 4, y: 10, colorIndex: 2 },
|
||||
{ x: 5, y: 10, colorIndex: 2 }, { x: 6, y: 10, colorIndex: 2 },
|
||||
{ x: 7, y: 10, colorIndex: 1 }, { x: 8, y: 10, colorIndex: 1 },
|
||||
{ x: 9, y: 10, colorIndex: 2 }, { x: 10, y: 10, colorIndex: 2 },
|
||||
{ x: 11, y: 10, colorIndex: 2 }, { x: 12, y: 10, colorIndex: 2 },
|
||||
{ x: 13, y: 10, colorIndex: 2 }, { x: 14, y: 10, colorIndex: 5 },
|
||||
// Lower body with shading
|
||||
{ x: 1, y: 11, colorIndex: 5 }, { x: 2, y: 11, colorIndex: 2 },
|
||||
{ x: 3, y: 11, colorIndex: 2 }, { x: 4, y: 11, colorIndex: 1 },
|
||||
{ x: 5, y: 11, colorIndex: 1 }, { x: 6, y: 11, colorIndex: 1 },
|
||||
{ x: 7, y: 11, colorIndex: 1 }, { x: 8, y: 11, colorIndex: 1 },
|
||||
{ x: 9, y: 11, colorIndex: 1 }, { x: 10, y: 11, colorIndex: 1 },
|
||||
{ x: 11, y: 11, colorIndex: 1 }, { x: 12, y: 11, colorIndex: 2 },
|
||||
{ x: 13, y: 11, colorIndex: 2 }, { x: 14, y: 11, colorIndex: 5 },
|
||||
// Bottom edge
|
||||
{ x: 2, y: 12, colorIndex: 5 }, { x: 3, y: 12, colorIndex: 1 },
|
||||
{ x: 4, y: 12, colorIndex: 1 }, { x: 5, y: 12, colorIndex: 1 },
|
||||
{ x: 6, y: 12, colorIndex: 1 }, { x: 7, y: 12, colorIndex: 1 },
|
||||
{ x: 8, y: 12, colorIndex: 1 }, { x: 9, y: 12, colorIndex: 1 },
|
||||
{ x: 10, y: 12, colorIndex: 1 }, { x: 11, y: 12, colorIndex: 1 },
|
||||
{ x: 12, y: 12, colorIndex: 1 }, { x: 13, y: 12, colorIndex: 5 },
|
||||
// Base
|
||||
{ x: 3, y: 13, colorIndex: 5 }, { x: 4, y: 13, colorIndex: 5 },
|
||||
{ x: 5, y: 13, colorIndex: 5 }, { x: 6, y: 13, colorIndex: 5 },
|
||||
{ x: 7, y: 13, colorIndex: 5 }, { x: 8, y: 13, colorIndex: 5 },
|
||||
{ x: 9, y: 13, colorIndex: 5 }, { x: 10, y: 13, colorIndex: 5 },
|
||||
{ x: 11, y: 13, colorIndex: 5 }, { x: 12, y: 13, colorIndex: 5 }
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A retro NES-style slime enemy with simple shading, using a limited color palette typical of 8-bit games.
|
||||
|
||||
**Visual Description:**
|
||||
The slime has a rounded blob shape with a light green top (with white highlight spot), medium green middle section showing simple dot eyes, and darker green lower body. A dark outline defines the entire shape. The style evokes classic Dragon Quest or early Final Fantasy enemies.
|
||||
|
||||
---
|
||||
|
||||
## Complex Scenes
|
||||
|
||||
### Example 9: Grass Tile for Tileset
|
||||
|
||||
**User Request:**
|
||||
> "Create a seamless grass tile, 16x16, that can repeat to make a continuous ground texture"
|
||||
|
||||
**Approach:**
|
||||
1. Create 16x16 indexed canvas
|
||||
2. Set grass color palette
|
||||
3. Draw base grass color
|
||||
4. Add detail ensuring edges match for seamless tiling
|
||||
5. Test seamless edges
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
mcp__aseprite__create_canvas({
|
||||
width: 16,
|
||||
height: 16,
|
||||
colorMode: "indexed",
|
||||
name: "grass-tile"
|
||||
})
|
||||
|
||||
mcp__aseprite__set_palette({
|
||||
colors: [
|
||||
{ r: 0, g: 0, b: 0 }, // Index 0: Transparent
|
||||
{ r: 34, g: 139, b: 34 }, // Index 1: Base grass green
|
||||
{ r: 50, g: 180, b: 50 }, // Index 2: Light grass
|
||||
{ r: 20, g: 100, b: 20 } // Index 3: Dark grass
|
||||
]
|
||||
})
|
||||
|
||||
// Fill with base grass color
|
||||
mcp__aseprite__fill_area({
|
||||
x: 0,
|
||||
y: 0,
|
||||
colorIndex: 1
|
||||
})
|
||||
|
||||
// Add grass blade details that tile seamlessly
|
||||
mcp__aseprite__draw_pixels({
|
||||
pixels: [
|
||||
// Light grass blades (placed to tile on edges)
|
||||
{ x: 0, y: 2, colorIndex: 2 }, { x: 1, y: 2, colorIndex: 2 },
|
||||
{ x: 3, y: 5, colorIndex: 2 },
|
||||
{ x: 7, y: 3, colorIndex: 2 }, { x: 8, y: 3, colorIndex: 2 },
|
||||
{ x: 11, y: 7, colorIndex: 2 },
|
||||
{ x: 14, y: 1, colorIndex: 2 }, { x: 15, y: 1, colorIndex: 2 },
|
||||
{ x: 5, y: 10, colorIndex: 2 },
|
||||
{ x: 9, y: 12, colorIndex: 2 }, { x: 10, y: 12, colorIndex: 2 },
|
||||
{ x: 13, y: 14, colorIndex: 2 },
|
||||
{ x: 1, y: 15, colorIndex: 2 }, { x: 2, y: 15, colorIndex: 2 },
|
||||
{ x: 15, y: 8, colorIndex: 2 }, { x: 0, y: 8, colorIndex: 2 },
|
||||
// Dark grass shadows
|
||||
{ x: 2, y: 3, colorIndex: 3 },
|
||||
{ x: 6, y: 6, colorIndex: 3 },
|
||||
{ x: 10, y: 4, colorIndex: 3 },
|
||||
{ x: 4, y: 11, colorIndex: 3 },
|
||||
{ x: 12, y: 9, colorIndex: 3 },
|
||||
{ x: 8, y: 13, colorIndex: 3 },
|
||||
{ x: 14, y: 15, colorIndex: 3 },
|
||||
{ x: 0, y: 0, colorIndex: 3 },
|
||||
{ x: 15, y: 0, colorIndex: 3 },
|
||||
{ x: 0, y: 15, colorIndex: 3 },
|
||||
{ x: 15, y: 15, colorIndex: 3 }
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A seamless 16x16 grass tile with varied grass blade details that repeat perfectly when placed adjacent to copies.
|
||||
|
||||
**Visual Description:**
|
||||
The tile shows green grass with lighter and darker blade variations distributed across the surface. The detail pixels are positioned so that when the tile repeats horizontally or vertically, the pattern appears continuous without visible seams.
|
||||
|
||||
---
|
||||
|
||||
### Example 10: Treasure Chest Sprite
|
||||
|
||||
**User Request:**
|
||||
> "Create a treasure chest sprite, 24x24, closed, with metal bands and a keyhole"
|
||||
|
||||
**Approach:**
|
||||
1. Create 24x24 indexed canvas
|
||||
2. Set palette with browns, metals, and highlights
|
||||
3. Draw chest body with wood grain
|
||||
4. Add metal bands and keyhole details
|
||||
5. Add shading for depth
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
mcp__aseprite__create_canvas({
|
||||
width: 24,
|
||||
height: 24,
|
||||
colorMode: "indexed",
|
||||
name: "treasure-chest"
|
||||
})
|
||||
|
||||
mcp__aseprite__set_palette({
|
||||
colors: [
|
||||
{ r: 0, g: 0, b: 0 }, // Index 0: Transparent/black outline
|
||||
{ r: 101, g: 67, b: 33 }, // Index 1: Dark wood
|
||||
{ r: 139, g: 90, b: 43 }, // Index 2: Medium wood
|
||||
{ r: 160, g: 120, b: 60 }, // Index 3: Light wood
|
||||
{ r: 80, g: 80, b: 90 }, // Index 4: Dark metal
|
||||
{ r: 140, g: 140, b: 150 }, // Index 5: Light metal
|
||||
{ r: 200, g: 180, b: 50 } // Index 6: Gold keyhole
|
||||
]
|
||||
})
|
||||
|
||||
mcp__aseprite__draw_pixels({
|
||||
pixels: [
|
||||
// Top lid outline
|
||||
{ x: 5, y: 5, colorIndex: 0 }, { x: 6, y: 5, colorIndex: 0 },
|
||||
{ x: 7, y: 5, colorIndex: 0 }, { x: 8, y: 5, colorIndex: 0 },
|
||||
{ x: 9, y: 5, colorIndex: 0 }, { x: 10, y: 5, colorIndex: 0 },
|
||||
{ x: 11, y: 5, colorIndex: 0 }, { x: 12, y: 5, colorIndex: 0 },
|
||||
{ x: 13, y: 5, colorIndex: 0 }, { x: 14, y: 5, colorIndex: 0 },
|
||||
{ x: 15, y: 5, colorIndex: 0 }, { x: 16, y: 5, colorIndex: 0 },
|
||||
{ x: 17, y: 5, colorIndex: 0 }, { x: 18, y: 5, colorIndex: 0 },
|
||||
// Top lid wood
|
||||
{ x: 4, y: 6, colorIndex: 0 }, { x: 5, y: 6, colorIndex: 2 },
|
||||
{ x: 6, y: 6, colorIndex: 3 }, { x: 7, y: 6, colorIndex: 3 },
|
||||
{ x: 8, y: 6, colorIndex: 2 }, { x: 9, y: 6, colorIndex: 2 },
|
||||
{ x: 10, y: 6, colorIndex: 2 }, { x: 11, y: 6, colorIndex: 3 },
|
||||
{ x: 12, y: 6, colorIndex: 3 }, { x: 13, y: 6, colorIndex: 2 },
|
||||
{ x: 14, y: 6, colorIndex: 2 }, { x: 15, y: 6, colorIndex: 3 },
|
||||
{ x: 16, y: 6, colorIndex: 3 }, { x: 17, y: 6, colorIndex: 2 },
|
||||
{ x: 18, y: 6, colorIndex: 2 }, { x: 19, y: 6, colorIndex: 0 },
|
||||
// Continue lid
|
||||
{ x: 3, y: 7, colorIndex: 0 }, { x: 4, y: 7, colorIndex: 2 },
|
||||
{ x: 5, y: 7, colorIndex: 3 }, { x: 6, y: 7, colorIndex: 3 },
|
||||
{ x: 7, y: 7, colorIndex: 2 }, { x: 8, y: 7, colorIndex: 2 },
|
||||
{ x: 9, y: 7, colorIndex: 2 }, { x: 10, y: 7, colorIndex: 3 },
|
||||
{ x: 11, y: 7, colorIndex: 3 }, { x: 12, y: 7, colorIndex: 2 },
|
||||
{ x: 13, y: 7, colorIndex: 2 }, { x: 14, y: 7, colorIndex: 2 },
|
||||
{ x: 15, y: 7, colorIndex: 3 }, { x: 16, y: 7, colorIndex: 3 },
|
||||
{ x: 17, y: 7, colorIndex: 2 }, { x: 18, y: 7, colorIndex: 2 },
|
||||
{ x: 19, y: 7, colorIndex: 2 }, { x: 20, y: 7, colorIndex: 0 },
|
||||
// Metal band on lid
|
||||
{ x: 3, y: 8, colorIndex: 0 }, { x: 4, y: 8, colorIndex: 4 },
|
||||
{ x: 5, y: 8, colorIndex: 5 }, { x: 6, y: 8, colorIndex: 5 },
|
||||
{ x: 7, y: 8, colorIndex: 4 }, { x: 8, y: 8, colorIndex: 4 },
|
||||
{ x: 9, y: 8, colorIndex: 4 }, { x: 10, y: 8, colorIndex: 5 },
|
||||
{ x: 11, y: 8, colorIndex: 5 }, { x: 12, y: 8, colorIndex: 4 },
|
||||
{ x: 13, y: 8, colorIndex: 4 }, { x: 14, y: 8, colorIndex: 4 },
|
||||
{ x: 15, y: 8, colorIndex: 5 }, { x: 16, y: 8, colorIndex: 5 },
|
||||
{ x: 17, y: 8, colorIndex: 4 }, { x: 18, y: 8, colorIndex: 4 },
|
||||
{ x: 19, y: 8, colorIndex: 4 }, { x: 20, y: 8, colorIndex: 0 },
|
||||
// Main body - upper section
|
||||
{ x: 4, y: 9, colorIndex: 0 }, { x: 5, y: 9, colorIndex: 2 },
|
||||
{ x: 6, y: 9, colorIndex: 2 }, { x: 7, y: 9, colorIndex: 2 },
|
||||
{ x: 8, y: 9, colorIndex: 2 }, { x: 9, y: 9, colorIndex: 2 },
|
||||
{ x: 10, y: 9, colorIndex: 2 }, { x: 11, y: 9, colorIndex: 2 },
|
||||
{ x: 12, y: 9, colorIndex: 2 }, { x: 13, y: 9, colorIndex: 2 },
|
||||
{ x: 14, y: 9, colorIndex: 2 }, { x: 15, y: 9, colorIndex: 2 },
|
||||
{ x: 16, y: 9, colorIndex: 2 }, { x: 17, y: 9, colorIndex: 2 },
|
||||
{ x: 18, y: 9, colorIndex: 2 }, { x: 19, y: 9, colorIndex: 0 },
|
||||
// Body with wood grain
|
||||
{ x: 5, y: 10, colorIndex: 0 }, { x: 6, y: 10, colorIndex: 3 },
|
||||
{ x: 7, y: 10, colorIndex: 2 }, { x: 8, y: 10, colorIndex: 2 },
|
||||
{ x: 9, y: 10, colorIndex: 1 }, { x: 10, y: 10, colorIndex: 2 },
|
||||
{ x: 11, y: 10, colorIndex: 3 }, { x: 12, y: 10, colorIndex: 3 },
|
||||
{ x: 13, y: 10, colorIndex: 2 }, { x: 14, y: 10, colorIndex: 1 },
|
||||
{ x: 15, y: 10, colorIndex: 2 }, { x: 16, y: 10, colorIndex: 3 },
|
||||
{ x: 17, y: 10, colorIndex: 2 }, { x: 18, y: 10, colorIndex: 0 },
|
||||
// Keyhole area
|
||||
{ x: 5, y: 11, colorIndex: 0 }, { x: 6, y: 11, colorIndex: 2 },
|
||||
{ x: 7, y: 11, colorIndex: 2 }, { x: 8, y: 11, colorIndex: 1 },
|
||||
{ x: 9, y: 11, colorIndex: 1 }, { x: 10, y: 11, colorIndex: 6 },
|
||||
{ x: 11, y: 11, colorIndex: 6 }, { x: 12, y: 11, colorIndex: 6 },
|
||||
{ x: 13, y: 11, colorIndex: 6 }, { x: 14, y: 11, colorIndex: 1 },
|
||||
{ x: 15, y: 11, colorIndex: 1 }, { x: 16, y: 11, colorIndex: 2 },
|
||||
{ x: 17, y: 11, colorIndex: 2 }, { x: 18, y: 11, colorIndex: 0 },
|
||||
{ x: 5, y: 12, colorIndex: 0 }, { x: 6, y: 12, colorIndex: 2 },
|
||||
{ x: 7, y: 12, colorIndex: 1 }, { x: 8, y: 12, colorIndex: 1 },
|
||||
{ x: 9, y: 12, colorIndex: 1 }, { x: 10, y: 12, colorIndex: 6 },
|
||||
{ x: 11, y: 12, colorIndex: 0 }, { x: 12, y: 12, colorIndex: 0 },
|
||||
{ x: 13, y: 12, colorIndex: 6 }, { x: 14, y: 12, colorIndex: 1 },
|
||||
{ x: 15, y: 12, colorIndex: 1 }, { x: 16, y: 12, colorIndex: 1 },
|
||||
{ x: 17, y: 12, colorIndex: 2 }, { x: 18, y: 12, colorIndex: 0 },
|
||||
{ x: 5, y: 13, colorIndex: 0 }, { x: 6, y: 13, colorIndex: 2 },
|
||||
{ x: 7, y: 13, colorIndex: 1 }, { x: 8, y: 13, colorIndex: 1 },
|
||||
{ x: 9, y: 13, colorIndex: 1 }, { x: 10, y: 13, colorIndex: 1 },
|
||||
{ x: 11, y: 13, colorIndex: 0 }, { x: 12, y: 13, colorIndex: 0 },
|
||||
{ x: 13, y: 13, colorIndex: 1 }, { x: 14, y: 13, colorIndex: 1 },
|
||||
{ x: 15, y: 13, colorIndex: 1 }, { x: 16, y: 13, colorIndex: 1 },
|
||||
{ x: 17, y: 13, colorIndex: 2 }, { x: 18, y: 13, colorIndex: 0 },
|
||||
// Lower body
|
||||
{ x: 5, y: 14, colorIndex: 0 }, { x: 6, y: 14, colorIndex: 2 },
|
||||
{ x: 7, y: 14, colorIndex: 1 }, { x: 8, y: 14, colorIndex: 1 },
|
||||
{ x: 9, y: 14, colorIndex: 1 }, { x: 10, y: 14, colorIndex: 1 },
|
||||
{ x: 11, y: 14, colorIndex: 1 }, { x: 12, y: 14, colorIndex: 1 },
|
||||
{ x: 13, y: 14, colorIndex: 1 }, { x: 14, y: 14, colorIndex: 1 },
|
||||
{ x: 15, y: 14, colorIndex: 1 }, { x: 16, y: 14, colorIndex: 1 },
|
||||
{ x: 17, y: 14, colorIndex: 2 }, { x: 18, y: 14, colorIndex: 0 },
|
||||
// Bottom metal band
|
||||
{ x: 5, y: 15, colorIndex: 0 }, { x: 6, y: 15, colorIndex: 4 },
|
||||
{ x: 7, y: 15, colorIndex: 5 }, { x: 8, y: 15, colorIndex: 4 },
|
||||
{ x: 9, y: 15, colorIndex: 4 }, { x: 10, y: 15, colorIndex: 4 },
|
||||
{ x: 11, y: 15, colorIndex: 5 }, { x: 12, y: 15, colorIndex: 5 },
|
||||
{ x: 13, y: 15, colorIndex: 4 }, { x: 14, y: 15, colorIndex: 4 },
|
||||
{ x: 15, y: 15, colorIndex: 4 }, { x: 16, y: 15, colorIndex: 5 },
|
||||
{ x: 17, y: 15, colorIndex: 4 }, { x: 18, y: 15, colorIndex: 0 },
|
||||
// Base
|
||||
{ x: 6, y: 16, colorIndex: 0 }, { x: 7, y: 16, colorIndex: 1 },
|
||||
{ x: 8, y: 16, colorIndex: 1 }, { x: 9, y: 16, colorIndex: 1 },
|
||||
{ x: 10, y: 16, colorIndex: 1 }, { x: 11, y: 16, colorIndex: 1 },
|
||||
{ x: 12, y: 16, colorIndex: 1 }, { x: 13, y: 16, colorIndex: 1 },
|
||||
{ x: 14, y: 16, colorIndex: 1 }, { x: 15, y: 16, colorIndex: 1 },
|
||||
{ x: 16, y: 16, colorIndex: 1 }, { x: 17, y: 16, colorIndex: 0 },
|
||||
{ x: 7, y: 17, colorIndex: 0 }, { x: 8, y: 17, colorIndex: 0 },
|
||||
{ x: 9, y: 17, colorIndex: 0 }, { x: 10, y: 17, colorIndex: 0 },
|
||||
{ x: 11, y: 17, colorIndex: 0 }, { x: 12, y: 17, colorIndex: 0 },
|
||||
{ x: 13, y: 17, colorIndex: 0 }, { x: 14, y: 17, colorIndex: 0 },
|
||||
{ x: 15, y: 17, colorIndex: 0 }, { x: 16, y: 17, colorIndex: 0 }
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A detailed treasure chest with wooden texture, metal reinforcement bands, and a prominent gold keyhole.
|
||||
|
||||
**Visual Description:**
|
||||
The chest shows a curved lid at the top with wood grain texture, two metal bands (one on the lid, one on the body), and a central gold keyhole. The wood uses three shades for depth, while the metal bands have highlights. Dark outlines define the structure clearly.
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
This examples collection demonstrates the pixel-art-creator skill's capabilities across various complexity levels:
|
||||
|
||||
- **Basic shapes** (Examples 1-4): Simple geometric sprites and icons with clear tool call patterns
|
||||
- **Layered compositions** (Examples 5-6): Multi-layer sprites with separate editable components
|
||||
- **Retro/indexed styles** (Examples 7-8): Period-accurate color palettes (Game Boy, NES)
|
||||
- **Complex scenes** (Examples 9-10): Tiles and detailed objects with intricate pixel work
|
||||
|
||||
Each example provides complete MCP tool call syntax that can be adapted for similar projects. The progression from simple to complex helps users understand how to build up sophisticated pixel art using the available tools.
|
||||
239
skills/pixel-art-creator/reference.md
Normal file
239
skills/pixel-art-creator/reference.md
Normal file
@@ -0,0 +1,239 @@
|
||||
# Pixel Art Creator - Technical Reference
|
||||
|
||||
## Color Mode Reference
|
||||
|
||||
### RGB Mode
|
||||
- **Bits Per Pixel**: 24-bit (8 bits each for R, G, B)
|
||||
- **Color Range**: 16,777,216 colors (256^3)
|
||||
- **Use Cases**: Modern pixel art, unrestricted color palettes, photorealistic pixel art
|
||||
- **Advantages**: No color limitations, easy to work with
|
||||
- **Disadvantages**: Larger file sizes, not authentic to retro aesthetics
|
||||
|
||||
### Grayscale Mode
|
||||
- **Bits Per Pixel**: 8-bit
|
||||
- **Color Range**: 256 shades of gray (black to white)
|
||||
- **Use Cases**: Monochrome art, vintage aesthetics, contrast studies
|
||||
- **Advantages**: Simpler color management, smaller file sizes
|
||||
- **Disadvantages**: No color information
|
||||
|
||||
### Indexed Mode
|
||||
- **Bits Per Pixel**: 1-8 bit (depending on palette size)
|
||||
- **Color Range**: 1-256 colors from defined palette
|
||||
- **Use Cases**: Retro game art, limited palette challenges, authentic vintage look
|
||||
- **Advantages**: Authentic retro aesthetic, enforced color constraints, smaller file sizes
|
||||
- **Disadvantages**: Must define palette first, color substitution required
|
||||
|
||||
## Common Sprite Dimensions
|
||||
|
||||
### Game Console Standards
|
||||
|
||||
**Nintendo Entertainment System (NES)**
|
||||
- Sprites: 8x8, 8x16 pixels
|
||||
- Screen: 256x240 pixels
|
||||
- Palette: 54 colors available, 4 colors per sprite
|
||||
|
||||
**Game Boy**
|
||||
- Sprites: 8x8, 8x16 pixels
|
||||
- Screen: 160x144 pixels
|
||||
- Palette: 4 shades of green/gray
|
||||
|
||||
**Super Nintendo (SNES)**
|
||||
- Sprites: 8x8 to 64x64 pixels (various sizes)
|
||||
- Screen: 256x224 pixels
|
||||
- Palette: 256 colors available, 15 colors per sprite
|
||||
|
||||
**Sega Genesis**
|
||||
- Sprites: 8x8 to 32x32 pixels
|
||||
- Screen: 320x224 pixels
|
||||
- Palette: 512 colors available, 15 colors per sprite
|
||||
|
||||
### Modern Standards
|
||||
|
||||
**Mobile Icons**
|
||||
- 16x16, 24x24, 32x32, 48x48, 64x64, 128x128
|
||||
|
||||
**Game Characters**
|
||||
- Small: 32x32, 48x48
|
||||
- Medium: 64x64, 96x96
|
||||
- Large: 128x128, 256x256
|
||||
|
||||
**Tiles/Blocks**
|
||||
- Standard: 16x16, 32x32
|
||||
- Large: 64x64, 128x128
|
||||
|
||||
## Drawing Coordinate System
|
||||
|
||||
```
|
||||
(0,0) ────────────► X
|
||||
│
|
||||
│
|
||||
│
|
||||
│
|
||||
▼
|
||||
Y
|
||||
|
||||
Canvas Bounds:
|
||||
- Top-Left: (0, 0)
|
||||
- Top-Right: (width-1, 0)
|
||||
- Bottom-Left: (0, height-1)
|
||||
- Bottom-Right: (width-1, height-1)
|
||||
```
|
||||
|
||||
## Color Format Specifications
|
||||
|
||||
### Hexadecimal Colors
|
||||
Format: `#RRGGBB`
|
||||
- RR: Red component (00-FF)
|
||||
- GG: Green component (00-FF)
|
||||
- BB: Blue component (00-FF)
|
||||
|
||||
Examples:
|
||||
- Red: #FF0000
|
||||
- Green: #00FF00
|
||||
- Blue: #0000FF
|
||||
- Cyan: #00FFFF
|
||||
- Magenta: #FF00FF
|
||||
- Yellow: #FFFF00
|
||||
- Black: #000000
|
||||
- White: #FFFFFF
|
||||
|
||||
### RGB Values
|
||||
Format: (R, G, B)
|
||||
- R: 0-255
|
||||
- G: 0-255
|
||||
- B: 0-255
|
||||
|
||||
Examples:
|
||||
- Red: (255, 0, 0)
|
||||
- Green: (0, 255, 0)
|
||||
- Blue: (0, 0, 255)
|
||||
|
||||
## Tool Usage Patterns
|
||||
|
||||
### Batch Pixel Drawing
|
||||
When drawing many pixels, batch them:
|
||||
|
||||
```
|
||||
Good (batched):
|
||||
draw_pixels([
|
||||
{x: 10, y: 10, color: "#FF0000"},
|
||||
{x: 11, y: 10, color: "#FF0000"},
|
||||
{x: 12, y: 10, color: "#FF0000"}
|
||||
])
|
||||
|
||||
Less Efficient (individual):
|
||||
draw_pixels({x: 10, y: 10, color: "#FF0000"})
|
||||
draw_pixels({x: 11, y: 10, color: "#FF0000"})
|
||||
draw_pixels({x: 12, y: 10, color: "#FF0000"})
|
||||
```
|
||||
|
||||
### Shape Drawing Best Practices
|
||||
|
||||
**Rectangles:**
|
||||
- Use for backgrounds, platforms, UI elements
|
||||
- Filled mode: solid blocks
|
||||
- Outline mode: frames, borders
|
||||
|
||||
**Circles:**
|
||||
- Use for round objects, planets, bubbles
|
||||
- Filled mode: solid circles
|
||||
- Outline mode: rings, hoops
|
||||
|
||||
**Lines:**
|
||||
- Use for edges, connections, rays
|
||||
- Diagonal lines may have pixel stepping (antialiasing in professional Skill)
|
||||
|
||||
**Contours:**
|
||||
- Use for irregular shapes, terrain, complex outlines
|
||||
- Connect points in order
|
||||
- Closed polygon: last point connects to first
|
||||
|
||||
## Performance Guidelines
|
||||
|
||||
### Operation Speeds (typical)
|
||||
- Create canvas: <50ms
|
||||
- Add layer: <20ms
|
||||
- Draw pixels (batch of 100): <50ms
|
||||
- Draw rectangle: <30ms
|
||||
- Draw circle: <40ms
|
||||
- Fill area: <100ms (depends on area size)
|
||||
|
||||
### Optimization Tips
|
||||
1. Batch pixel operations when drawing many pixels
|
||||
2. Use shapes instead of pixels when possible (faster)
|
||||
3. Fill areas instead of drawing individual pixels
|
||||
4. Use layers to organize work (not for performance, but workflow)
|
||||
|
||||
## Palette Examples
|
||||
|
||||
### Game Boy (4 colors)
|
||||
```json
|
||||
["#0F380F", "#306230", "#8BAC0F", "#9BBC0F"]
|
||||
```
|
||||
Darkest to lightest green
|
||||
|
||||
### NES (simplified 16-color palette)
|
||||
```json
|
||||
[
|
||||
"#000000", "#FCFCFC", "#F8F8F8", "#BCBCBC",
|
||||
"#7C7C7C", "#A4E4FC", "#3CBCFC", "#0078F8",
|
||||
"#0000FC", "#B8B8F8", "#6888FC", "#0058F8",
|
||||
"#0000BC", "#D8B8F8", "#9878F8", "#6844FC"
|
||||
]
|
||||
```
|
||||
|
||||
### Pico-8 (16-color palette)
|
||||
```json
|
||||
[
|
||||
"#000000", "#1D2B53", "#7E2553", "#008751",
|
||||
"#AB5236", "#5F574F", "#C2C3C7", "#FFF1E8",
|
||||
"#FF004D", "#FFA300", "#FFEC27", "#00E436",
|
||||
"#29ADFF", "#83769C", "#FF77A8", "#FFCCAA"
|
||||
]
|
||||
```
|
||||
|
||||
### C64 (Commodore 64, 16 colors)
|
||||
```json
|
||||
[
|
||||
"#000000", "#FFFFFF", "#880000", "#AAFFEE",
|
||||
"#CC44CC", "#00CC55", "#0000AA", "#EEEE77",
|
||||
"#DD8855", "#664400", "#FF7777", "#333333",
|
||||
"#777777", "#AAFF66", "#0088FF", "#BBBBBB"
|
||||
]
|
||||
```
|
||||
|
||||
## Layer Naming Conventions
|
||||
|
||||
**Descriptive Names:**
|
||||
- "Background" - solid color or pattern behind main subject
|
||||
- "Character" - main subject or character
|
||||
- "Foreground" - objects in front of character
|
||||
- "Effects" - highlights, shadows, particles
|
||||
- "Outline" - borders or edge highlights
|
||||
- "Details" - fine details, accessories
|
||||
|
||||
**Organization Tips:**
|
||||
- Use consistent naming across projects
|
||||
- Name layers by content, not by color
|
||||
- Keep names short but descriptive
|
||||
- Use layers even for simple sprites (good habit)
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Pixelated Circle (Manual)
|
||||
For precise pixel placement in a circle:
|
||||
- Radius 4: 5x5 bounding box, 13 pixels
|
||||
- Radius 8: 9x9 bounding box, 57 pixels
|
||||
- Use symmetry: draw quadrant, mirror to others
|
||||
|
||||
### Pixelated Line (Manual)
|
||||
Bresenham's line algorithm (built into draw_line):
|
||||
- Minimizes pixel stepping
|
||||
- Creates clean diagonal lines
|
||||
- No gaps or overlaps
|
||||
|
||||
### Color Ramps (Shading)
|
||||
For smooth color transitions:
|
||||
- 3-color ramp: shadow, base, highlight
|
||||
- 5-color ramp: darkest, dark, base, light, lightest
|
||||
- Use analogous colors for smooth transitions
|
||||
746
skills/pixel-art-exporter/SKILL.md
Normal file
746
skills/pixel-art-exporter/SKILL.md
Normal file
@@ -0,0 +1,746 @@
|
||||
---
|
||||
name: Pixel Art Exporter
|
||||
description: Export sprites to PNG, GIF, or spritesheet formats with JSON metadata for game engines. Use when the user wants to "export", "save", "output", "render", "generate", "create file", mentions file formats like "PNG", "GIF", "animated GIF", "spritesheet", "sprite sheet", "texture atlas", "tile sheet", or game engine integration with "Unity", "Godot", "Phaser", "Unreal", "GameMaker". Trigger on layout terms ("horizontal", "vertical", "grid", "packed", "strip"), scaling ("2x", "4x", "upscale", "pixel-perfect"), file operations ("save as", "export to", "output to"), metadata formats ("JSON", "XML", "metadata", "atlas data"), and delivery terms ("for web", "for game", "for Twitter", "for itch.io", "optimized").
|
||||
allowed-tools: Read, Bash, mcp__aseprite__export_png, mcp__aseprite__export_gif, mcp__aseprite__export_spritesheet, mcp__aseprite__get_sprite_info
|
||||
---
|
||||
|
||||
# Pixel Art Exporter
|
||||
|
||||
## Overview
|
||||
|
||||
The Pixel Art Exporter Skill enables exporting pixel art sprites from Aseprite to various formats optimized for different use cases. This includes single images (PNG), animated GIFs, spritesheets, and JSON metadata for game engines.
|
||||
|
||||
**Core Capabilities:**
|
||||
- Export single frames or entire animations as PNG images
|
||||
- Generate animated GIFs with customizable timing and looping
|
||||
- Create spritesheets in multiple layouts (horizontal, vertical, grid, packed)
|
||||
- Generate JSON metadata for game engines (Unity, Godot, Phaser, generic)
|
||||
- Scale exports with pixel-perfect upscaling (1x, 2x, 4x, etc.)
|
||||
- Handle transparency, background colors, and frame-specific exports
|
||||
|
||||
**Export Formats Supported:**
|
||||
- **PNG**: Single images or frame sequences with transparency
|
||||
- **GIF**: Animated GIFs with frame timing and loop control
|
||||
- **Spritesheet**: Texture atlases with various packing algorithms
|
||||
- **JSON**: Frame metadata, animation tags, layer information
|
||||
|
||||
This Skill works with the pixel-mcp server tools to produce production-ready assets for web, games, and applications.
|
||||
|
||||
## When to Use
|
||||
|
||||
Invoke this Skill when the user:
|
||||
|
||||
- **Wants to export or save**: "export this sprite", "save as PNG", "generate a spritesheet"
|
||||
- **Mentions file formats**: "PNG", "GIF", "spritesheet", "sprite sheet", "texture atlas", "JSON"
|
||||
- **Prepares for game engines**: "export for Unity", "Godot spritesheet", "Phaser animation"
|
||||
- **Needs specific outputs**: "export just frame 3", "create a tileset", "save each layer separately"
|
||||
- **Requests scaling**: "export at 2x size", "scale up 4x", "upscale for retina displays"
|
||||
- **Wants animation exports**: "make this into a GIF", "export the animation", "save all frames"
|
||||
- **Needs metadata**: "include JSON data", "export with coordinates", "frame information"
|
||||
|
||||
**Example Triggers:**
|
||||
- "Can you export this character sprite as a PNG?"
|
||||
- "I need a spritesheet for my game engine"
|
||||
- "Save this animation as an animated GIF"
|
||||
- "Export at 4x scale for high-resolution displays"
|
||||
- "Generate a texture atlas with JSON metadata"
|
||||
- "Export just the 'run' animation tag"
|
||||
|
||||
## Instructions
|
||||
|
||||
### 1. Exporting Single Images (PNG)
|
||||
|
||||
**For static sprites or single frames:**
|
||||
|
||||
1. **Get Sprite Information First**
|
||||
```
|
||||
Use mcp__aseprite__get_sprite_info to understand:
|
||||
- Current dimensions
|
||||
- Number of frames
|
||||
- Available layers
|
||||
- Color mode and transparency settings
|
||||
```
|
||||
|
||||
2. **Export PNG with Transparency**
|
||||
```
|
||||
Use mcp__aseprite__export_png:
|
||||
- file_path: Absolute path (e.g., "/path/to/output/sprite.png")
|
||||
- frame_number: Specific frame (0-indexed) or omit for current frame
|
||||
- layer: Specific layer name or omit for merged output
|
||||
- scale: Scaling factor (1, 2, 4, etc.) - default is 1
|
||||
```
|
||||
|
||||
3. **Export Options**
|
||||
- **Transparent background**: Default behavior, preserves alpha channel
|
||||
- **Specific background**: Use layer visibility or flatten before export
|
||||
- **Single frame from animation**: Specify frame_number parameter
|
||||
- **Specific layer only**: Provide layer name to export just that layer
|
||||
|
||||
**Example Workflow:**
|
||||
```
|
||||
1. Get sprite info to verify dimensions and frame count
|
||||
2. Export PNG: mcp__aseprite__export_png with desired frame and scale
|
||||
3. Confirm file creation and report dimensions to user
|
||||
```
|
||||
|
||||
### 2. Exporting Animated GIFs
|
||||
|
||||
**For animations intended for web or presentations:**
|
||||
|
||||
1. **Verify Animation Setup**
|
||||
```
|
||||
Use mcp__aseprite__get_sprite_info to check:
|
||||
- Frame count (needs 2+ frames)
|
||||
- Frame durations (timing information)
|
||||
- Animation tags (if specific tag requested)
|
||||
- Sprite dimensions
|
||||
```
|
||||
|
||||
2. **Export GIF**
|
||||
```
|
||||
Use mcp__aseprite__export_gif:
|
||||
- file_path: Output path (e.g., "/path/to/animation.gif")
|
||||
- animation_tag: Optional - specific tag name to export
|
||||
- loop: true (infinite loop) or false (play once)
|
||||
- scale: Upscaling factor if needed
|
||||
```
|
||||
|
||||
3. **GIF Optimization Considerations**
|
||||
- GIF format has 256-color limit - ensure palette is optimized
|
||||
- Frame timing is preserved from Aseprite frame durations
|
||||
- Transparency is supported but may have edge artifacts
|
||||
- File size increases with dimensions and frame count
|
||||
|
||||
**Example Workflow:**
|
||||
```
|
||||
1. Verify sprite has multiple frames
|
||||
2. Export GIF with appropriate loop setting
|
||||
3. Report file size and frame count to user
|
||||
4. Suggest optimization if file is large (>1MB)
|
||||
```
|
||||
|
||||
### 3. Creating Spritesheets
|
||||
|
||||
**For game engines and texture atlases:**
|
||||
|
||||
1. **Understand Layout Requirements**
|
||||
|
||||
**Layout Types:**
|
||||
- **Horizontal**: All frames in a single row (good for scrolling animations)
|
||||
- **Vertical**: All frames in a single column (good for CSS animations)
|
||||
- **Grid**: Frames arranged in rows and columns (balanced dimensions)
|
||||
- **Packed**: Optimized packing to minimize texture size (engine-specific)
|
||||
|
||||
2. **Export Spritesheet**
|
||||
```
|
||||
Use mcp__aseprite__export_spritesheet:
|
||||
- file_path: Output PNG path (e.g., "/path/to/spritesheet.png")
|
||||
- layout: "horizontal", "vertical", "grid", or "packed"
|
||||
- animation_tag: Optional - export specific animation only
|
||||
- scale: Upscaling factor
|
||||
- padding: Pixels between frames (default 0, common: 1-2)
|
||||
- include_json: true to generate metadata file
|
||||
```
|
||||
|
||||
3. **JSON Metadata Structure**
|
||||
|
||||
When `include_json: true`, creates a .json file with:
|
||||
```json
|
||||
{
|
||||
"frames": [
|
||||
{
|
||||
"filename": "frame_0.png",
|
||||
"frame": {"x": 0, "y": 0, "w": 32, "h": 32},
|
||||
"spriteSourceSize": {"x": 0, "y": 0, "w": 32, "h": 32},
|
||||
"sourceSize": {"w": 32, "h": 32},
|
||||
"duration": 100
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"app": "Aseprite",
|
||||
"version": "1.3.x",
|
||||
"format": "RGBA8888",
|
||||
"size": {"w": 256, "h": 32},
|
||||
"scale": "1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
4. **Layout Selection Guidelines**
|
||||
- **Horizontal**: Best for web/CSS sprite animations, simple scrolling
|
||||
- **Vertical**: Mobile-friendly, vertical scrolling animations
|
||||
- **Grid**: Unity, Godot - balanced texture dimensions (power-of-2)
|
||||
- **Packed**: Advanced engines with atlas support (Phaser, LibGDX)
|
||||
|
||||
**Example Workflow:**
|
||||
```
|
||||
1. Ask user about target platform if not specified
|
||||
2. Recommend layout based on use case
|
||||
3. Export spritesheet with JSON metadata
|
||||
4. Report texture dimensions and frame count
|
||||
5. Provide integration code sample for their engine
|
||||
```
|
||||
|
||||
### 4. Generating JSON Metadata
|
||||
|
||||
**For game engine integration:**
|
||||
|
||||
1. **Metadata Formats by Engine**
|
||||
|
||||
**Unity:**
|
||||
- Use "grid" layout for Unity's Sprite Editor
|
||||
- JSON provides frame coordinates for slicing
|
||||
- Include padding to prevent texture bleeding
|
||||
|
||||
**Godot:**
|
||||
- Use "horizontal" or "grid" layout
|
||||
- JSON maps to AnimatedSprite frames
|
||||
- Frame duration converts to FPS
|
||||
|
||||
**Phaser:**
|
||||
- Use "packed" layout for optimal performance
|
||||
- JSON follows Texture Packer format
|
||||
- Supports trimmed sprites and rotation
|
||||
|
||||
**Generic/Custom:**
|
||||
- Standard frame array with x, y, w, h coordinates
|
||||
- Duration in milliseconds per frame
|
||||
- Animation tag groupings
|
||||
|
||||
2. **Export with Metadata**
|
||||
```
|
||||
Always include JSON when exporting for game engines:
|
||||
- Set include_json: true in export_spritesheet
|
||||
- JSON file created with same name as PNG (different extension)
|
||||
- Contains frame positions, durations, and sprite metadata
|
||||
```
|
||||
|
||||
3. **Metadata Usage Examples**
|
||||
|
||||
**Parsing in JavaScript (Phaser):**
|
||||
```javascript
|
||||
this.load.atlas('sprite', 'spritesheet.png', 'spritesheet.json');
|
||||
this.add.sprite(x, y, 'sprite', 'frame_0.png');
|
||||
```
|
||||
|
||||
**Parsing in C# (Unity):**
|
||||
```csharp
|
||||
// Import spritesheet.png with Multiple sprite mode
|
||||
// Use JSON to set sprite rectangles in Sprite Editor
|
||||
```
|
||||
|
||||
### 5. Scaling Exports
|
||||
|
||||
**Pixel-perfect upscaling for high-resolution displays:**
|
||||
|
||||
1. **When to Scale**
|
||||
- Retina/HiDPI displays: Use 2x or 4x
|
||||
- Modern game engines: Export at native size, let engine scale
|
||||
- Web: Export 2x and use CSS to scale down (sharper rendering)
|
||||
- Print/marketing: Use 4x or higher
|
||||
|
||||
2. **Scaling Best Practices**
|
||||
- Always use integer scaling (1x, 2x, 3x, 4x, not 1.5x)
|
||||
- Maintain pixel-perfect sharpness with nearest-neighbor
|
||||
- Scale before export, not after (prevents blurring)
|
||||
- Consider file size vs. quality tradeoffs
|
||||
|
||||
3. **Apply Scaling**
|
||||
```
|
||||
Add scale parameter to any export:
|
||||
- mcp__aseprite__export_png: scale: 2
|
||||
- mcp__aseprite__export_gif: scale: 4
|
||||
- mcp__aseprite__export_spritesheet: scale: 2
|
||||
```
|
||||
|
||||
4. **Resolution Recommendations**
|
||||
- **1x**: Original pixel art size, retro aesthetic
|
||||
- **2x**: Standard for modern displays, good balance
|
||||
- **4x**: High-resolution, marketing materials
|
||||
- **8x+**: Ultra-high-resolution, print, large displays
|
||||
|
||||
## Export Workflows for Different Use Cases
|
||||
|
||||
### Static Sprite for Web
|
||||
|
||||
```
|
||||
1. Get sprite info to verify single frame
|
||||
2. Export PNG at 2x scale with transparency
|
||||
3. Optimize PNG with compression tools if needed
|
||||
4. Provide HTML/CSS example for display
|
||||
```
|
||||
|
||||
### Character Animation for Game
|
||||
|
||||
```
|
||||
1. Verify animation has multiple frames and tags
|
||||
2. Export spritesheet with "grid" layout
|
||||
3. Include JSON metadata (include_json: true)
|
||||
4. Set appropriate padding (1-2 pixels)
|
||||
5. Scale if needed (typically 1x for engines)
|
||||
6. Provide code snippet for target engine
|
||||
```
|
||||
|
||||
### Icon Set Export
|
||||
|
||||
```
|
||||
1. If multiple layers, export each separately
|
||||
2. Use PNG format with transparency
|
||||
3. Scale to multiple sizes (16x16, 32x32, 64x64)
|
||||
4. Batch export all sizes
|
||||
5. Organize in output directory structure
|
||||
```
|
||||
|
||||
### Social Media GIF
|
||||
|
||||
```
|
||||
1. Verify frame timing is appropriate (100-200ms typical)
|
||||
2. Export GIF with loop: true
|
||||
3. Scale to 2x or 4x for visibility
|
||||
4. Check file size (optimize if >2MB)
|
||||
5. Suggest hosting platforms if needed
|
||||
```
|
||||
|
||||
### Tileset for Game Engine
|
||||
|
||||
```
|
||||
1. Verify tiles are uniform size (e.g., 16x16, 32x32)
|
||||
2. Export as grid spritesheet
|
||||
3. Set padding to 0 or 1 (depends on engine)
|
||||
4. Include JSON for tile coordinates
|
||||
5. Provide tile size and grid dimensions
|
||||
```
|
||||
|
||||
## Game Engine Integration
|
||||
|
||||
### Unity Integration
|
||||
|
||||
**Export Settings:**
|
||||
- Layout: "grid"
|
||||
- Include JSON: true
|
||||
- Padding: 1-2 pixels (prevents bleeding)
|
||||
- Scale: 1x (Unity handles scaling)
|
||||
|
||||
**Import Steps:**
|
||||
1. Import spritesheet.png into Assets
|
||||
2. Set Texture Type to "Sprite (2D and UI)"
|
||||
3. Set Sprite Mode to "Multiple"
|
||||
4. Open Sprite Editor and use JSON coordinates to slice
|
||||
5. Create Animator Controller with sprite animation
|
||||
|
||||
**Code Example:**
|
||||
```csharp
|
||||
SpriteRenderer renderer = GetComponent<SpriteRenderer>();
|
||||
renderer.sprite = sprites[frameIndex];
|
||||
```
|
||||
|
||||
### Godot Integration
|
||||
|
||||
**Export Settings:**
|
||||
- Layout: "horizontal" or "grid"
|
||||
- Include JSON: true
|
||||
- Scale: 1x
|
||||
- Padding: 0-1 pixels
|
||||
|
||||
**Import Steps:**
|
||||
1. Import spritesheet.png to project
|
||||
2. Create AnimatedSprite node
|
||||
3. Create SpriteFrames resource
|
||||
4. Add frames from spritesheet
|
||||
5. Use JSON durations to set FPS
|
||||
|
||||
**Code Example:**
|
||||
```gdscript
|
||||
$AnimatedSprite.play("run")
|
||||
$AnimatedSprite.speed_scale = 1.0
|
||||
```
|
||||
|
||||
### Phaser Integration
|
||||
|
||||
**Export Settings:**
|
||||
- Layout: "packed" or "horizontal"
|
||||
- Include JSON: true (Texture Packer format)
|
||||
- Scale: 1x or 2x depending on game resolution
|
||||
|
||||
**Import Steps:**
|
||||
1. Place spritesheet.png and .json in assets
|
||||
2. Load as atlas in preload()
|
||||
3. Create sprite with atlas key
|
||||
4. Create animations from frame names
|
||||
|
||||
**Code Example:**
|
||||
```javascript
|
||||
this.load.atlas('player', 'spritesheet.png', 'spritesheet.json');
|
||||
|
||||
this.anims.create({
|
||||
key: 'run',
|
||||
frames: this.anims.generateFrameNames('player', {
|
||||
prefix: 'frame_',
|
||||
suffix: '.png',
|
||||
start: 0,
|
||||
end: 7
|
||||
}),
|
||||
frameRate: 10,
|
||||
repeat: -1
|
||||
});
|
||||
```
|
||||
|
||||
### Generic/Custom Engine
|
||||
|
||||
**Export Settings:**
|
||||
- Layout: Based on engine capabilities
|
||||
- Include JSON: true
|
||||
- Provide simple frame array format
|
||||
|
||||
**JSON Structure:**
|
||||
```json
|
||||
{
|
||||
"frames": [
|
||||
{"x": 0, "y": 0, "w": 32, "h": 32, "duration": 100}
|
||||
],
|
||||
"meta": {
|
||||
"frameWidth": 32,
|
||||
"frameHeight": 32,
|
||||
"frameCount": 8
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Integration Pattern:**
|
||||
1. Load PNG texture
|
||||
2. Parse JSON to get frame rectangles
|
||||
3. Create sub-textures/sprites from coordinates
|
||||
4. Use duration for animation timing
|
||||
|
||||
## Technical Details
|
||||
|
||||
### PNG Export Format
|
||||
|
||||
**Specifications:**
|
||||
- Color Mode: RGBA (8-bit per channel)
|
||||
- Transparency: Full alpha channel support
|
||||
- Compression: PNG lossless compression
|
||||
- Color Space: sRGB
|
||||
- Bit Depth: 32-bit (8-bit per channel RGBA)
|
||||
|
||||
**When to Use:**
|
||||
- Static sprites with transparency
|
||||
- Individual frames from animations
|
||||
- High-quality source files
|
||||
- Layer-specific exports
|
||||
|
||||
### GIF Export Format
|
||||
|
||||
**Specifications:**
|
||||
- Color Palette: Maximum 256 colors
|
||||
- Transparency: Binary (on/off), no partial alpha
|
||||
- Animation: Frame-based with per-frame timing
|
||||
- Loop Control: Infinite or play-once
|
||||
- Compression: LZW compression
|
||||
|
||||
**Limitations:**
|
||||
- Color limit may require palette optimization
|
||||
- No partial transparency (alpha is binary)
|
||||
- Larger file sizes than video formats
|
||||
- Limited to 8-bit color depth
|
||||
|
||||
**When to Use:**
|
||||
- Web animations without video player
|
||||
- Social media posts
|
||||
- Email-compatible animations
|
||||
- Simple looping animations
|
||||
|
||||
### Spritesheet Layouts
|
||||
|
||||
**Horizontal Layout:**
|
||||
```
|
||||
[Frame0][Frame1][Frame2][Frame3]...
|
||||
```
|
||||
- Dimensions: width = frameWidth * frameCount, height = frameHeight
|
||||
- Best for: CSS animations, simple scrolling
|
||||
|
||||
**Vertical Layout:**
|
||||
```
|
||||
[Frame0]
|
||||
[Frame1]
|
||||
[Frame2]
|
||||
[Frame3]
|
||||
...
|
||||
```
|
||||
- Dimensions: width = frameWidth, height = frameHeight * frameCount
|
||||
- Best for: Mobile-optimized, vertical scrolling
|
||||
|
||||
**Grid Layout:**
|
||||
```
|
||||
[Frame0][Frame1][Frame2][Frame3]
|
||||
[Frame4][Frame5][Frame6][Frame7]
|
||||
[Frame8][Frame9][Frame10][Frame11]
|
||||
```
|
||||
- Dimensions: Balanced to create near-square texture
|
||||
- Best for: Game engines, power-of-2 textures, Unity, Godot
|
||||
|
||||
**Packed Layout:**
|
||||
```
|
||||
[Frame0][Frame2][Frame5]
|
||||
[Frame1][Frame3][Frame6]
|
||||
[Frame4][Frame7]
|
||||
```
|
||||
- Dimensions: Optimally packed to minimize wasted space
|
||||
- Best for: Advanced engines with atlas support (Phaser, LibGDX)
|
||||
- Requires JSON metadata for frame positions
|
||||
|
||||
### Metadata Structures
|
||||
|
||||
**Standard Frame Format:**
|
||||
```json
|
||||
{
|
||||
"filename": "frame_0.png",
|
||||
"frame": {"x": 0, "y": 0, "w": 32, "h": 32},
|
||||
"rotated": false,
|
||||
"trimmed": false,
|
||||
"spriteSourceSize": {"x": 0, "y": 0, "w": 32, "h": 32},
|
||||
"sourceSize": {"w": 32, "h": 32},
|
||||
"duration": 100
|
||||
}
|
||||
```
|
||||
|
||||
**Fields Explained:**
|
||||
- `filename`: Logical frame identifier
|
||||
- `frame`: Position and size in spritesheet (pixels)
|
||||
- `rotated`: Whether frame is rotated 90° (packed layouts)
|
||||
- `trimmed`: Whether transparent pixels were removed
|
||||
- `spriteSourceSize`: Position within original canvas if trimmed
|
||||
- `sourceSize`: Original canvas size before trimming
|
||||
- `duration`: Frame duration in milliseconds
|
||||
|
||||
**Meta Information:**
|
||||
```json
|
||||
{
|
||||
"app": "Aseprite",
|
||||
"version": "1.3.x",
|
||||
"format": "RGBA8888",
|
||||
"size": {"w": 256, "h": 128},
|
||||
"scale": "1",
|
||||
"frameTags": [
|
||||
{"name": "idle", "from": 0, "to": 3, "direction": "forward"},
|
||||
{"name": "run", "from": 4, "to": 11, "direction": "forward"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Common Export Patterns
|
||||
|
||||
### Pattern 1: Single Frame Export
|
||||
|
||||
**Scenario:** User wants just one frame as PNG
|
||||
|
||||
```
|
||||
1. mcp__aseprite__get_sprite_info (verify frame exists)
|
||||
2. mcp__aseprite__export_png:
|
||||
- file_path: "/output/frame.png"
|
||||
- frame_number: 0 (or user-specified)
|
||||
- scale: 1 (or user-specified)
|
||||
3. Confirm export with dimensions
|
||||
```
|
||||
|
||||
### Pattern 2: Full Animation GIF
|
||||
|
||||
**Scenario:** User wants animated GIF of entire sprite
|
||||
|
||||
```
|
||||
1. mcp__aseprite__get_sprite_info (verify frames > 1)
|
||||
2. mcp__aseprite__export_gif:
|
||||
- file_path: "/output/animation.gif"
|
||||
- loop: true
|
||||
- scale: 2
|
||||
3. Report frame count and file size
|
||||
```
|
||||
|
||||
### Pattern 3: Game-Ready Spritesheet
|
||||
|
||||
**Scenario:** User wants spritesheet for Unity/Godot
|
||||
|
||||
```
|
||||
1. mcp__aseprite__get_sprite_info (check dimensions and frames)
|
||||
2. Ask about target engine if not specified
|
||||
3. mcp__aseprite__export_spritesheet:
|
||||
- file_path: "/output/spritesheet.png"
|
||||
- layout: "grid"
|
||||
- include_json: true
|
||||
- padding: 1
|
||||
- scale: 1
|
||||
4. Provide integration instructions for target engine
|
||||
```
|
||||
|
||||
### Pattern 4: Specific Animation Tag
|
||||
|
||||
**Scenario:** User wants to export just one animation (e.g., "run")
|
||||
|
||||
```
|
||||
1. mcp__aseprite__get_sprite_info (verify tag exists)
|
||||
2. mcp__aseprite__export_spritesheet or export_gif:
|
||||
- animation_tag: "run"
|
||||
- Other settings as appropriate
|
||||
3. Confirm only tagged frames exported
|
||||
```
|
||||
|
||||
### Pattern 5: Multi-Resolution Export
|
||||
|
||||
**Scenario:** User wants multiple scales (1x, 2x, 4x)
|
||||
|
||||
```
|
||||
1. Export PNG/spritesheet at scale: 1
|
||||
2. Export PNG/spritesheet at scale: 2
|
||||
3. Export PNG/spritesheet at scale: 4
|
||||
4. Organize files: sprite_1x.png, sprite_2x.png, sprite_4x.png
|
||||
5. Report all outputs with dimensions
|
||||
```
|
||||
|
||||
### Pattern 6: Layer-Specific Export
|
||||
|
||||
**Scenario:** User wants individual layers as separate files
|
||||
|
||||
```
|
||||
1. mcp__aseprite__get_sprite_info (get layer names)
|
||||
2. For each layer:
|
||||
- mcp__aseprite__export_png:
|
||||
- layer: "LayerName"
|
||||
- file_path: "/output/layerName.png"
|
||||
3. Report all exported layers
|
||||
```
|
||||
|
||||
## Integration with Other Skills
|
||||
|
||||
### Pixel Art Creator Integration
|
||||
|
||||
**Workflow:** Create → Export
|
||||
```
|
||||
1. User creates sprite with Pixel Art Creator Skill
|
||||
2. Automatically offer export options when creation complete
|
||||
3. Suggest appropriate format based on sprite type (static vs animated)
|
||||
4. Use this Skill to handle export
|
||||
```
|
||||
|
||||
### Pixel Art Animator Integration
|
||||
|
||||
**Workflow:** Animate → Export
|
||||
```
|
||||
1. User creates animation with Pixel Art Animator Skill
|
||||
2. When animation complete, offer export formats:
|
||||
- GIF for web/social
|
||||
- Spritesheet for games
|
||||
3. Use this Skill for export with animation metadata
|
||||
```
|
||||
|
||||
### Pixel Art Professional Integration
|
||||
|
||||
**Workflow:** Optimize → Export
|
||||
```
|
||||
1. User applies professional techniques (dithering, palette optimization)
|
||||
2. Export with optimized settings:
|
||||
- Preserve palette for GIF export
|
||||
- Use appropriate compression for PNG
|
||||
3. This Skill handles format-specific optimization
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### File Path Issues
|
||||
|
||||
**Problem:** Invalid or inaccessible output path
|
||||
|
||||
**Solution:**
|
||||
```
|
||||
1. Verify directory exists (create if needed using Bash)
|
||||
2. Check write permissions
|
||||
3. Use absolute paths, not relative
|
||||
4. Suggest valid path if user provides invalid one
|
||||
```
|
||||
|
||||
### Missing Frames or Tags
|
||||
|
||||
**Problem:** User requests frame/tag that doesn't exist
|
||||
|
||||
**Solution:**
|
||||
```
|
||||
1. Use get_sprite_info to verify available frames and tags
|
||||
2. List available options to user
|
||||
3. Ask user to clarify which frame/tag they want
|
||||
4. Don't attempt export until valid selection made
|
||||
```
|
||||
|
||||
### Large File Warnings
|
||||
|
||||
**Problem:** Export will create very large file (GIF >5MB, PNG >10MB)
|
||||
|
||||
**Solution:**
|
||||
```
|
||||
1. Calculate approximate size based on dimensions and frame count
|
||||
2. Warn user before export if size exceeds thresholds
|
||||
3. Suggest alternatives:
|
||||
- Reduce scale factor
|
||||
- Export fewer frames
|
||||
- Use spritesheet instead of GIF
|
||||
- Optimize palette
|
||||
```
|
||||
|
||||
### Format Limitations
|
||||
|
||||
**Problem:** User requests feature not supported by format (e.g., GIF transparency)
|
||||
|
||||
**Solution:**
|
||||
```
|
||||
1. Explain format limitation clearly
|
||||
2. Suggest alternative format or approach
|
||||
3. Proceed with export noting the limitation
|
||||
4. Examples:
|
||||
- GIF binary transparency → suggest PNG for partial alpha
|
||||
- GIF 256-color limit → suggest palette optimization first
|
||||
```
|
||||
|
||||
### Scale Factor Issues
|
||||
|
||||
**Problem:** Non-integer scale or excessive scaling
|
||||
|
||||
**Solution:**
|
||||
```
|
||||
1. Only accept integer scale factors (1, 2, 3, 4, etc.)
|
||||
2. Warn if scale >4 (may create very large files)
|
||||
3. Explain pixel-perfect scaling benefits
|
||||
4. Suggest appropriate scale for user's use case
|
||||
```
|
||||
|
||||
## Success Indicators
|
||||
|
||||
**Export completed successfully when:**
|
||||
|
||||
1. **File Created**: Output file exists at specified path
|
||||
2. **Correct Format**: File extension matches requested format (.png, .gif)
|
||||
3. **Expected Dimensions**: Scaled dimensions are correct (originalSize * scale)
|
||||
4. **Frame Count Match**: Spritesheet or GIF contains expected number of frames
|
||||
5. **JSON Generated**: Metadata file created if include_json was true
|
||||
6. **User Confirmation**: User can open and verify exported file
|
||||
|
||||
**Report to User:**
|
||||
```
|
||||
✓ Export complete: /path/to/output.png
|
||||
- Format: PNG with transparency
|
||||
- Dimensions: 64x64 (2x scale from 32x32 original)
|
||||
- Frames: 1 (static image)
|
||||
- File size: ~8KB
|
||||
|
||||
[For spritesheets, also include:]
|
||||
- Layout: Grid (4x2)
|
||||
- Frame dimensions: 32x32 each
|
||||
- Total frames: 8
|
||||
- JSON metadata: /path/to/output.json
|
||||
- Integration: Ready for Unity/Godot import
|
||||
|
||||
[Provide relevant integration code snippet if applicable]
|
||||
```
|
||||
|
||||
**Post-Export Guidance:**
|
||||
- Suggest next steps (import to engine, optimize file size, create additional scales)
|
||||
- Offer integration code for target platform
|
||||
- Explain how to use JSON metadata
|
||||
- Recommend testing in target environment
|
||||
617
skills/pixel-art-exporter/examples.md
Normal file
617
skills/pixel-art-exporter/examples.md
Normal file
@@ -0,0 +1,617 @@
|
||||
# Pixel Art Exporter Examples
|
||||
|
||||
This document provides concrete examples of how the pixel-art-exporter skill handles exporting pixel art from Aseprite to various formats. Each example shows the user's request, step-by-step approach, actual MCP tool calls with parameters, and expected results.
|
||||
|
||||
Examples are organized by export type: single images, animated GIFs, spritesheets, and game engine integration workflows.
|
||||
|
||||
---
|
||||
|
||||
## Single Image Exports
|
||||
|
||||
### Example 1: Simple PNG Export
|
||||
|
||||
**User Request:**
|
||||
> "Export my sprite as a PNG file with transparency"
|
||||
|
||||
**Approach:**
|
||||
1. Get current sprite information
|
||||
2. Export as PNG with alpha channel
|
||||
3. Specify output path
|
||||
4. Maintain original dimensions
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// Get sprite info to confirm dimensions
|
||||
mcp__aseprite__get_sprite_info()
|
||||
|
||||
// Export as PNG with transparency
|
||||
mcp__aseprite__export_png({
|
||||
filename: "character-sprite.png",
|
||||
frame: "current", // Export currently selected frame
|
||||
layer: "all", // Include all layers
|
||||
alpha: true // Preserve transparency
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A PNG file with transparent background, ready to use in games or websites.
|
||||
|
||||
**Visual Description:**
|
||||
The exported PNG shows the sprite with a checkered transparency background in image viewers. All colors are preserved exactly as they appear in Aseprite. The file can be placed over any background in a game engine or graphics program.
|
||||
|
||||
---
|
||||
|
||||
### Example 2: PNG with Specific Background Color
|
||||
|
||||
**User Request:**
|
||||
> "Export my icon with a white background instead of transparency"
|
||||
|
||||
**Approach:**
|
||||
1. Check sprite info
|
||||
2. Export PNG with background color specified
|
||||
3. Flatten transparency to solid color
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
mcp__aseprite__get_sprite_info()
|
||||
|
||||
// Export PNG with white background
|
||||
mcp__aseprite__export_png({
|
||||
filename: "icon-white-bg.png",
|
||||
frame: "current",
|
||||
layer: "all",
|
||||
alpha: false, // No transparency
|
||||
background: { r: 255, g: 255, b: 255, a: 255 } // White
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A PNG with white background replacing all transparent areas.
|
||||
|
||||
**Visual Description:**
|
||||
The exported image has a solid white background. All transparent pixels have been filled with white. This is useful for icons that will be displayed on light backgrounds or for printing.
|
||||
|
||||
---
|
||||
|
||||
### Example 3: Scaled Export for High-DPI Displays
|
||||
|
||||
**User Request:**
|
||||
> "Export my 32x32 sprite at 4x scale for retina displays, without blur"
|
||||
|
||||
**Approach:**
|
||||
1. Get original dimensions
|
||||
2. Export with integer scaling (nearest neighbor)
|
||||
3. Maintain pixel-perfect sharpness
|
||||
4. Output at 128x128 pixels
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// Get sprite info
|
||||
const spriteInfo = mcp__aseprite__get_sprite_info()
|
||||
// Returns: { width: 32, height: 32, colorMode: "rgb", frames: 1 }
|
||||
|
||||
// Export at 4x scale with nearest neighbor
|
||||
mcp__aseprite__export_png({
|
||||
filename: "character-4x.png",
|
||||
frame: "current",
|
||||
layer: "all",
|
||||
alpha: true,
|
||||
scale: 4, // 4x larger
|
||||
scaleFilter: "nearest" // Pixel-perfect scaling (no blur)
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A 128x128 PNG that looks identical to the original but 4x larger, with crisp pixel edges.
|
||||
|
||||
**Visual Description:**
|
||||
The exported sprite is now 128x128 pixels. Each original pixel has become a 4x4 block of identical pixels. The image looks sharp and clear at large sizes with no blur or antialiasing artifacts. Perfect for high-DPI displays or large game sprites.
|
||||
|
||||
---
|
||||
|
||||
### Example 4: Export Specific Layer Only
|
||||
|
||||
**User Request:**
|
||||
> "Export just the 'character' layer without the background"
|
||||
|
||||
**Approach:**
|
||||
1. Identify layer name
|
||||
2. Export only that layer
|
||||
3. Maintain transparency from other layers
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// Get sprite info including layer information
|
||||
mcp__aseprite__get_sprite_info()
|
||||
|
||||
// Export only the character layer
|
||||
mcp__aseprite__export_png({
|
||||
filename: "character-only.png",
|
||||
frame: "current",
|
||||
layer: "character", // Specific layer name
|
||||
alpha: true
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A PNG containing only the character layer, with background layer excluded and transparent.
|
||||
|
||||
**Visual Description:**
|
||||
The exported image shows only the character sprite without the background elements. Areas where the background layer was are now fully transparent. Useful for exporting game assets separately or creating variations.
|
||||
|
||||
---
|
||||
|
||||
## Animated GIF Exports
|
||||
|
||||
### Example 5: Basic Animated GIF
|
||||
|
||||
**User Request:**
|
||||
> "Export my walk cycle animation as an animated GIF"
|
||||
|
||||
**Approach:**
|
||||
1. Verify animation has multiple frames
|
||||
2. Export all frames as GIF
|
||||
3. Use frame durations from Aseprite
|
||||
4. Enable looping
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// Get sprite info to check frames
|
||||
const spriteInfo = mcp__aseprite__get_sprite_info()
|
||||
// Returns: { width: 32, height: 32, frames: 4, ... }
|
||||
|
||||
// Export as animated GIF
|
||||
mcp__aseprite__export_gif({
|
||||
filename: "walk-cycle.gif",
|
||||
fromFrame: 1,
|
||||
toFrame: 4, // All frames
|
||||
loop: true, // Infinite loop
|
||||
useOriginalDuration: true // Use Aseprite frame timings
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
An animated GIF that plays the walk cycle continuously, preserving the timing from Aseprite.
|
||||
|
||||
**Visual Description:**
|
||||
The GIF animates smoothly, cycling through all 4 walk frames indefinitely. Frame timings match what was set in Aseprite (e.g., 100ms per frame). The animation looks exactly as it did in the Aseprite editor.
|
||||
|
||||
---
|
||||
|
||||
### Example 6: Optimized GIF with Reduced Colors
|
||||
|
||||
**User Request:**
|
||||
> "Export my animation as a small GIF file with reduced file size"
|
||||
|
||||
**Approach:**
|
||||
1. Get animation info
|
||||
2. Export with palette optimization
|
||||
3. Reduce color count for smaller file
|
||||
4. Maintain visual quality
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
mcp__aseprite__get_sprite_info()
|
||||
|
||||
// Export GIF with optimized palette
|
||||
mcp__aseprite__export_gif({
|
||||
filename: "optimized-animation.gif",
|
||||
fromFrame: 1,
|
||||
toFrame: 8,
|
||||
loop: true,
|
||||
useOriginalDuration: true,
|
||||
colorQuantization: true, // Optimize palette
|
||||
maxColors: 64, // Reduce from 256 to 64 colors
|
||||
dithering: "floyd-steinberg" // Smooth color transitions
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A smaller GIF file with optimized colors that looks nearly identical to the full-color version.
|
||||
|
||||
**Visual Description:**
|
||||
The GIF plays the animation smoothly with slightly reduced color depth. Floyd-Steinberg dithering creates smooth transitions where colors were reduced. File size is significantly smaller (often 50-70% reduction) while maintaining good visual quality.
|
||||
|
||||
---
|
||||
|
||||
### Example 7: GIF with Specific Frame Range
|
||||
|
||||
**User Request:**
|
||||
> "Export just frames 5-8 of my animation (the attack sequence) as a GIF"
|
||||
|
||||
**Approach:**
|
||||
1. Identify frame range for specific animation
|
||||
2. Export only that range
|
||||
3. Set appropriate loop behavior
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
mcp__aseprite__get_sprite_info()
|
||||
|
||||
// Export specific frame range
|
||||
mcp__aseprite__export_gif({
|
||||
filename: "attack-animation.gif",
|
||||
fromFrame: 5,
|
||||
toFrame: 8, // Just the attack frames
|
||||
loop: false, // Play once (not infinite loop)
|
||||
useOriginalDuration: true
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A GIF containing only the 4-frame attack sequence that plays once and stops.
|
||||
|
||||
**Visual Description:**
|
||||
The GIF shows frames 5-8 of the original animation (the attack move). It plays through once and stops on the last frame rather than looping. Perfect for sharing a specific animation sequence or game move demonstrations.
|
||||
|
||||
---
|
||||
|
||||
## Spritesheet Exports
|
||||
|
||||
### Example 8: Horizontal Strip Spritesheet
|
||||
|
||||
**User Request:**
|
||||
> "Export all my animation frames as a single horizontal strip for my game engine"
|
||||
|
||||
**Approach:**
|
||||
1. Get frame count
|
||||
2. Export as horizontal spritesheet
|
||||
3. Frames arranged left to right
|
||||
4. Include metadata about frame positions
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// Get sprite info
|
||||
const spriteInfo = mcp__aseprite__get_sprite_info()
|
||||
// Returns: { width: 32, height: 32, frames: 8, ... }
|
||||
|
||||
// Export as horizontal strip
|
||||
mcp__aseprite__export_spritesheet({
|
||||
filename: "spritesheet-horizontal.png",
|
||||
sheetType: "horizontal", // All frames in one row
|
||||
fromFrame: 1,
|
||||
toFrame: 8,
|
||||
padding: 0, // No space between frames
|
||||
innerPadding: 0 // No padding inside frames
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A 256x32 PNG (8 frames × 32px wide) with all frames arranged horizontally.
|
||||
|
||||
**Visual Description:**
|
||||
The spritesheet is a wide horizontal image showing all 8 animation frames side by side. Frame 1 starts at x=0, frame 2 at x=32, frame 3 at x=64, and so on. Each frame is 32x32 pixels. The spritesheet is 256 pixels wide by 32 pixels tall.
|
||||
|
||||
---
|
||||
|
||||
### Example 9: Grid Spritesheet with JSON Data
|
||||
|
||||
**User Request:**
|
||||
> "Export my sprites as a grid spritesheet with JSON metadata for frame positions"
|
||||
|
||||
**Approach:**
|
||||
1. Arrange frames in a grid (e.g., 4x2)
|
||||
2. Export PNG spritesheet
|
||||
3. Export accompanying JSON with frame coordinates
|
||||
4. Include frame durations
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// Get sprite info
|
||||
const spriteInfo = mcp__aseprite__get_sprite_info()
|
||||
|
||||
// Export as grid with JSON
|
||||
mcp__aseprite__export_spritesheet({
|
||||
filename: "spritesheet-grid.png",
|
||||
sheetType: "grid",
|
||||
columns: 4, // 4 frames per row
|
||||
rows: 2, // 2 rows
|
||||
fromFrame: 1,
|
||||
toFrame: 8,
|
||||
padding: 1, // 1px space between frames
|
||||
innerPadding: 0,
|
||||
jsonData: true, // Export JSON metadata
|
||||
jsonFilename: "spritesheet-grid.json"
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A 133x65 PNG grid (4×2 frames with padding) plus a JSON file with frame coordinates and timing data.
|
||||
|
||||
**Visual Description:**
|
||||
The spritesheet shows 8 frames arranged in a 4×2 grid. Each frame is separated by 1 pixel of padding. The accompanying JSON file contains:
|
||||
```json
|
||||
{
|
||||
"frames": [
|
||||
{
|
||||
"frame": { "x": 0, "y": 0, "w": 32, "h": 32 },
|
||||
"duration": 100
|
||||
},
|
||||
{
|
||||
"frame": { "x": 33, "y": 0, "w": 32, "h": 32 },
|
||||
"duration": 100
|
||||
},
|
||||
// ... more frames
|
||||
],
|
||||
"meta": {
|
||||
"size": { "w": 133, "h": 65 },
|
||||
"scale": "1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Example 10: Packed Spritesheet for Efficiency
|
||||
|
||||
**User Request:**
|
||||
> "Export my sprites as a tightly packed spritesheet to save texture memory"
|
||||
|
||||
**Approach:**
|
||||
1. Analyze frame sizes
|
||||
2. Use bin-packing algorithm
|
||||
3. Arrange frames efficiently
|
||||
4. Export with JSON coordinates
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// Export with automatic packing
|
||||
mcp__aseprite__export_spritesheet({
|
||||
filename: "spritesheet-packed.png",
|
||||
sheetType: "packed", // Bin-packing algorithm
|
||||
fromFrame: 1,
|
||||
toFrame: 8,
|
||||
padding: 2, // 2px padding for safety
|
||||
powerOfTwo: true, // Force dimensions to power of 2
|
||||
jsonData: true,
|
||||
jsonFilename: "spritesheet-packed.json"
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
An efficiently packed spritesheet (e.g., 64x64 or 128x64) with frames arranged to minimize wasted space, plus JSON coordinates.
|
||||
|
||||
**Visual Description:**
|
||||
The spritesheet uses minimal texture space by packing frames tightly. Frames aren't in a regular grid - they're arranged optimally based on size and shape. The JSON file provides exact coordinates for each frame. The total image size is a power of 2 (64x64, 128x128, etc.) for GPU efficiency.
|
||||
|
||||
---
|
||||
|
||||
### Example 11: Spritesheet with Animation Tags
|
||||
|
||||
**User Request:**
|
||||
> "Export a spritesheet with separate animations (idle, walk, attack) marked in the JSON"
|
||||
|
||||
**Approach:**
|
||||
1. Create spritesheet with all frames
|
||||
2. Export JSON including animation tag ranges
|
||||
3. Organize by animation name
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// Get sprite info including tags
|
||||
const spriteInfo = mcp__aseprite__get_sprite_info()
|
||||
// Returns: { frames: 16, tags: ["idle", "walk", "attack"], ... }
|
||||
|
||||
// Export spritesheet with tag information
|
||||
mcp__aseprite__export_spritesheet({
|
||||
filename: "character-all-animations.png",
|
||||
sheetType: "horizontal",
|
||||
fromFrame: 1,
|
||||
toFrame: 16, // All frames
|
||||
padding: 1,
|
||||
jsonData: true,
|
||||
jsonFilename: "character-all-animations.json",
|
||||
includeTags: true // Include animation tag data in JSON
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A horizontal spritesheet with all 16 frames plus JSON with animation tag ranges.
|
||||
|
||||
**Visual Description:**
|
||||
The spritesheet contains all animations in sequence: idle (frames 1-4), walk (frames 5-8), attack (frames 9-16). The JSON includes:
|
||||
```json
|
||||
{
|
||||
"frames": [ /* frame data */ ],
|
||||
"meta": {
|
||||
"frameTags": [
|
||||
{ "name": "idle", "from": 0, "to": 3 },
|
||||
{ "name": "walk", "from": 4, "to": 7 },
|
||||
{ "name": "attack", "from": 8, "to": 15 }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Game Engine Integration
|
||||
|
||||
### Example 12: Unity Spritesheet Export
|
||||
|
||||
**User Request:**
|
||||
> "Export my animation for Unity with the correct JSON format"
|
||||
|
||||
**Approach:**
|
||||
1. Export spritesheet in Unity-compatible format
|
||||
2. Use Unity's JSON structure
|
||||
3. Include pivot points and frame data
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// Export Unity-compatible spritesheet
|
||||
mcp__aseprite__export_spritesheet({
|
||||
filename: "unity-sprite.png",
|
||||
sheetType: "grid",
|
||||
columns: 4,
|
||||
rows: 2,
|
||||
fromFrame: 1,
|
||||
toFrame: 8,
|
||||
padding: 0,
|
||||
jsonData: true,
|
||||
jsonFilename: "unity-sprite.json",
|
||||
jsonFormat: "unity" // Unity-specific format
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A spritesheet PNG and JSON in Unity's sprite atlas format.
|
||||
|
||||
**Visual Description:**
|
||||
The export creates files that Unity can import directly. The JSON uses Unity's expected structure with sprite names, rectangles, pivots, and borders. In Unity, you can drag the PNG into your project, set it as Multiple sprite mode, and use the JSON to slice it automatically.
|
||||
|
||||
---
|
||||
|
||||
### Example 13: Godot Spritesheet Export
|
||||
|
||||
**User Request:**
|
||||
> "Export my sprites for Godot Engine with proper metadata"
|
||||
|
||||
**Approach:**
|
||||
1. Export spritesheet
|
||||
2. Use Godot-compatible JSON format
|
||||
3. Include region and frame data
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// Export Godot-compatible spritesheet
|
||||
mcp__aseprite__export_spritesheet({
|
||||
filename: "godot-sprite.png",
|
||||
sheetType: "packed",
|
||||
fromFrame: 1,
|
||||
toFrame: 8,
|
||||
padding: 1,
|
||||
jsonData: true,
|
||||
jsonFilename: "godot-sprite.json",
|
||||
jsonFormat: "godot" // Godot-specific format
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A packed spritesheet with Godot-compatible JSON metadata.
|
||||
|
||||
**Visual Description:**
|
||||
The export creates files ready for Godot's AnimatedSprite or SpriteFrames resource. The JSON uses Godot's expected structure. In Godot, you can load this directly into a SpriteFrames resource and reference frames by name in your animations.
|
||||
|
||||
---
|
||||
|
||||
### Example 14: Phaser JSON Hash Export
|
||||
|
||||
**User Request:**
|
||||
> "Export my spritesheet with Phaser 3 compatible JSON hash format"
|
||||
|
||||
**Approach:**
|
||||
1. Export spritesheet
|
||||
2. Use Phaser's JSON hash structure
|
||||
3. Include all frame data with string keys
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// Export Phaser-compatible spritesheet
|
||||
mcp__aseprite__export_spritesheet({
|
||||
filename: "phaser-sprite.png",
|
||||
sheetType: "grid",
|
||||
columns: 4,
|
||||
rows: 2,
|
||||
fromFrame: 1,
|
||||
toFrame: 8,
|
||||
padding: 0,
|
||||
jsonData: true,
|
||||
jsonFilename: "phaser-sprite.json",
|
||||
jsonFormat: "hash" // Phaser JSON hash format
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A spritesheet with Phaser 3 JSON hash format for easy loading.
|
||||
|
||||
**Visual Description:**
|
||||
The JSON uses Phaser's hash format where each frame is a key-value pair:
|
||||
```json
|
||||
{
|
||||
"frames": {
|
||||
"frame0.png": {
|
||||
"frame": { "x": 0, "y": 0, "w": 32, "h": 32 },
|
||||
"rotated": false,
|
||||
"trimmed": false,
|
||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 },
|
||||
"sourceSize": { "w": 32, "h": 32 }
|
||||
},
|
||||
// ... more frames
|
||||
}
|
||||
}
|
||||
```
|
||||
In Phaser, load with: `this.load.atlas('sprite', 'phaser-sprite.png', 'phaser-sprite.json')`
|
||||
|
||||
---
|
||||
|
||||
### Example 15: Export Multiple Animations Separately
|
||||
|
||||
**User Request:**
|
||||
> "Export each of my tagged animations as separate files for easier game engine management"
|
||||
|
||||
**Approach:**
|
||||
1. Get list of animation tags
|
||||
2. Export each tag as separate file
|
||||
3. Create organized file structure
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// Get sprite info with tags
|
||||
const spriteInfo = mcp__aseprite__get_sprite_info()
|
||||
// Returns: { tags: ["idle", "walk", "attack"], ... }
|
||||
|
||||
// Export idle animation
|
||||
mcp__aseprite__export_spritesheet({
|
||||
filename: "character-idle.png",
|
||||
sheetType: "horizontal",
|
||||
tag: "idle", // Export only frames in this tag
|
||||
padding: 0,
|
||||
jsonData: true,
|
||||
jsonFilename: "character-idle.json"
|
||||
})
|
||||
|
||||
// Export walk animation
|
||||
mcp__aseprite__export_spritesheet({
|
||||
filename: "character-walk.png",
|
||||
sheetType: "horizontal",
|
||||
tag: "walk", // Export only frames in this tag
|
||||
padding: 0,
|
||||
jsonData: true,
|
||||
jsonFilename: "character-walk.json"
|
||||
})
|
||||
|
||||
// Export attack animation
|
||||
mcp__aseprite__export_spritesheet({
|
||||
filename: "character-attack.png",
|
||||
sheetType: "horizontal",
|
||||
tag: "attack", // Export only frames in this tag
|
||||
padding: 0,
|
||||
jsonData: true,
|
||||
jsonFilename: "character-attack.json"
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
Three separate spritesheet files, each containing one animation with its own JSON.
|
||||
|
||||
**Visual Description:**
|
||||
The export creates:
|
||||
- `character-idle.png`: 128x32 (4 frames)
|
||||
- `character-walk.png`: 128x32 (4 frames)
|
||||
- `character-attack.png`: 192x32 (6 frames)
|
||||
|
||||
Plus corresponding JSON files. This organization makes it easy to load only needed animations in game engines and manage animation states separately.
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
This examples collection demonstrates the pixel-art-exporter skill's capabilities:
|
||||
|
||||
- **Single images** (Examples 1-4): PNG exports with various options (transparency, backgrounds, scaling, layers)
|
||||
- **Animated GIFs** (Examples 5-7): Full animations, optimized versions, specific frame ranges
|
||||
- **Spritesheets** (Examples 8-11): Horizontal strips, grids, packed layouts, with JSON metadata
|
||||
- **Game engine integration** (Examples 12-15): Unity, Godot, Phaser formats, and organized multi-file exports
|
||||
|
||||
Each example shows complete MCP tool call syntax with practical export scenarios for web, games, and various platforms. The progression demonstrates flexibility from simple PNG exports to complex multi-format game engine pipelines.
|
||||
823
skills/pixel-art-exporter/export-formats.md
Normal file
823
skills/pixel-art-exporter/export-formats.md
Normal file
@@ -0,0 +1,823 @@
|
||||
# Export Formats Reference
|
||||
|
||||
This document provides comprehensive technical specifications for exporting pixel art in various formats, including static images, animated formats, spritesheets, and game engine-specific outputs.
|
||||
|
||||
## PNG Export Options
|
||||
|
||||
PNG (Portable Network Graphics) is the primary format for pixel art due to lossless compression and transparency support.
|
||||
|
||||
### Transparency Handling
|
||||
|
||||
**Full Alpha Channel:**
|
||||
- 8-bit alpha channel (0-255 transparency levels)
|
||||
- Preserves semi-transparent pixels from antialiasing or effects
|
||||
- Essential for overlay sprites, particles, or UI elements
|
||||
- File size increases with alpha complexity
|
||||
|
||||
**Binary Transparency:**
|
||||
- Pixels are either fully opaque (255) or fully transparent (0)
|
||||
- Smaller file size compared to full alpha
|
||||
- Sufficient for most pixel art with hard edges
|
||||
- Compatible with older systems
|
||||
|
||||
**No Transparency:**
|
||||
- All pixels opaque
|
||||
- Smallest file size for PNG
|
||||
- Use when background is always solid
|
||||
- Useful for tiles, backgrounds, or when transparency not needed
|
||||
|
||||
### Background Colors
|
||||
|
||||
**Transparent Background:**
|
||||
- Default for sprites, characters, UI elements
|
||||
- Allows compositing over any background
|
||||
- Required for multi-layer game objects
|
||||
|
||||
**Solid Background:**
|
||||
- Specify hex color (e.g., #FF00FF for magenta)
|
||||
- Useful for preview/reference images
|
||||
- Can use specific color for manual masking later
|
||||
- Common for texture atlases with padding
|
||||
|
||||
**Checkerboard Pattern:**
|
||||
- Not exported, but visible in editor
|
||||
- Indicates transparent areas during editing
|
||||
- Final export still uses true transparency
|
||||
|
||||
### Color Depth Options
|
||||
|
||||
**Indexed Color (8-bit):**
|
||||
- Maximum 256 colors
|
||||
- Smallest file size
|
||||
- Perfect for retro pixel art
|
||||
- Preserves exact palette
|
||||
- Example: NES-style art (54 colors), Game Boy (4 colors)
|
||||
|
||||
**RGB (24-bit):**
|
||||
- 16.7 million colors
|
||||
- No transparency channel
|
||||
- Use when alpha not needed
|
||||
- Moderate file size
|
||||
|
||||
**RGBA (32-bit):**
|
||||
- 16.7 million colors + alpha
|
||||
- Full transparency support
|
||||
- Largest file size
|
||||
- Industry standard for modern games
|
||||
|
||||
### Compression Settings
|
||||
|
||||
**PNG Compression Levels:**
|
||||
- Level 0: No compression (fastest, largest)
|
||||
- Level 1-5: Low compression (fast encoding)
|
||||
- Level 6: Default (balanced)
|
||||
- Level 9: Maximum compression (slowest, smallest)
|
||||
|
||||
**Best Practices:**
|
||||
- Use level 9 for final game assets (one-time cost)
|
||||
- Use level 1-3 for rapid iteration/testing
|
||||
- Compression is lossless at all levels
|
||||
- File size varies by image complexity, not canvas size
|
||||
|
||||
## GIF Export
|
||||
|
||||
GIF format provides animation support with wide compatibility but limited color palette.
|
||||
|
||||
### Frame Timing Control
|
||||
|
||||
**Frame Duration:**
|
||||
- Measured in centiseconds (100ths of a second)
|
||||
- Minimum: 1cs (10ms) - browser limit typically 20ms
|
||||
- Common values: 10cs (100ms), 5cs (50ms), 20cs (200ms)
|
||||
- Per-frame timing allows variable animation speeds
|
||||
|
||||
**Timing Examples:**
|
||||
```
|
||||
Walking cycle: 10cs per frame (10 FPS)
|
||||
Idle breathing: 30cs per frame (3.3 FPS)
|
||||
Fast attack: 5cs per frame (20 FPS)
|
||||
Slow blink: [50cs, 5cs, 50cs] (hold, blink, hold)
|
||||
```
|
||||
|
||||
**Aseprite Frame Duration:**
|
||||
- Set in timeline (milliseconds in Aseprite)
|
||||
- Export converts to centiseconds
|
||||
- Maintains exact timing in GIF output
|
||||
|
||||
### Looping Options
|
||||
|
||||
**Infinite Loop:**
|
||||
- Default for game sprites
|
||||
- NETSCAPE2.0 extension with loop count 0
|
||||
- Plays continuously until stopped
|
||||
- Standard for web animations
|
||||
|
||||
**Count-Based Looping:**
|
||||
- Specify exact number of repetitions
|
||||
- Example: Loop 3 times then stop
|
||||
- Useful for intro animations, effects
|
||||
- Browser support varies
|
||||
|
||||
**No Loop (Play Once):**
|
||||
- Loop count set to 1
|
||||
- Stops on final frame
|
||||
- Good for cutscenes, transitions
|
||||
- Fallback: some viewers may still loop
|
||||
|
||||
### Color Quantization for GIF
|
||||
|
||||
**256 Color Limitation:**
|
||||
- GIF maximum palette size
|
||||
- Quantization reduces full-color to 256 colors
|
||||
- Critical consideration when exporting from 24-bit source
|
||||
|
||||
**Quantization Algorithms:**
|
||||
|
||||
**Global Palette:**
|
||||
- Single 256-color palette for all frames
|
||||
- Ensures color consistency across animation
|
||||
- Analyze all frames to build optimal palette
|
||||
- Best for most pixel art animations
|
||||
|
||||
**Local Palette:**
|
||||
- Different palette per frame
|
||||
- Allows more colors across animation
|
||||
- Can cause color shifting/flickering
|
||||
- Rarely appropriate for pixel art
|
||||
|
||||
**Dithering Options:**
|
||||
- **None**: Hard color boundaries (best for pixel art)
|
||||
- **Floyd-Steinberg**: Error diffusion, adds noise
|
||||
- **Ordered**: Pattern-based, creates artifacts
|
||||
- **Recommendation**: Disable dithering for pixel art
|
||||
|
||||
### Optimization Techniques
|
||||
|
||||
**Frame Disposal Methods:**
|
||||
- **Restore to Background**: Clear before next frame
|
||||
- **Do Not Dispose**: Keep previous frame
|
||||
- **Restore to Previous**: Revert to prior state
|
||||
|
||||
**Delta Frame Encoding:**
|
||||
- Only encode changed pixels between frames
|
||||
- Significant size reduction for small changes
|
||||
- Automatic in most GIF encoders
|
||||
- Example: Idle animation (80% size reduction)
|
||||
|
||||
**Transparency Optimization:**
|
||||
- Designate one color as transparent
|
||||
- Reduce file size by not encoding unchanged areas
|
||||
- Works with delta encoding
|
||||
- Choose unused color for transparency index
|
||||
|
||||
**Size Reduction Checklist:**
|
||||
- Use global palette
|
||||
- Enable delta encoding
|
||||
- Minimize frame dimensions (crop to animation bounds)
|
||||
- Reduce frame count if possible
|
||||
- Lower frame rate for slower animations
|
||||
|
||||
### File Size Considerations
|
||||
|
||||
**Size Factors:**
|
||||
```
|
||||
Small (1-50 KB): 16×16 sprite, 4-8 frames, simple movement
|
||||
Medium (50-200 KB): 32×32 sprite, 10-20 frames, detailed animation
|
||||
Large (200KB-1MB): 64×64+ sprite, 30+ frames, complex animation
|
||||
```
|
||||
|
||||
**Optimization Trade-offs:**
|
||||
- Frame count vs. smoothness
|
||||
- Canvas size vs. detail
|
||||
- Frame rate vs. file size
|
||||
- Color count vs. palette accuracy
|
||||
|
||||
## Spritesheet Layouts
|
||||
|
||||
Spritesheets combine multiple frames or sprites into a single image for efficient loading and rendering.
|
||||
|
||||
### Horizontal Strip
|
||||
|
||||
All frames arranged in a single horizontal row.
|
||||
|
||||
```
|
||||
+----+----+----+----+----+
|
||||
| F1 | F2 | F3 | F4 | F5 |
|
||||
+----+----+----+----+----+
|
||||
```
|
||||
|
||||
**Use Cases:**
|
||||
- Simple animations (walk, run, jump)
|
||||
- Scrolling backgrounds
|
||||
- UI button states
|
||||
|
||||
**Advantages:**
|
||||
- Simple to parse (X offset only)
|
||||
- Easy to calculate frame position: `frame_x = frame_index * frame_width`
|
||||
- Good for texture atlases with power-of-2 heights
|
||||
|
||||
**Disadvantages:**
|
||||
- Very wide images with many frames
|
||||
- Inefficient for non-power-of-2 widths
|
||||
- GPU texture size limits (typically 4096-8192px)
|
||||
|
||||
### Vertical Strip
|
||||
|
||||
All frames arranged in a single vertical column.
|
||||
|
||||
```
|
||||
+----+
|
||||
| F1 |
|
||||
+----+
|
||||
| F2 |
|
||||
+----+
|
||||
| F3 |
|
||||
+----+
|
||||
| F4 |
|
||||
+----+
|
||||
```
|
||||
|
||||
**Use Cases:**
|
||||
- Mobile-optimized layouts
|
||||
- Vertical scrolling effects
|
||||
- Legacy systems preferring tall textures
|
||||
|
||||
**Advantages:**
|
||||
- Simple to parse (Y offset only)
|
||||
- Frame position: `frame_y = frame_index * frame_height`
|
||||
- Better for portrait-oriented displays
|
||||
|
||||
**Disadvantages:**
|
||||
- Very tall images
|
||||
- Less common than horizontal
|
||||
- Same texture size constraints
|
||||
|
||||
### Grid Layout
|
||||
|
||||
Frames arranged in rows and columns.
|
||||
|
||||
```
|
||||
+----+----+----+----+
|
||||
| F1 | F2 | F3 | F4 |
|
||||
+----+----+----+----+
|
||||
| F5 | F6 | F7 | F8 |
|
||||
+----+----+----+----+
|
||||
| F9 | 10 | 11 | 12 |
|
||||
+----+----+----+----+
|
||||
```
|
||||
|
||||
**Configuration:**
|
||||
- Rows: Number of vertical divisions
|
||||
- Columns: Number of horizontal divisions
|
||||
- Example: 4 columns × 3 rows = 12 frames
|
||||
|
||||
**Frame Calculation:**
|
||||
```python
|
||||
frame_x = (frame_index % columns) * frame_width
|
||||
frame_y = (frame_index // columns) * frame_height
|
||||
```
|
||||
|
||||
**Use Cases:**
|
||||
- Large animation sets (16+ frames)
|
||||
- Multiple animations in one sheet
|
||||
- Power-of-2 texture optimization
|
||||
|
||||
**Advantages:**
|
||||
- Balanced dimensions (square or near-square)
|
||||
- GPU-friendly (easier to fit power-of-2)
|
||||
- Compact representation
|
||||
|
||||
**Best Practices:**
|
||||
- Use power-of-2 dimensions: 256×256, 512×512, 1024×1024
|
||||
- Add padding between frames (1-2px) to prevent bleeding
|
||||
- Organize by animation (row per animation type)
|
||||
|
||||
### Packed Layout
|
||||
|
||||
Optimal space usage with variable frame positions.
|
||||
|
||||
```
|
||||
+--------+----+----+
|
||||
| | F3 | F4 |
|
||||
| F1 +----+----+
|
||||
| | F5 | F6 |
|
||||
+----+---+----+----+
|
||||
| F2 | F7 | F8|
|
||||
+----+---------+---+
|
||||
```
|
||||
|
||||
**Characteristics:**
|
||||
- Frames positioned to minimize whitespace
|
||||
- Requires metadata for frame positions
|
||||
- Non-uniform layout
|
||||
|
||||
**Algorithms:**
|
||||
- **Maxrects**: Maximum rectangles bin packing
|
||||
- **Skyline**: Skyline bottom-left heuristic
|
||||
- **Guillotine**: Recursive subdivision
|
||||
|
||||
**Use Cases:**
|
||||
- Variable-size sprites (UI elements, items)
|
||||
- Texture atlases with many assets
|
||||
- Maximizing GPU texture memory
|
||||
|
||||
**Advantages:**
|
||||
- Smallest total texture size
|
||||
- Efficient memory usage
|
||||
- Professional game asset pipelines
|
||||
|
||||
**Disadvantages:**
|
||||
- Requires JSON/XML metadata
|
||||
- More complex to parse
|
||||
- Not suitable for uniform animations
|
||||
|
||||
**Metadata Example:**
|
||||
```json
|
||||
{
|
||||
"frame1": {"x": 0, "y": 0, "w": 32, "h": 64},
|
||||
"frame2": {"x": 0, "y": 64, "w": 16, "h": 16},
|
||||
"frame3": {"x": 32, "y": 0, "w": 16, "h": 16}
|
||||
}
|
||||
```
|
||||
|
||||
## JSON Metadata Formats
|
||||
|
||||
JSON files provide frame data, animation metadata, and asset information for game engines.
|
||||
|
||||
### Aseprite JSON Format
|
||||
|
||||
Native format exported by Aseprite with comprehensive metadata.
|
||||
|
||||
```json
|
||||
{
|
||||
"frames": {
|
||||
"sprite_0.aseprite": {
|
||||
"frame": {"x": 0, "y": 0, "w": 32, "h": 32},
|
||||
"rotated": false,
|
||||
"trimmed": false,
|
||||
"spriteSourceSize": {"x": 0, "y": 0, "w": 32, "h": 32},
|
||||
"sourceSize": {"w": 32, "h": 32},
|
||||
"duration": 100
|
||||
},
|
||||
"sprite_1.aseprite": {
|
||||
"frame": {"x": 32, "y": 0, "w": 32, "h": 32},
|
||||
"rotated": false,
|
||||
"trimmed": false,
|
||||
"spriteSourceSize": {"x": 0, "y": 0, "w": 32, "h": 32},
|
||||
"sourceSize": {"w": 32, "h": 32},
|
||||
"duration": 100
|
||||
}
|
||||
},
|
||||
"meta": {
|
||||
"app": "http://www.aseprite.org/",
|
||||
"version": "1.3.0",
|
||||
"image": "sprite.png",
|
||||
"format": "RGBA8888",
|
||||
"size": {"w": 128, "h": 32},
|
||||
"scale": "1",
|
||||
"frameTags": [
|
||||
{
|
||||
"name": "walk",
|
||||
"from": 0,
|
||||
"to": 3,
|
||||
"direction": "forward"
|
||||
}
|
||||
],
|
||||
"layers": [
|
||||
{"name": "Layer 1", "opacity": 255, "blendMode": "normal"}
|
||||
],
|
||||
"slices": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Key Fields:**
|
||||
- `frames`: Per-frame data with positions and durations
|
||||
- `frameTags`: Animation sequences (walk, run, idle)
|
||||
- `direction`: forward, reverse, pingpong
|
||||
- `duration`: Frame duration in milliseconds
|
||||
|
||||
### TexturePacker JSON Format
|
||||
|
||||
Industry-standard format used by many tools and engines.
|
||||
|
||||
```json
|
||||
{
|
||||
"frames": {
|
||||
"hero_walk_00.png": {
|
||||
"frame": {"x": 2, "y": 2, "w": 32, "h": 32},
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": {"x": 2, "y": 1, "w": 32, "h": 32},
|
||||
"sourceSize": {"w": 36, "h": 34},
|
||||
"pivot": {"x": 0.5, "y": 0.5}
|
||||
}
|
||||
},
|
||||
"meta": {
|
||||
"app": "https://www.codeandweb.com/texturepacker",
|
||||
"version": "1.0",
|
||||
"image": "spritesheet.png",
|
||||
"format": "RGBA8888",
|
||||
"size": {"w": 512, "h": 512},
|
||||
"scale": "1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Key Features:**
|
||||
- `trimmed`: Indicates if transparent pixels were removed
|
||||
- `spriteSourceSize`: Position of trimmed sprite in original
|
||||
- `pivot`: Rotation/scaling origin point (0-1 normalized)
|
||||
- Widely supported by game frameworks
|
||||
|
||||
### Unity Sprite Atlas Format
|
||||
|
||||
Unity-specific JSON structure for sprite atlases.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "PlayerAtlas",
|
||||
"spriteSheet": {
|
||||
"sprites": [
|
||||
{
|
||||
"name": "player_idle_0",
|
||||
"rect": {"x": 0, "y": 0, "width": 32, "height": 32},
|
||||
"pivot": {"x": 0.5, "y": 0},
|
||||
"border": {"x": 0, "y": 0, "z": 0, "w": 0},
|
||||
"alignment": 7,
|
||||
"pixelsPerUnit": 32
|
||||
},
|
||||
{
|
||||
"name": "player_idle_1",
|
||||
"rect": {"x": 32, "y": 0, "width": 32, "height": 32},
|
||||
"pivot": {"x": 0.5, "y": 0},
|
||||
"border": {"x": 0, "y": 0, "z": 0, "w": 0},
|
||||
"alignment": 7,
|
||||
"pixelsPerUnit": 32
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Unity-Specific Fields:**
|
||||
- `pixelsPerUnit`: Sprite resolution (typically 32 or 100)
|
||||
- `alignment`: Pivot preset (7 = bottom-center)
|
||||
- `border`: 9-slice borders for UI scaling
|
||||
- Compatible with Unity's SpriteAtlas system
|
||||
|
||||
### Godot SpriteFrames Format
|
||||
|
||||
Godot engine's resource format for AnimatedSprite nodes.
|
||||
|
||||
```json
|
||||
{
|
||||
"frames": [
|
||||
{
|
||||
"name": "walk",
|
||||
"frames": [
|
||||
{"texture": "res://sprites/player_walk_0.png", "duration": 0.1},
|
||||
{"texture": "res://sprites/player_walk_1.png", "duration": 0.1},
|
||||
{"texture": "res://sprites/player_walk_2.png", "duration": 0.1},
|
||||
{"texture": "res://sprites/player_walk_3.png", "duration": 0.1}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "idle",
|
||||
"frames": [
|
||||
{"texture": "res://sprites/player_idle_0.png", "duration": 0.5},
|
||||
{"texture": "res://sprites/player_idle_1.png", "duration": 0.5}
|
||||
]
|
||||
}
|
||||
],
|
||||
"speed": 10.0,
|
||||
"loop": true
|
||||
}
|
||||
```
|
||||
|
||||
**Godot Features:**
|
||||
- Animation-based organization (not single frames)
|
||||
- Per-frame duration in seconds
|
||||
- Global speed multiplier
|
||||
- Directly compatible with AnimatedSprite node
|
||||
|
||||
## Scaling Considerations
|
||||
|
||||
Pixel art requires special handling when scaling to maintain crisp, pixel-perfect appearance.
|
||||
|
||||
### Nearest-Neighbor Algorithm
|
||||
|
||||
**How It Works:**
|
||||
- Each output pixel uses value from closest input pixel
|
||||
- No interpolation or blending
|
||||
- Preserves hard edges and exact colors
|
||||
|
||||
**Mathematical Definition:**
|
||||
```
|
||||
output[x, y] = input[floor(x / scale), floor(y / scale)]
|
||||
```
|
||||
|
||||
**Results:**
|
||||
- Perfectly sharp pixels
|
||||
- No color bleeding or artifacts
|
||||
- Integer scales produce perfect results
|
||||
- Non-integer scales may show uneven pixels
|
||||
|
||||
**Essential for Pixel Art:**
|
||||
- Maintains artistic intent
|
||||
- Preserves hand-placed pixels
|
||||
- No blur or antialiasing
|
||||
- Industry standard for retro aesthetics
|
||||
|
||||
### Why Other Algorithms Blur Pixels
|
||||
|
||||
**Bilinear Interpolation:**
|
||||
- Averages 4 nearest pixels
|
||||
- Creates smooth gradients
|
||||
- **Problem**: Blurs pixel art edges
|
||||
- Use case: Photography, 3D textures
|
||||
|
||||
**Bicubic Interpolation:**
|
||||
- Averages 16 nearest pixels
|
||||
- Even smoother than bilinear
|
||||
- **Problem**: Severe blurring for pixel art
|
||||
- Use case: High-quality photo scaling
|
||||
|
||||
**Lanczos Resampling:**
|
||||
- Advanced algorithm, high quality
|
||||
- **Problem**: Introduces ringing artifacts
|
||||
- Use case: Photographic downscaling
|
||||
|
||||
**Visual Comparison:**
|
||||
```
|
||||
Original (8×8): Nearest (16×16): Bilinear (16×16):
|
||||
████████ ████████████████ ░░░░░░░░░░░░░░░░
|
||||
██ ██ ████ ████ ░░██ ██░░
|
||||
██ ██ ------> ████ ████ ░░██ ██░░
|
||||
████████ ████████████████ ░░░░░░░░░░░░░░░░
|
||||
(Sharp edges) (Sharp edges) (Blurred edges)
|
||||
```
|
||||
|
||||
### Common Scale Factors
|
||||
|
||||
**Integer Scales (Recommended):**
|
||||
- **1x**: Native resolution (32×32 remains 32×32)
|
||||
- **2x**: Double size (32×32 becomes 64×64)
|
||||
- **4x**: Quad size (32×32 becomes 128×128)
|
||||
- **8x**: Octo size (32×32 becomes 256×256)
|
||||
|
||||
**Benefits:**
|
||||
- Perfect pixel mapping (1 source pixel → N×N output pixels)
|
||||
- No distortion or uneven pixels
|
||||
- Crisp, clean appearance
|
||||
|
||||
**Non-Integer Scales (Use with Caution):**
|
||||
- **1.5x**: Some pixels larger than others
|
||||
- **3x**: Still integer, good quality
|
||||
- **2.5x**: Uneven pixel sizes, slight distortion
|
||||
|
||||
**Best Practices:**
|
||||
- Prefer integer scales (2x, 3x, 4x)
|
||||
- Design base sprites at smallest playable size
|
||||
- Scale up for high-DPI displays
|
||||
- Use viewport/camera scaling instead of asset scaling when possible
|
||||
|
||||
### Maintaining Pixel-Perfect Appearance
|
||||
|
||||
**Canvas Alignment:**
|
||||
- Position sprites on integer coordinates
|
||||
- Avoid sub-pixel positioning (0.5, 1.3, etc.)
|
||||
- Round camera position to integers
|
||||
|
||||
**Viewport Scaling:**
|
||||
- Scale entire game viewport, not individual sprites
|
||||
- Maintain aspect ratio
|
||||
- Use integer scale factors
|
||||
|
||||
**Export Settings:**
|
||||
- Disable antialiasing
|
||||
- Use nearest-neighbor filter
|
||||
- Set texture filtering to "Point" or "Nearest"
|
||||
|
||||
**GPU Texture Settings:**
|
||||
- Mag Filter: Nearest/Point
|
||||
- Min Filter: Nearest/Point (not Mipmap)
|
||||
- Wrap Mode: Clamp or Repeat as needed
|
||||
|
||||
## Game Engine Integration Examples
|
||||
|
||||
### Unity
|
||||
|
||||
**Import Settings:**
|
||||
```
|
||||
Texture Type: Sprite (2D and UI)
|
||||
Sprite Mode: Multiple (for spritesheets)
|
||||
Pixels Per Unit: 32 (or native sprite size)
|
||||
Filter Mode: Point (no filter)
|
||||
Compression: None
|
||||
Format: RGBA 32 bit
|
||||
```
|
||||
|
||||
**Sprite Atlas Usage:**
|
||||
```csharp
|
||||
using UnityEngine;
|
||||
|
||||
public class SpriteAnimator : MonoBehaviour
|
||||
{
|
||||
public Sprite[] walkFrames;
|
||||
private SpriteRenderer spriteRenderer;
|
||||
private int currentFrame = 0;
|
||||
private float frameTimer = 0f;
|
||||
private float frameDuration = 0.1f;
|
||||
|
||||
void Start()
|
||||
{
|
||||
spriteRenderer = GetComponent<SpriteRenderer>();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
frameTimer += Time.deltaTime;
|
||||
if (frameTimer >= frameDuration)
|
||||
{
|
||||
frameTimer = 0f;
|
||||
currentFrame = (currentFrame + 1) % walkFrames.Length;
|
||||
spriteRenderer.sprite = walkFrames[currentFrame];
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Godot
|
||||
|
||||
**SpriteFrames Setup:**
|
||||
```gdscript
|
||||
# Import spritesheet
|
||||
var texture = preload("res://sprites/player.png")
|
||||
|
||||
# Create SpriteFrames resource
|
||||
var sprite_frames = SpriteFrames.new()
|
||||
|
||||
# Add animation
|
||||
sprite_frames.add_animation("walk")
|
||||
sprite_frames.set_animation_speed("walk", 10.0)
|
||||
|
||||
# Add frames (assume 32×32 frames in horizontal strip)
|
||||
for i in range(4):
|
||||
var atlas = AtlasTexture.new()
|
||||
atlas.atlas = texture
|
||||
atlas.region = Rect2(i * 32, 0, 32, 32)
|
||||
sprite_frames.add_frame("walk", atlas, i)
|
||||
```
|
||||
|
||||
**AnimatedSprite Configuration:**
|
||||
```gdscript
|
||||
extends AnimatedSprite
|
||||
|
||||
func _ready():
|
||||
# Disable filtering for pixel-perfect
|
||||
texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
|
||||
|
||||
# Play animation
|
||||
play("walk")
|
||||
```
|
||||
|
||||
**Project Settings:**
|
||||
```
|
||||
Rendering > Textures > Canvas Textures > Default Texture Filter: Nearest
|
||||
Display > Window > Stretch > Mode: viewport
|
||||
Display > Window > Stretch > Aspect: keep
|
||||
```
|
||||
|
||||
### Phaser
|
||||
|
||||
**Loading Spritesheet:**
|
||||
```javascript
|
||||
class GameScene extends Phaser.Scene {
|
||||
preload() {
|
||||
// Load spritesheet
|
||||
this.load.spritesheet('player', 'assets/player.png', {
|
||||
frameWidth: 32,
|
||||
frameHeight: 32
|
||||
});
|
||||
}
|
||||
|
||||
create() {
|
||||
// Create animation from frames 0-3
|
||||
this.anims.create({
|
||||
key: 'walk',
|
||||
frames: this.anims.generateFrameNumbers('player', {
|
||||
start: 0,
|
||||
end: 3
|
||||
}),
|
||||
frameRate: 10,
|
||||
repeat: -1
|
||||
});
|
||||
|
||||
// Create sprite
|
||||
const player = this.add.sprite(100, 100, 'player');
|
||||
player.play('walk');
|
||||
|
||||
// Disable texture smoothing for pixel-perfect
|
||||
player.setTexture('player').setOrigin(0.5, 0.5);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Game Configuration:**
|
||||
```javascript
|
||||
const config = {
|
||||
type: Phaser.AUTO,
|
||||
width: 800,
|
||||
height: 600,
|
||||
pixelArt: true, // Enables nearest-neighbor filtering
|
||||
render: {
|
||||
antialias: false,
|
||||
pixelArt: true
|
||||
},
|
||||
scene: [GameScene]
|
||||
};
|
||||
|
||||
const game = new Phaser.Game(config);
|
||||
```
|
||||
|
||||
### Generic Engine Patterns
|
||||
|
||||
**Frame-Based Animation Loop:**
|
||||
```javascript
|
||||
class Animation {
|
||||
constructor(frames, frameDuration) {
|
||||
this.frames = frames; // Array of frame data {x, y, w, h}
|
||||
this.frameDuration = frameDuration; // Milliseconds per frame
|
||||
this.currentFrame = 0;
|
||||
this.elapsedTime = 0;
|
||||
}
|
||||
|
||||
update(deltaTime) {
|
||||
this.elapsedTime += deltaTime;
|
||||
if (this.elapsedTime >= this.frameDuration) {
|
||||
this.elapsedTime = 0;
|
||||
this.currentFrame = (this.currentFrame + 1) % this.frames.length;
|
||||
}
|
||||
}
|
||||
|
||||
getCurrentFrame() {
|
||||
return this.frames[this.currentFrame];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Spritesheet Rendering:**
|
||||
```javascript
|
||||
function drawSprite(context, image, frame, x, y, scale) {
|
||||
// Use nearest-neighbor scaling
|
||||
context.imageSmoothingEnabled = false;
|
||||
|
||||
context.drawImage(
|
||||
image,
|
||||
frame.x, frame.y, frame.w, frame.h, // Source
|
||||
Math.floor(x), Math.floor(y), // Destination (integer coords)
|
||||
frame.w * scale, frame.h * scale // Scaled size
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
**JSON Metadata Parsing:**
|
||||
```javascript
|
||||
async function loadSpritesheet(imagePath, jsonPath) {
|
||||
const [image, metadata] = await Promise.all([
|
||||
loadImage(imagePath),
|
||||
fetch(jsonPath).then(r => r.json())
|
||||
]);
|
||||
|
||||
const animations = {};
|
||||
|
||||
// Parse Aseprite JSON format
|
||||
for (const tag of metadata.meta.frameTags) {
|
||||
const frames = [];
|
||||
for (let i = tag.from; i <= tag.to; i++) {
|
||||
const frameKey = Object.keys(metadata.frames)[i];
|
||||
const frameData = metadata.frames[frameKey];
|
||||
frames.push({
|
||||
x: frameData.frame.x,
|
||||
y: frameData.frame.y,
|
||||
w: frameData.frame.w,
|
||||
h: frameData.frame.h,
|
||||
duration: frameData.duration
|
||||
});
|
||||
}
|
||||
animations[tag.name] = new Animation(frames, frames[0].duration);
|
||||
}
|
||||
|
||||
return { image, animations };
|
||||
}
|
||||
```
|
||||
|
||||
**Best Practices Summary:**
|
||||
- Always disable texture filtering (use nearest/point)
|
||||
- Position sprites on integer pixel coordinates
|
||||
- Use integer scale factors
|
||||
- Set `imageSmoothingEnabled = false` for canvas
|
||||
- Configure engine for pixel-perfect rendering
|
||||
- Load metadata alongside spritesheet images
|
||||
- Cache parsed animations for performance
|
||||
376
skills/pixel-art-professional/SKILL.md
Normal file
376
skills/pixel-art-professional/SKILL.md
Normal file
@@ -0,0 +1,376 @@
|
||||
---
|
||||
name: Pixel Art Professional
|
||||
description: Apply advanced pixel art techniques including dithering, palette optimization, shading, antialiasing, and color theory. Use when the user mentions "dithering", "dither", "Bayer", "Floyd-Steinberg", "palette", "colors", "reduce colors", "optimize palette", "color limit", "shading", "shadows", "highlights", "lighting", "light source", "antialiasing", "smooth", "smoothing", "anti-alias", "AA", "color ramp", "gradient", "hue shifting", "saturation", "value", "contrast", or wants to "refine", "polish", "improve", "enhance", "make better", "add depth", "add dimension" to existing pixel art. Trigger on retro palette names (NES, Game Boy, C64, PICO-8), texture terms ("metal", "fabric", "stone", "wood"), and visual quality terms ("professional", "clean", "smooth", "vibrant").
|
||||
allowed-tools: Read, Bash, mcp__aseprite__get_sprite_info, mcp__aseprite__draw_pixels, mcp__aseprite__set_palette, mcp__aseprite__get_palette, mcp__aseprite__quantize_palette, mcp__aseprite__apply_auto_shading, mcp__aseprite__draw_with_dither, mcp__aseprite__add_layer, mcp__aseprite__flatten_layers
|
||||
---
|
||||
|
||||
# Pixel Art Professional
|
||||
|
||||
## Overview
|
||||
|
||||
This Skill provides advanced pixel art techniques for refining and polishing sprites. It handles dithering patterns, palette optimization, color theory, shading techniques, and antialiasing for professional-quality pixel art.
|
||||
|
||||
## When to Use
|
||||
|
||||
Use this Skill when the user:
|
||||
- Wants to apply "dithering" or mentions dither patterns
|
||||
- Asks about "palette optimization" or "color reduction"
|
||||
- Mentions "shading", "highlights", "shadows", or "lighting"
|
||||
- Requests "antialiasing", "smoothing", or "edge refinement"
|
||||
- Talks about "color ramps", "gradients", or "color theory"
|
||||
- Wants to "polish" or "refine" existing pixel art
|
||||
- Mentions specific techniques like "Bayer dithering" or "Floyd-Steinberg"
|
||||
|
||||
**Trigger Keywords:** dithering, palette, shading, antialiasing, smooth, gradient, color ramp, polish, refine, color theory, quantize
|
||||
|
||||
## Instructions
|
||||
|
||||
### 1. Understanding Dithering
|
||||
|
||||
**Dithering** creates the illusion of additional colors by mixing pixels of available colors in patterns.
|
||||
|
||||
**When to Use Dithering:**
|
||||
- Reducing color count (e.g., 256 colors → 16 colors)
|
||||
- Creating smooth gradients with limited palettes
|
||||
- Simulating textures (fabric, metal, stone)
|
||||
- Retro aesthetic (classic games used dithering extensively)
|
||||
|
||||
**Dithering Algorithms:**
|
||||
|
||||
**Ordered Dithering (Bayer Matrix):**
|
||||
- Uses fixed pattern matrix (2x2, 4x4, 8x8)
|
||||
- Predictable, regular pattern
|
||||
- Best for: textures, backgrounds, retro look
|
||||
- Fast and consistent
|
||||
|
||||
**Error Diffusion (Floyd-Steinberg):**
|
||||
- Distributes color error to neighboring pixels
|
||||
- More organic, less regular pattern
|
||||
- Best for: gradients, natural images, smooth transitions
|
||||
- Slower but higher quality
|
||||
|
||||
**Common Dithering Patterns:**
|
||||
- **Checkerboard**: Simple 2-color alternating pattern
|
||||
- **Bayer 2x2**: Basic ordered dithering
|
||||
- **Bayer 4x4**: More subtle ordered dithering
|
||||
- **Bayer 8x8**: Very subtle, near-gradient appearance
|
||||
- **Floyd-Steinberg**: Error diffusion for smooth gradients
|
||||
|
||||
### 2. Palette Management
|
||||
|
||||
**Color Quantization:**
|
||||
Use `mcp__aseprite__quantize_palette` to reduce sprite colors intelligently:
|
||||
- Analyzes sprite colors
|
||||
- Finds optimal limited palette
|
||||
- Remaps pixels to new palette
|
||||
- Preserves visual quality
|
||||
|
||||
**Palette Optimization Workflow:**
|
||||
1. Get current sprite info and palette
|
||||
2. Decide target color count (4, 8, 16, 32, 64, 256)
|
||||
3. Apply quantization with optional dithering
|
||||
4. Review and adjust palette if needed
|
||||
|
||||
**Common Palette Sizes:**
|
||||
- **4 colors**: Game Boy, ZX Spectrum per-sprite
|
||||
- **8 colors**: CGA, early arcade
|
||||
- **16 colors**: NES, Master System, early VGA
|
||||
- **32 colors**: SNES per-background, Amiga OCS
|
||||
- **64 colors**: Genesis, PC Engine
|
||||
- **256 colors**: VGA, SNES full palette, Amiga AGA
|
||||
|
||||
**Palette Theory:**
|
||||
- **Color Ramps**: Gradual transitions from dark to light for shading
|
||||
- **Hue Shifting**: Changing hue slightly in shadows/highlights for vibrant look
|
||||
- **Saturation**: Higher saturation in midtones, lower in shadows/highlights
|
||||
- **Contrast**: Ensure sufficient contrast between key elements
|
||||
|
||||
### 3. Shading Techniques
|
||||
|
||||
**Types of Shading:**
|
||||
|
||||
**Flat Shading (No Shading):**
|
||||
- Single color per surface
|
||||
- Simple, iconic look
|
||||
- Best for: UI icons, simple sprites, minimalist style
|
||||
|
||||
**Cell Shading (Hard Shading):**
|
||||
- Distinct color bands with hard edges
|
||||
- 2-3 colors per surface (base, shadow, highlight)
|
||||
- Best for: cartoon style, bold graphics, readable sprites
|
||||
|
||||
**Soft Shading (Dithered Shading):**
|
||||
- Gradual transitions using dithering
|
||||
- Smooth appearance with limited colors
|
||||
- Best for: realistic look, smooth surfaces, gradients
|
||||
|
||||
**Pixel Clusters:**
|
||||
- Manual dithering with strategic pixel placement
|
||||
- Organic, hand-crafted appearance
|
||||
- Best for: metal, fabric textures, custom look
|
||||
|
||||
**Shading Workflow:**
|
||||
1. Identify light source direction
|
||||
2. Determine base color
|
||||
3. Create darker shade for shadows (hue shift toward blue/purple)
|
||||
4. Create lighter shade for highlights (hue shift toward yellow/white)
|
||||
5. Apply shadows on surfaces away from light
|
||||
6. Apply highlights on surfaces toward light
|
||||
7. Add reflected light in deep shadows (subtle)
|
||||
|
||||
**Common Shading Mistakes:**
|
||||
- Pure black shadows (use dark hue-shifted colors instead)
|
||||
- Pure white highlights (use light tinted colors instead)
|
||||
- No hue shifting (shadows/highlights same hue as base)
|
||||
- Pillow shading (shading around edges instead of from light source)
|
||||
|
||||
### 4. Antialiasing
|
||||
|
||||
**Purpose**: Smooth jagged edges and diagonal lines by adding intermediate colors.
|
||||
|
||||
**When to Use Antialiasing:**
|
||||
- Diagonal lines look jagged
|
||||
- Curves appear stepped
|
||||
- Edges need smoothing
|
||||
- Higher resolution sprites (64x64+)
|
||||
|
||||
**When NOT to Use Antialiasing:**
|
||||
- Very small sprites (16x16 or smaller)
|
||||
- Intentional pixelated aesthetic
|
||||
- High-contrast situations (AA reduces contrast)
|
||||
- Limited palette (need intermediate colors)
|
||||
|
||||
**Manual Antialiasing Technique:**
|
||||
1. Identify jagged edge
|
||||
2. Find intermediate color between edge and background
|
||||
3. Place intermediate pixels at edge "steps"
|
||||
4. Use 1-pixel wide AA (avoid thick fuzzy edges)
|
||||
5. AA selectively (not every edge needs it)
|
||||
|
||||
**Automated Antialiasing:**
|
||||
- Some tools offer automatic edge smoothing
|
||||
- Use with caution (can blur intended sharpness)
|
||||
- Manual AA gives better control
|
||||
|
||||
### 5. Color Theory for Pixel Art
|
||||
|
||||
**HSV/HSB Model:**
|
||||
- **Hue**: Color type (red, blue, green, etc.)
|
||||
- **Saturation**: Color intensity (vivid vs. gray)
|
||||
- **Value/Brightness**: Lightness (dark vs. light)
|
||||
|
||||
**Creating Color Ramps:**
|
||||
1. Start with base color (midtone)
|
||||
2. Create shadow: lower value, optionally shift hue toward cool (blue/purple)
|
||||
3. Create highlight: raise value, optionally shift hue toward warm (yellow/white)
|
||||
4. Create midtone between base and shadow
|
||||
5. Create midtone between base and highlight
|
||||
6. Result: 5-color ramp (deep shadow, shadow, base, highlight, bright highlight)
|
||||
|
||||
**Hue Shifting:**
|
||||
- Shadows: shift toward blue, purple, or complementary color
|
||||
- Highlights: shift toward yellow, orange, or light source color
|
||||
- Creates vibrant, lively colors instead of flat gradients
|
||||
|
||||
**Contrast:**
|
||||
- Ensure important elements have high value contrast
|
||||
- Background should contrast with foreground
|
||||
- Silhouette should be readable in solid black
|
||||
|
||||
**Color Harmony:**
|
||||
- **Monochromatic**: Variations of single hue
|
||||
- **Analogous**: Adjacent hues on color wheel
|
||||
- **Complementary**: Opposite hues on color wheel
|
||||
- **Triadic**: Three evenly spaced hues
|
||||
|
||||
### 6. Professional Workflows
|
||||
|
||||
**Workflow 1: Palette Reduction with Dithering**
|
||||
|
||||
User Request: "Reduce this sprite to 16 colors with dithering"
|
||||
|
||||
Approach:
|
||||
1. Get current sprite info
|
||||
2. Check current palette size
|
||||
3. Use `mcp__aseprite__quantize_palette` with:
|
||||
- target_colors: 16
|
||||
- algorithm: "median_cut" or "kmeans"
|
||||
- dither: true (enables Floyd-Steinberg dithering)
|
||||
4. Review result and adjust if needed
|
||||
|
||||
**Workflow 2: Adding Shading to Flat Sprite**
|
||||
|
||||
User Request: "Add shading to this sprite with light from top-left"
|
||||
|
||||
**Option A - Automatic Shading (Quick):**
|
||||
1. Use `mcp__aseprite__apply_auto_shading` with:
|
||||
- light_direction: "top_left"
|
||||
- intensity: 0.3-0.7 (adjust to preference)
|
||||
- style: "smooth", "hard", or "pillow"
|
||||
- hue_shift: true (for vibrant results)
|
||||
2. Tool automatically detects regions and adds shading
|
||||
3. Review and manually refine if needed
|
||||
|
||||
**Option B - Manual Shading (Precise):**
|
||||
1. Analyze sprite structure
|
||||
2. Identify base colors
|
||||
3. Create shadow colors (darker, hue-shifted)
|
||||
4. Create highlight colors (lighter, hue-shifted)
|
||||
5. Update palette with new colors
|
||||
6. Draw shadows on bottom-right surfaces
|
||||
7. Draw highlights on top-left surfaces
|
||||
8. Add subtle reflected light in deep shadows
|
||||
|
||||
**Workflow 3: Smoothing Jagged Edges**
|
||||
|
||||
User Request: "Smooth out the edges on this character"
|
||||
|
||||
Approach:
|
||||
1. Identify jagged diagonal lines and curves
|
||||
2. Find edge color and background color
|
||||
3. Create intermediate colors (1-2 shades between)
|
||||
4. Place AA pixels at edge steps
|
||||
5. Review and refine (avoid over-smoothing)
|
||||
|
||||
**Workflow 4: Converting to Retro Palette (Full Palette Conversion)**
|
||||
|
||||
User Request: "Convert this to NES palette"
|
||||
|
||||
Approach:
|
||||
1. Use `mcp__aseprite__quantize_palette` with retro palette colors
|
||||
2. Specify target palette (e.g., 54 NES colors, 4 Game Boy colors, 16 C64 colors)
|
||||
3. Algorithm maps each pixel to nearest palette color
|
||||
4. Pixels are remapped to new palette indices
|
||||
5. Optionally apply dithering for smoother transitions
|
||||
6. Verify all colors match target palette
|
||||
|
||||
**IMPORTANT**: Use `quantize_palette`, NOT `set_palette`. The `set_palette` tool only replaces the color table without remapping pixel data, which will produce incorrect colors in indexed mode.
|
||||
|
||||
Example:
|
||||
```
|
||||
quantize_palette(
|
||||
sprite_path: "sprite.aseprite",
|
||||
target_colors: 54, # NES full palette
|
||||
algorithm: "median_cut",
|
||||
convert_to_indexed: true,
|
||||
dither: false # or true for Bayer dithering
|
||||
)
|
||||
```
|
||||
|
||||
### 7. Dithering Patterns Reference
|
||||
|
||||
**2-Color Patterns:**
|
||||
|
||||
**Checkerboard (50% mix):**
|
||||
```
|
||||
A B A B
|
||||
B A B A
|
||||
A B A B
|
||||
B A B A
|
||||
```
|
||||
|
||||
**25% Pattern:**
|
||||
```
|
||||
A A B A
|
||||
A A A A
|
||||
B A A A
|
||||
A A A A
|
||||
```
|
||||
|
||||
**75% Pattern:**
|
||||
```
|
||||
B B A B
|
||||
B B B B
|
||||
A B B B
|
||||
B B B B
|
||||
```
|
||||
|
||||
**Bayer 2x2:**
|
||||
```
|
||||
Threshold matrix:
|
||||
0 2
|
||||
3 1
|
||||
|
||||
If pixel value > threshold, use lighter color
|
||||
```
|
||||
|
||||
**Bayer 4x4:**
|
||||
```
|
||||
0 8 2 10
|
||||
12 4 14 6
|
||||
3 11 1 9
|
||||
15 7 13 5
|
||||
```
|
||||
|
||||
**Note**: See `dithering-patterns.md` for comprehensive pattern library.
|
||||
|
||||
### 8. Technical Details
|
||||
|
||||
**Quantization Parameters:**
|
||||
- Target colors: 2-256
|
||||
- Dithering: optional, specify algorithm
|
||||
- Alpha handling: preserve transparency or flatten
|
||||
|
||||
**Palette Constraints:**
|
||||
- RGB mode: No palette constraints
|
||||
- Indexed mode: Max 256 colors
|
||||
- Grayscale: 256 shades of gray
|
||||
|
||||
**Performance:**
|
||||
- Quantization: ~100-500ms depending on sprite size
|
||||
- Dithering: ~200-800ms depending on algorithm and size
|
||||
- Manual pixel operations: <50ms per operation
|
||||
|
||||
### 9. Common Patterns
|
||||
|
||||
**Pattern: Quick Polish**
|
||||
For "make this look better" requests:
|
||||
1. Check palette (reduce if too many colors)
|
||||
2. Add basic shading (light source from top-left)
|
||||
3. Add selective antialiasing on curves
|
||||
4. Adjust contrast if needed
|
||||
|
||||
**Pattern: Retro Conversion**
|
||||
For "make this look retro" requests:
|
||||
1. Reduce to appropriate palette (4, 8, or 16 colors)
|
||||
2. Apply ordered dithering (Bayer)
|
||||
3. Remove antialiasing (make edges sharp)
|
||||
4. Ensure pixel-perfect alignment
|
||||
|
||||
**Pattern: Smooth Gradient**
|
||||
For "smooth out the colors" requests:
|
||||
1. Analyze color distribution
|
||||
2. Apply Floyd-Steinberg dithering
|
||||
3. Optional: slight quantization to clean up palette
|
||||
4. Verify smooth transitions
|
||||
|
||||
## Integration with Other Skills
|
||||
|
||||
- **Start with pixel-art-creator** for base sprite before polishing
|
||||
- **Use pixel-art-animator** for animation, then polish with this Skill
|
||||
- **Hand off to pixel-art-exporter** when refinement is complete
|
||||
|
||||
## Error Handling
|
||||
|
||||
**Quantization fails:**
|
||||
- Target color count must be 2-256
|
||||
- Sprite must have content (not blank)
|
||||
|
||||
**Dithering issues:**
|
||||
- Requires sufficient color depth
|
||||
- May not work well with very limited palettes
|
||||
- Some algorithms better for certain content
|
||||
|
||||
**Palette conflicts:**
|
||||
- Indexed mode has strict limits
|
||||
- Converting to indexed may require quantization first
|
||||
|
||||
## Success Indicators
|
||||
|
||||
You've successfully used this Skill when:
|
||||
- Dithering applied produces smooth gradients or textures
|
||||
- Palette reduced while preserving visual quality
|
||||
- Shading adds depth and dimension
|
||||
- Antialiasing smooths edges without blurring
|
||||
- Colors follow good color theory principles
|
||||
- Sprite has professional, polished appearance
|
||||
346
skills/pixel-art-professional/dithering-patterns.md
Normal file
346
skills/pixel-art-professional/dithering-patterns.md
Normal file
@@ -0,0 +1,346 @@
|
||||
# Dithering Patterns Library
|
||||
|
||||
Comprehensive reference of dithering patterns for pixel art.
|
||||
|
||||
## 2-Color Patterns (50% Mix)
|
||||
|
||||
### Checkerboard
|
||||
```
|
||||
A B A B A B A B
|
||||
B A B A B A B A
|
||||
A B A B A B A B
|
||||
B A B A B A B A
|
||||
A B A B A B A B
|
||||
B A B A B A B A
|
||||
A B A B A B A B
|
||||
B A B A B A B A
|
||||
```
|
||||
|
||||
**Use**: Even 50/50 mix, very regular, obvious pattern.
|
||||
|
||||
### Diagonal Lines
|
||||
```
|
||||
A B . . A B . .
|
||||
B A . . B A . .
|
||||
. . A B . . A B
|
||||
. . B A . . B A
|
||||
A B . . A B . .
|
||||
B A . . B A . .
|
||||
. . A B . . A B
|
||||
. . B A . . B A
|
||||
```
|
||||
|
||||
**Use**: Directional texture, fabric weave.
|
||||
|
||||
### Crosshatch
|
||||
```
|
||||
A B A . A B A .
|
||||
B . B A B . B A
|
||||
A B A . A B A .
|
||||
. A . B . A . B
|
||||
A B A . A B A .
|
||||
B . B A B . B A
|
||||
A B A . A B A .
|
||||
. A . B . A . B
|
||||
```
|
||||
|
||||
**Use**: Rough texture, sketch-like appearance.
|
||||
|
||||
## 2-Color Patterns (25% Mix)
|
||||
|
||||
### Sparse Dots
|
||||
```
|
||||
A A B A A A B A
|
||||
A A A A A A A A
|
||||
B A A A B A A A
|
||||
A A A A A A A A
|
||||
A A B A A A B A
|
||||
A A A A A A A A
|
||||
B A A A B A A A
|
||||
A A A A A A A A
|
||||
```
|
||||
|
||||
**Use**: Subtle texture, 25% darker/lighter.
|
||||
|
||||
### Diagonal Sparse
|
||||
```
|
||||
A A A B A A A A
|
||||
A A A A A A A B
|
||||
A A B A A A A A
|
||||
A A A A A B A A
|
||||
B A A A A A A A
|
||||
A A A B A A A A
|
||||
A A A A A A B A
|
||||
A B A A A A A A
|
||||
```
|
||||
|
||||
**Use**: Gentle diagonal flow.
|
||||
|
||||
## 2-Color Patterns (75% Mix)
|
||||
|
||||
### Dense Dots (Inverse of 25%)
|
||||
```
|
||||
B B A B B B A B
|
||||
B B B B B B B B
|
||||
A B B B A B B B
|
||||
B B B B B B B B
|
||||
B B A B B B A B
|
||||
B B B B B B B B
|
||||
A B B B A B B B
|
||||
B B B B B B B B
|
||||
```
|
||||
|
||||
**Use**: Mostly lighter color, subtle darkening.
|
||||
|
||||
## 3-Color Patterns
|
||||
|
||||
### Smooth Gradient (A → B → C)
|
||||
```
|
||||
A A A A B B B B
|
||||
A A A B B B B C
|
||||
A A A B B B C C
|
||||
A A B B B C C C
|
||||
A B B B C C C C
|
||||
B B B C C C C C
|
||||
B B C C C C C C
|
||||
B C C C C C C C
|
||||
```
|
||||
|
||||
**Use**: Smooth transition between 3 colors.
|
||||
|
||||
### Stepped Gradient
|
||||
```
|
||||
A A A A A A A A
|
||||
A A A A B B B B
|
||||
A A B B B B B B
|
||||
B B B B B B C C
|
||||
B B B B C C C C
|
||||
B B C C C C C C
|
||||
C C C C C C C C
|
||||
C C C C C C C C
|
||||
```
|
||||
|
||||
**Use**: Clear separation between color zones.
|
||||
|
||||
## Bayer Matrices
|
||||
|
||||
### Bayer 2×2 (4 Threshold Levels)
|
||||
```
|
||||
Thresholds:
|
||||
0 2
|
||||
3 1
|
||||
|
||||
Pattern visualization (0=darkest, 3=lightest):
|
||||
0/4 2/4
|
||||
3/4 1/4
|
||||
```
|
||||
|
||||
**Use**: Basic ordered dithering, very coarse.
|
||||
|
||||
### Bayer 4×4 (16 Threshold Levels)
|
||||
```
|
||||
Thresholds:
|
||||
0 8 2 10
|
||||
12 4 14 6
|
||||
3 11 1 9
|
||||
15 7 13 5
|
||||
|
||||
Pattern visualization (0-15 scale):
|
||||
0/16 8/16 2/16 10/16
|
||||
12/16 4/16 14/16 6/16
|
||||
3/16 11/16 1/16 9/16
|
||||
15/16 7/16 13/16 5/16
|
||||
```
|
||||
|
||||
**Use**: Standard ordered dithering, balanced regularity and smoothness.
|
||||
|
||||
### Bayer 8×8 (64 Threshold Levels)
|
||||
```
|
||||
Thresholds:
|
||||
0 32 8 40 2 34 10 42
|
||||
48 16 56 24 50 18 58 26
|
||||
12 44 4 36 14 46 6 38
|
||||
60 28 52 20 62 30 54 22
|
||||
3 35 11 43 1 33 9 41
|
||||
51 19 59 27 49 17 57 25
|
||||
15 47 7 39 13 45 5 37
|
||||
63 31 55 23 61 29 53 21
|
||||
```
|
||||
|
||||
**Use**: Fine ordered dithering, near-gradient quality.
|
||||
|
||||
## Artistic Patterns
|
||||
|
||||
### Hatching (Single Direction)
|
||||
```
|
||||
A A A B A A A B
|
||||
A A A B A A A B
|
||||
A A A B A A A B
|
||||
A A A B A A A B
|
||||
A A A B A A A B
|
||||
A A A B A A A B
|
||||
A A A B A A A B
|
||||
A A A B A A A B
|
||||
```
|
||||
|
||||
**Use**: Pen-and-ink style, directional shading.
|
||||
|
||||
### Cross-Hatching
|
||||
```
|
||||
A A B A A A B A
|
||||
A A B A A A B A
|
||||
B B A B B B A B
|
||||
A A B A A A B A
|
||||
A A B A A A B A
|
||||
A A B A A A B A
|
||||
B B A B B B A B
|
||||
A A B A A A B A
|
||||
```
|
||||
|
||||
**Use**: Heavier ink-style shading.
|
||||
|
||||
### Stippling
|
||||
```
|
||||
A A B A A A A B
|
||||
A A A A B A A A
|
||||
B A A A A A B A
|
||||
A A A B A A A A
|
||||
A A A A A B A A
|
||||
B A B A A A A A
|
||||
A A A A B A A B
|
||||
A B A A A A A A
|
||||
```
|
||||
|
||||
**Use**: Random-looking texture, organic.
|
||||
|
||||
### Vertical Lines (Fabric)
|
||||
```
|
||||
A B A B A B A B
|
||||
A B A B A B A B
|
||||
A B A B A B A B
|
||||
A B A B A B A B
|
||||
A B A B A B A B
|
||||
A B A B A B A B
|
||||
A B A B A B A B
|
||||
A B A B A B A B
|
||||
```
|
||||
|
||||
**Use**: Fabric weave, vertical texture.
|
||||
|
||||
### Horizontal Lines (Metal Brushing)
|
||||
```
|
||||
A A A A A A A A
|
||||
B B B B B B B B
|
||||
A A A A A A A A
|
||||
A A A A A A A A
|
||||
B B B B B B B B
|
||||
A A A A A A A A
|
||||
A A A A A A A A
|
||||
B B B B B B B B
|
||||
```
|
||||
|
||||
**Use**: Brushed metal, horizontal grain.
|
||||
|
||||
### Brick Pattern
|
||||
```
|
||||
A A B A A A B A
|
||||
A A B A A A B A
|
||||
B B A B B B A B
|
||||
B B A B B B A B
|
||||
A A B A A A B A
|
||||
A A B A A A B A
|
||||
B B A B B B A B
|
||||
B B A B B B A B
|
||||
```
|
||||
|
||||
**Use**: Masonry texture, tiled surfaces.
|
||||
|
||||
### Woven Fabric
|
||||
```
|
||||
A A B B A A B B
|
||||
A A B B A A B B
|
||||
B B A A B B A A
|
||||
B B A A B B A A
|
||||
A A B B A A B B
|
||||
A A B B A A B B
|
||||
B B A A B B A A
|
||||
B B A A B B A A
|
||||
```
|
||||
|
||||
**Use**: Basket weave, cloth texture.
|
||||
|
||||
## Retro Console Dithering
|
||||
|
||||
### NES-Style (Coarse Checkerboard)
|
||||
```
|
||||
A B A B A B A B
|
||||
B A B A B A B A
|
||||
A B A B A B A B
|
||||
B A B A B A B A
|
||||
A B A B A B A B
|
||||
B A B A B A B A
|
||||
A B A B A B A B
|
||||
B A B A B A B A
|
||||
```
|
||||
|
||||
**Use**: Classic 8-bit look, very visible pattern.
|
||||
|
||||
### Game Boy-Style (Dense Stippling)
|
||||
```
|
||||
A A B A A B A A
|
||||
A B A A B A A B
|
||||
B A A B A A B A
|
||||
A A B A A B A A
|
||||
A B A A B A A B
|
||||
B A A B A A B A
|
||||
A A B A A B A A
|
||||
A B A A B A A B
|
||||
```
|
||||
|
||||
**Use**: 4-shade Game Boy aesthetic.
|
||||
|
||||
### SNES-Style (Fine Bayer)
|
||||
```
|
||||
(Use Bayer 8×8 matrix)
|
||||
```
|
||||
|
||||
**Use**: Smooth 16-bit era gradients.
|
||||
|
||||
## Pattern Selection Guide
|
||||
|
||||
| Desired Effect | Recommended Pattern |
|
||||
|---|---|
|
||||
| Smooth gradient | Floyd-Steinberg or Bayer 8×8 |
|
||||
| Retro/obvious | Checkerboard or Bayer 2×2 |
|
||||
| Fabric texture | Woven or Vertical Lines |
|
||||
| Metal surface | Horizontal Lines |
|
||||
| Stone/rough | Stippling or Sparse Dots |
|
||||
| Ink drawing | Hatching or Cross-Hatching |
|
||||
| Subtle shading | Bayer 4×4 or Diagonal Sparse |
|
||||
| Dramatic contrast | Brick or Bold Checkerboard |
|
||||
|
||||
## Color Percentage Mix Table
|
||||
|
||||
| Pattern | % of Color A | % of Color B |
|
||||
|---|---|---|
|
||||
| Sparse Dots (25%) | 75% | 25% |
|
||||
| Checkerboard (50%) | 50% | 50% |
|
||||
| Dense Dots (75%) | 25% | 75% |
|
||||
| Single Line (12.5%) | 87.5% | 12.5% |
|
||||
| Double Line (25%) | 75% | 25% |
|
||||
| Triple Line (37.5%) | 62.5% | 37.5% |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
**Tiling**: All patterns above are 8×8 and tile seamlessly. Repeat pattern across larger areas.
|
||||
|
||||
**Color Mixing**: "A" and "B" represent two colors being mixed. Use actual hex colors from palette.
|
||||
|
||||
**Customization**: Modify patterns by:
|
||||
- Rotating 90°/180°/270° for directional change
|
||||
- Inverting (swap A and B) for opposite density
|
||||
- Combining patterns for complex textures
|
||||
|
||||
**Tool Support**:
|
||||
- Manual: Use `mcp__aseprite__draw_pixels` to place pattern pixels
|
||||
- Automatic: Use `mcp__aseprite__apply_dithering` with algorithm name
|
||||
868
skills/pixel-art-professional/examples.md
Normal file
868
skills/pixel-art-professional/examples.md
Normal file
@@ -0,0 +1,868 @@
|
||||
# Pixel Art Professional Examples
|
||||
|
||||
This document provides concrete examples of how the pixel-art-professional skill handles advanced pixel art techniques. Each example shows the user's request, step-by-step approach, actual MCP tool calls with parameters, and expected results.
|
||||
|
||||
Examples are organized by technique: dithering, palette optimization, shading, antialiasing, and complete refinement workflows.
|
||||
|
||||
---
|
||||
|
||||
## Dithering Applications
|
||||
|
||||
### Example 1: Floyd-Steinberg Dithering for Gradient
|
||||
|
||||
**User Request:**
|
||||
> "Apply Floyd-Steinberg dithering to create a smooth gradient with a limited palette"
|
||||
|
||||
**Approach:**
|
||||
1. Create canvas with gradient (or existing image)
|
||||
2. Set limited target palette
|
||||
3. Apply Floyd-Steinberg dithering algorithm
|
||||
4. Diffuses error to neighboring pixels for smooth transitions
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// Assume canvas exists with smooth RGB gradient
|
||||
// Create target palette (limited colors)
|
||||
mcp__aseprite__set_palette({
|
||||
colors: [
|
||||
{ r: 0, g: 0, b: 0 }, // Black
|
||||
{ r: 85, g: 85, b: 85 }, // Dark gray
|
||||
{ r: 170, g: 170, b: 170 }, // Light gray
|
||||
{ r: 255, g: 255, b: 255 } // White
|
||||
]
|
||||
})
|
||||
|
||||
// Apply Floyd-Steinberg dithering
|
||||
mcp__aseprite__apply_dithering({
|
||||
algorithm: "floyd-steinberg",
|
||||
matrix: "default"
|
||||
})
|
||||
|
||||
// Quantize to palette
|
||||
mcp__aseprite__quantize_colors({
|
||||
colors: 4,
|
||||
algorithm: "default"
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A gradient that appears smooth despite using only 4 colors, with error diffusion creating organic dither patterns.
|
||||
|
||||
**Visual Description:**
|
||||
The gradient transitions from black to white using a checkerboard-like pattern of gray pixels. Floyd-Steinberg's error diffusion creates irregular, organic-looking patterns that avoid banding. Close pixels seem to "blend" optically when viewed at normal distance.
|
||||
|
||||
---
|
||||
|
||||
### Example 2: Bayer Dithering for Ordered Pattern
|
||||
|
||||
**User Request:**
|
||||
> "Use Bayer dithering to create a consistent textured pattern"
|
||||
|
||||
**Approach:**
|
||||
1. Start with image or gradient
|
||||
2. Apply Bayer matrix dithering
|
||||
3. Creates ordered, repeating pattern
|
||||
4. Good for textures and consistent looks
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// Apply 8x8 Bayer matrix dithering
|
||||
mcp__aseprite__apply_dithering({
|
||||
algorithm: "bayer",
|
||||
matrix: "8x8"
|
||||
})
|
||||
|
||||
// Alternative: 4x4 for coarser pattern
|
||||
// mcp__aseprite__apply_dithering({
|
||||
// algorithm: "bayer",
|
||||
// matrix: "4x4"
|
||||
// })
|
||||
```
|
||||
|
||||
**Result:**
|
||||
An ordered dither pattern with consistent, repeating structure suitable for textures.
|
||||
|
||||
**Visual Description:**
|
||||
Instead of random-looking patterns, Bayer dithering creates a regular crosshatch or grid pattern. The 8x8 matrix produces finer patterns than 4x4. This technique gives a vintage computer graphics aesthetic and works well for fabric textures or patterned surfaces.
|
||||
|
||||
---
|
||||
|
||||
### Example 3: Retro Game Style Dithering
|
||||
|
||||
**User Request:**
|
||||
> "Apply classic dithering like old DOS games, convert my sprite to 16 colors"
|
||||
|
||||
**Approach:**
|
||||
1. Get current sprite palette
|
||||
2. Reduce to 16 colors
|
||||
3. Apply ordered dithering for retro look
|
||||
4. Maintain pixel art aesthetic
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// First, get current palette to analyze
|
||||
mcp__aseprite__get_palette()
|
||||
|
||||
// Quantize to 16 colors (typical VGA palette size)
|
||||
mcp__aseprite__quantize_colors({
|
||||
colors: 16,
|
||||
algorithm: "rgb5a3" // Retro-friendly quantization
|
||||
})
|
||||
|
||||
// Apply ordered dithering with smaller matrix
|
||||
mcp__aseprite__apply_dithering({
|
||||
algorithm: "ordered",
|
||||
matrix: "4x4"
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A sprite with authentic early-90s PC game aesthetic using ordered dither and 16-color palette.
|
||||
|
||||
**Visual Description:**
|
||||
The sprite has a distinctly retro appearance with visible dither patterns. Colors are limited to 16 values, and gradients show clear crosshatch patterns typical of VGA-era games. The ordered dither gives it that classic Sierra or LucasArts adventure game look.
|
||||
|
||||
---
|
||||
|
||||
### Example 4: Subtle Dithering for Smooth Shading
|
||||
|
||||
**User Request:**
|
||||
> "Add gentle dithering to my character's shading without making it too obvious"
|
||||
|
||||
**Approach:**
|
||||
1. Work with existing shaded sprite
|
||||
2. Apply light dithering only to transition areas
|
||||
3. Use high-resolution matrix for subtlety
|
||||
4. Preserve hard edges
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// Apply very subtle Floyd-Steinberg with reduced strength
|
||||
mcp__aseprite__apply_dithering({
|
||||
algorithm: "floyd-steinberg",
|
||||
matrix: "default",
|
||||
serpentine: true // Reduces banding artifacts
|
||||
})
|
||||
|
||||
// Alternative: Use fine Bayer matrix
|
||||
// mcp__aseprite__apply_dithering({
|
||||
// algorithm: "bayer",
|
||||
// matrix: "16x16" // Very fine pattern
|
||||
// })
|
||||
```
|
||||
|
||||
**Result:**
|
||||
Smooth shading with barely perceptible dithering that eliminates banding without dominating the aesthetic.
|
||||
|
||||
**Visual Description:**
|
||||
The character's shading appears mostly smooth but with subtle texture in the transition zones. The dithering is fine enough that it reads as smooth shading at normal viewing distance but eliminates harsh color banding. Edges remain clean and crisp.
|
||||
|
||||
---
|
||||
|
||||
## Palette Optimization
|
||||
|
||||
### Example 5: Color Reduction with Quantization
|
||||
|
||||
**User Request:**
|
||||
> "Reduce my sprite from thousands of colors to just 32 for a retro game"
|
||||
|
||||
**Approach:**
|
||||
1. Analyze current color usage
|
||||
2. Apply intelligent quantization
|
||||
3. Preserve important color relationships
|
||||
4. Set optimized palette
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// Get current palette info
|
||||
mcp__aseprite__get_palette()
|
||||
|
||||
// Quantize to 32 colors intelligently
|
||||
mcp__aseprite__quantize_colors({
|
||||
colors: 32,
|
||||
algorithm: "octree" // Good for color preservation
|
||||
})
|
||||
|
||||
// Alternatively, use k-means for better clustering
|
||||
// mcp__aseprite__quantize_colors({
|
||||
// colors: 32,
|
||||
// algorithm: "kmeans"
|
||||
// })
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A sprite using exactly 32 colors that maintains the original's visual appearance while being palette-constrained.
|
||||
|
||||
**Visual Description:**
|
||||
The quantized sprite looks remarkably similar to the original despite having far fewer colors. Important color distinctions are preserved (skin tone vs. clothing vs. highlights), while subtle variations are merged intelligently. Perfect for Game Boy Advance or similar systems.
|
||||
|
||||
---
|
||||
|
||||
### Example 6: Creating a Unified Palette
|
||||
|
||||
**User Request:**
|
||||
> "I have multiple sprites with different palettes - create one unified 16-color palette for all of them"
|
||||
|
||||
**Approach:**
|
||||
1. Analyze color usage across all sprites
|
||||
2. Find common colors and important distinctions
|
||||
3. Generate optimized shared palette
|
||||
4. Apply to all sprites with dithering for transitions
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// For sprite 1
|
||||
mcp__aseprite__get_palette()
|
||||
|
||||
// Quantize all sprites to same 16-color palette
|
||||
// First, determine optimal palette across all sprites
|
||||
mcp__aseprite__quantize_colors({
|
||||
colors: 16,
|
||||
algorithm: "octree",
|
||||
useAllFrames: true,
|
||||
useAllLayers: true
|
||||
})
|
||||
|
||||
// Get the generated palette
|
||||
const unifiedPalette = mcp__aseprite__get_palette()
|
||||
|
||||
// Apply Floyd-Steinberg to handle color transitions
|
||||
mcp__aseprite__apply_dithering({
|
||||
algorithm: "floyd-steinberg",
|
||||
matrix: "default"
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A cohesive 16-color palette that works across multiple sprites, enabling consistent art direction.
|
||||
|
||||
**Visual Description:**
|
||||
All sprites now share the same 16 colors, creating visual harmony. The palette includes key colors needed by all sprites: skin tones, common material colors, and essential highlights/shadows. Dithering bridges gaps where sprites previously had unique colors.
|
||||
|
||||
---
|
||||
|
||||
### Example 7: Palette Swapping Setup
|
||||
|
||||
**User Request:**
|
||||
> "Optimize my character palette so I can easily swap colors for different character variants"
|
||||
|
||||
**Approach:**
|
||||
1. Organize palette by function (skin, hair, clothing, details)
|
||||
2. Keep palette indices consistent
|
||||
3. Create base character with organized palette
|
||||
4. Enable easy color swapping
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// Set organized palette with functional groups
|
||||
mcp__aseprite__set_palette({
|
||||
colors: [
|
||||
// Indices 0-3: Skin tones
|
||||
{ r: 255, g: 220, b: 177 }, // Light skin
|
||||
{ r: 220, g: 180, b: 140 }, // Mid skin
|
||||
{ r: 180, g: 130, b: 90 }, // Shadow skin
|
||||
{ r: 0, g: 0, b: 0 }, // Outline
|
||||
|
||||
// Indices 4-7: Hair colors
|
||||
{ r: 101, g: 67, b: 33 }, // Brown hair
|
||||
{ r: 70, g: 45, b: 20 }, // Dark brown hair
|
||||
{ r: 50, g: 30, b: 10 }, // Hair shadow
|
||||
{ r: 130, g: 90, b: 50 }, // Hair highlight
|
||||
|
||||
// Indices 8-11: Primary clothing
|
||||
{ r: 200, g: 50, b: 50 }, // Red shirt
|
||||
{ r: 150, g: 30, b: 30 }, // Red shirt shadow
|
||||
{ r: 250, g: 100, b: 100 }, // Red shirt highlight
|
||||
{ r: 0, g: 0, b: 0 }, // Clothing outline
|
||||
|
||||
// Indices 12-15: Secondary colors
|
||||
{ r: 50, g: 100, b: 200 }, // Blue pants
|
||||
{ r: 30, g: 70, b: 150 }, // Blue pants shadow
|
||||
{ r: 100, g: 150, b: 250 }, // Blue pants highlight
|
||||
{ r: 255, g: 255, b: 255 } // White details
|
||||
]
|
||||
})
|
||||
|
||||
// Draw character using these organized indices
|
||||
mcp__aseprite__draw_pixels({
|
||||
pixels: [
|
||||
// Use indices 0-3 for all skin
|
||||
{ x: 15, y: 8, colorIndex: 0 }, // Light skin
|
||||
{ x: 16, y: 9, colorIndex: 1 }, // Mid skin
|
||||
{ x: 17, y: 10, colorIndex: 2 }, // Shadow skin
|
||||
// Use indices 4-7 for all hair
|
||||
{ x: 14, y: 6, colorIndex: 4 }, // Hair
|
||||
// Use indices 8-11 for clothing
|
||||
{ x: 15, y: 12, colorIndex: 8 }, // Shirt
|
||||
// etc.
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A character sprite with organized palette enabling easy variants (blonde, redhead, etc.) by swapping specific palette ranges.
|
||||
|
||||
**Visual Description:**
|
||||
The base character uses indices organized by feature. To create a blonde variant, simply replace palette indices 4-7 with yellow/blonde values. For a green shirt, replace indices 8-11. The character's structure remains identical, but appearances change dramatically with palette swaps.
|
||||
|
||||
---
|
||||
|
||||
## Shading Techniques
|
||||
|
||||
### Example 8: Adding Cell Shading
|
||||
|
||||
**User Request:**
|
||||
> "Add simple cell shading to my flat character sprite - just base color, shadow, and highlight"
|
||||
|
||||
**Approach:**
|
||||
1. Start with flat-colored sprite
|
||||
2. Identify light source direction
|
||||
3. Add shadow areas (typically 50% darker)
|
||||
4. Add highlight areas (typically 50% lighter)
|
||||
5. Keep clean, hard edges for cell-shaded look
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// Assume sprite exists with flat colors
|
||||
// Get current palette
|
||||
const currentPalette = mcp__aseprite__get_palette()
|
||||
|
||||
// Add darker shadow versions of each color to palette
|
||||
mcp__aseprite__set_palette({
|
||||
colors: [
|
||||
...currentPalette.colors,
|
||||
// Add shadow versions (multiply by 0.5-0.7)
|
||||
{ r: Math.floor(currentPalette.colors[1].r * 0.6),
|
||||
g: Math.floor(currentPalette.colors[1].g * 0.6),
|
||||
b: Math.floor(currentPalette.colors[1].b * 0.6) },
|
||||
// Add highlight versions (add 30-50%)
|
||||
{ r: Math.min(255, Math.floor(currentPalette.colors[1].r * 1.4)),
|
||||
g: Math.min(255, Math.floor(currentPalette.colors[1].g * 1.4)),
|
||||
b: Math.min(255, Math.floor(currentPalette.colors[1].b * 1.4)) }
|
||||
]
|
||||
})
|
||||
|
||||
// Draw shadow pixels (assuming light from upper-left)
|
||||
mcp__aseprite__draw_pixels({
|
||||
pixels: [
|
||||
// Right side of body - shadow
|
||||
{ x: 17, y: 13, colorIndex: 8 }, // Shadow color index
|
||||
{ x: 17, y: 14, colorIndex: 8 },
|
||||
{ x: 17, y: 15, colorIndex: 8 },
|
||||
// Under chin - shadow
|
||||
{ x: 15, y: 11, colorIndex: 2 }, // Skin shadow
|
||||
{ x: 16, y: 11, colorIndex: 2 },
|
||||
// Right side of legs - shadow
|
||||
{ x: 17, y: 18, colorIndex: 9 }, // Pants shadow
|
||||
{ x: 17, y: 19, colorIndex: 9 }
|
||||
]
|
||||
})
|
||||
|
||||
// Draw highlight pixels
|
||||
mcp__aseprite__draw_pixels({
|
||||
pixels: [
|
||||
// Top of head - highlight
|
||||
{ x: 14, y: 8, colorIndex: 5 }, // Hair highlight
|
||||
{ x: 15, y: 8, colorIndex: 5 },
|
||||
// Left shoulder - highlight
|
||||
{ x: 14, y: 12, colorIndex: 10 }, // Shirt highlight
|
||||
// Top of legs - highlight
|
||||
{ x: 14, y: 16, colorIndex: 11 } // Pants highlight
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A character with clean, cell-shaded appearance featuring distinct base, shadow, and highlight zones.
|
||||
|
||||
**Visual Description:**
|
||||
The sprite has a cartoon/anime look with three distinct tones per color area. Hard-edged shadows appear on the right side and underneath forms (light from upper-left). Bright highlights pop on the upper-left surfaces. No gradients - just clean color breaks creating dimensional appearance.
|
||||
|
||||
---
|
||||
|
||||
### Example 9: Soft Shading with Gradients
|
||||
|
||||
**User Request:**
|
||||
> "Add smooth, gradient-style shading to make my sprite look more realistic"
|
||||
|
||||
**Approach:**
|
||||
1. Start with base colors
|
||||
2. Create multiple intermediate shades
|
||||
3. Apply graduated shading with subtle transitions
|
||||
4. Use more colors for smoother gradients
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// Create expanded palette with many intermediate shades
|
||||
mcp__aseprite__set_palette({
|
||||
colors: [
|
||||
// Skin tone gradient (8 steps)
|
||||
{ r: 255, g: 220, b: 177 }, // Lightest
|
||||
{ r: 245, g: 210, b: 167 },
|
||||
{ r: 235, g: 200, b: 157 },
|
||||
{ r: 225, g: 190, b: 147 },
|
||||
{ r: 215, g: 180, b: 137 }, // Mid
|
||||
{ r: 200, g: 165, b: 122 },
|
||||
{ r: 185, g: 150, b: 107 },
|
||||
{ r: 170, g: 135, b: 92 }, // Darkest
|
||||
|
||||
// Red fabric gradient (6 steps)
|
||||
{ r: 255, g: 100, b: 100 }, // Highlight
|
||||
{ r: 230, g: 70, b: 70 },
|
||||
{ r: 200, g: 50, b: 50 }, // Base
|
||||
{ r: 170, g: 35, b: 35 },
|
||||
{ r: 140, g: 25, b: 25 },
|
||||
{ r: 110, g: 15, b: 15 } // Shadow
|
||||
]
|
||||
})
|
||||
|
||||
// Draw graduated shading on face
|
||||
mcp__aseprite__draw_pixels({
|
||||
pixels: [
|
||||
// Face - lightest on left, gradual transition right
|
||||
{ x: 14, y: 9, colorIndex: 0 }, // Lightest
|
||||
{ x: 15, y: 9, colorIndex: 1 },
|
||||
{ x: 16, y: 9, colorIndex: 2 },
|
||||
{ x: 17, y: 9, colorIndex: 3 },
|
||||
{ x: 18, y: 9, colorIndex: 4 }, // Mid
|
||||
{ x: 19, y: 9, colorIndex: 5 },
|
||||
{ x: 20, y: 9, colorIndex: 6 },
|
||||
{ x: 21, y: 9, colorIndex: 7 } // Darkest
|
||||
]
|
||||
})
|
||||
|
||||
// Draw smooth shading on clothing
|
||||
mcp__aseprite__draw_pixels({
|
||||
pixels: [
|
||||
// Shirt with gradient from light to dark
|
||||
{ x: 14, y: 13, colorIndex: 8 }, // Highlight
|
||||
{ x: 15, y: 13, colorIndex: 9 },
|
||||
{ x: 16, y: 13, colorIndex: 10 }, // Base
|
||||
{ x: 17, y: 13, colorIndex: 11 },
|
||||
{ x: 18, y: 13, colorIndex: 12 }, // Shadow
|
||||
{ x: 19, y: 13, colorIndex: 13 } // Deep shadow
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
Smooth, painterly shading with subtle gradients creating realistic volume and form.
|
||||
|
||||
**Visual Description:**
|
||||
The sprite has soft, graduated shading similar to oil painting. Forms curve smoothly with gradual light-to-dark transitions. The face has subtle volume with cheekbone highlights and jaw shadows. Clothing folds show dimensional depth. No harsh lines - everything blends naturally.
|
||||
|
||||
---
|
||||
|
||||
### Example 10: Ambient Occlusion
|
||||
|
||||
**User Request:**
|
||||
> "Add ambient occlusion darkening where surfaces meet and in crevices"
|
||||
|
||||
**Approach:**
|
||||
1. Identify contact points and corners
|
||||
2. Add extra-dark pixels in these areas
|
||||
3. Creates depth and grounds objects
|
||||
4. Subtle but impactful realism boost
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// Add very dark AO color to palette
|
||||
mcp__aseprite__set_palette({
|
||||
colors: [
|
||||
...existingPalette,
|
||||
{ r: 20, g: 20, b: 25 } // Very dark blue-black for AO
|
||||
]
|
||||
})
|
||||
|
||||
// Draw AO in crevices and contact points
|
||||
mcp__aseprite__draw_pixels({
|
||||
pixels: [
|
||||
// Under chin where head meets neck
|
||||
{ x: 15, y: 11, colorIndex: 20 },
|
||||
{ x: 16, y: 11, colorIndex: 20 },
|
||||
|
||||
// Where arm meets body
|
||||
{ x: 13, y: 14, colorIndex: 20 },
|
||||
|
||||
// Where legs meet ground
|
||||
{ x: 14, y: 21, colorIndex: 20 },
|
||||
{ x: 17, y: 21, colorIndex: 20 },
|
||||
|
||||
// Inside elbow crease
|
||||
{ x: 12, y: 15, colorIndex: 20 },
|
||||
|
||||
// Corner where torso meets legs
|
||||
{ x: 15, y: 16, colorIndex: 20 },
|
||||
{ x: 16, y: 16, colorIndex: 20 }
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
Added depth and realism through dark contact shadows that ground the character and define form connections.
|
||||
|
||||
**Visual Description:**
|
||||
The character now has subtle dark pixels in recessed areas: under the chin, inside elbows, where arms press against the torso, and where feet touch ground. These dark accents make the sprite feel more three-dimensional and properly lit by environmental light rather than just direct light.
|
||||
|
||||
---
|
||||
|
||||
## Antialiasing
|
||||
|
||||
### Example 11: Edge Smoothing with AA
|
||||
|
||||
**User Request:**
|
||||
> "Smooth out the jagged edges on my circle sprite with antialiasing"
|
||||
|
||||
**Approach:**
|
||||
1. Identify hard diagonal edges
|
||||
2. Add intermediate color pixels along edges
|
||||
3. Blend between foreground and background
|
||||
4. Creates smoother curves
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// Assume we have a red circle on white background
|
||||
// Add AA colors to palette - blend between red and white
|
||||
mcp__aseprite__set_palette({
|
||||
colors: [
|
||||
{ r: 255, g: 255, b: 255 }, // White background
|
||||
{ r: 200, g: 0, b: 0 }, // Red circle
|
||||
{ r: 255, g: 200, b: 200 }, // Light pink (75% white, 25% red)
|
||||
{ r: 230, g: 100, b: 100 } // Pink (50% blend)
|
||||
]
|
||||
})
|
||||
|
||||
// Draw AA pixels along curved edges
|
||||
mcp__aseprite__draw_pixels({
|
||||
pixels: [
|
||||
// Top curve - original had stair-step edge
|
||||
{ x: 14, y: 5, colorIndex: 2 }, // Light AA
|
||||
{ x: 18, y: 5, colorIndex: 2 }, // Light AA
|
||||
{ x: 13, y: 6, colorIndex: 3 }, // Medium AA
|
||||
{ x: 19, y: 6, colorIndex: 3 }, // Medium AA
|
||||
|
||||
// Left curve
|
||||
{ x: 11, y: 7, colorIndex: 2 },
|
||||
{ x: 10, y: 8, colorIndex: 3 },
|
||||
{ x: 9, y: 10, colorIndex: 3 },
|
||||
{ x: 9, y: 11, colorIndex: 2 },
|
||||
|
||||
// Right curve (mirror)
|
||||
{ x: 21, y: 7, colorIndex: 2 },
|
||||
{ x: 22, y: 8, colorIndex: 3 },
|
||||
{ x: 23, y: 10, colorIndex: 3 },
|
||||
{ x: 23, y: 11, colorIndex: 2 },
|
||||
|
||||
// Bottom curve
|
||||
{ x: 13, y: 15, colorIndex: 3 },
|
||||
{ x: 19, y: 15, colorIndex: 3 },
|
||||
{ x: 14, y: 16, colorIndex: 2 },
|
||||
{ x: 18, y: 16, colorIndex: 2 }
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A circle with smooth, anti-aliased edges that appear curved rather than stair-stepped.
|
||||
|
||||
**Visual Description:**
|
||||
The circle's edges now have pink transitional pixels that blend the red circle into the white background. Diagonal and curved edges that previously showed obvious pixel stairs now appear smooth and rounded. The overall shape reads as a true circle rather than a pixelated approximation.
|
||||
|
||||
---
|
||||
|
||||
### Example 12: Selective AA for Readability
|
||||
|
||||
**User Request:**
|
||||
> "Add antialiasing to curved parts but keep pixel-perfect straight edges"
|
||||
|
||||
**Approach:**
|
||||
1. Identify which edges are curved vs. straight
|
||||
2. Apply AA only to diagonals and curves
|
||||
3. Keep horizontal/vertical edges sharp
|
||||
4. Maintains clarity while smoothing curves
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// Character sprite - AA only on rounded features
|
||||
mcp__aseprite__draw_pixels({
|
||||
pixels: [
|
||||
// Round head - add AA on curves
|
||||
{ x: 13, y: 8, colorIndex: 15 }, // AA pixel
|
||||
{ x: 19, y: 8, colorIndex: 15 }, // AA pixel
|
||||
|
||||
// Shoulders - slight curve, add AA
|
||||
{ x: 12, y: 12, colorIndex: 16 }, // AA blend
|
||||
{ x: 20, y: 12, colorIndex: 16 }, // AA blend
|
||||
|
||||
// Arms - straight sides, NO AA applied
|
||||
// Leave edges sharp at x: 13, 19 from y: 13-15
|
||||
|
||||
// Bottom of torso - slight curve
|
||||
{ x: 13, y: 16, colorIndex: 17 }, // AA blend
|
||||
{ x: 19, y: 16, colorIndex: 17 } // AA blend
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A sprite with smooth curved features (head, shoulders) but crisp, readable straight edges (arms, torso sides).
|
||||
|
||||
**Visual Description:**
|
||||
The character's round head has smooth antialiased edges that look natural. Shoulders curve gently into arms with subtle AA. However, the vertical edges of the torso and straight lines of the arms remain pixel-perfect sharp, maintaining pixel art clarity and preventing muddiness.
|
||||
|
||||
---
|
||||
|
||||
## Complete Refinement Workflows
|
||||
|
||||
### Example 13: Draft to Polished Character
|
||||
|
||||
**User Request:**
|
||||
> "Take my rough character sketch and apply professional techniques - shading, palette optimization, and AA"
|
||||
|
||||
**Approach:**
|
||||
1. Start with flat-color draft
|
||||
2. Optimize palette to organized scheme
|
||||
3. Add cell shading with 3 tones per color
|
||||
4. Apply subtle dithering in transitions
|
||||
5. Add antialiasing to curves
|
||||
6. Apply ambient occlusion at contacts
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// Step 1: Get current palette and optimize
|
||||
const draftPalette = mcp__aseprite__get_palette()
|
||||
|
||||
mcp__aseprite__quantize_colors({
|
||||
colors: 24, // Enough for 3 tones × 8 material types
|
||||
algorithm: "octree"
|
||||
})
|
||||
|
||||
// Step 2: Reorganize palette by material and tone
|
||||
mcp__aseprite__set_palette({
|
||||
colors: [
|
||||
// Skin: light, mid, dark
|
||||
{ r: 255, g: 220, b: 177 },
|
||||
{ r: 220, g: 180, b: 140 },
|
||||
{ r: 185, g: 145, b: 105 },
|
||||
|
||||
// Hair: light, mid, dark
|
||||
{ r: 150, g: 100, b: 50 },
|
||||
{ r: 110, g: 70, b: 30 },
|
||||
{ r: 70, g: 40, b: 15 },
|
||||
|
||||
// Clothing and so on...
|
||||
]
|
||||
})
|
||||
|
||||
// Step 3: Add cell shading (shadows on right, highlights on left)
|
||||
mcp__aseprite__draw_pixels({
|
||||
pixels: [
|
||||
// Skin shadows
|
||||
{ x: 18, y: 9, colorIndex: 2 }, // Dark skin on right face
|
||||
{ x: 18, y: 10, colorIndex: 2 },
|
||||
// Skin highlights
|
||||
{ x: 14, y: 9, colorIndex: 0 }, // Light skin on left face
|
||||
{ x: 14, y: 10, colorIndex: 0 },
|
||||
// Hair shadows...
|
||||
// Clothing shadows...
|
||||
]
|
||||
})
|
||||
|
||||
// Step 4: Apply subtle dithering to smooth transitions
|
||||
mcp__aseprite__apply_dithering({
|
||||
algorithm: "floyd-steinberg",
|
||||
matrix: "default"
|
||||
})
|
||||
|
||||
// Step 5: Add antialiasing to curved edges
|
||||
mcp__aseprite__draw_pixels({
|
||||
pixels: [
|
||||
// AA on head curves
|
||||
{ x: 13, y: 8, colorIndex: 16 }, // Blend color
|
||||
{ x: 19, y: 8, colorIndex: 16 },
|
||||
// AA on shoulders...
|
||||
]
|
||||
})
|
||||
|
||||
// Step 6: Add ambient occlusion
|
||||
mcp__aseprite__draw_pixels({
|
||||
pixels: [
|
||||
// Dark pixels under chin, in armpits, where feet meet ground
|
||||
{ x: 15, y: 11, colorIndex: 23 }, // AO color
|
||||
{ x: 16, y: 11, colorIndex: 23 }
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A polished character sprite with professional shading, optimized palette, smooth edges, and dimensional depth.
|
||||
|
||||
**Visual Description:**
|
||||
The transformation is dramatic. The flat draft now has dimensional form with light from the upper-left creating clear highlights and shadows. Curves are smooth with antialiasing. Contact points have subtle darkening that grounds the character. The palette is organized and efficient. The sprite looks professional and game-ready.
|
||||
|
||||
---
|
||||
|
||||
### Example 14: Retro Game Sprite Enhancement
|
||||
|
||||
**User Request:**
|
||||
> "Enhance my NES-style sprite with modern techniques while keeping the retro feel"
|
||||
|
||||
**Approach:**
|
||||
1. Start with authentic NES palette (52 colors)
|
||||
2. Add selective AA only on important elements
|
||||
3. Use ordered dithering for textures
|
||||
4. Enhance shading without adding colors
|
||||
5. Keep that retro charm
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// Use authentic NES palette subset
|
||||
mcp__aseprite__set_palette({
|
||||
colors: [
|
||||
{ r: 124, g: 124, b: 124 }, // NES gray
|
||||
{ r: 0, g: 0, b: 252 }, // NES blue
|
||||
{ r: 0, g: 0, b: 188 }, // NES dark blue
|
||||
{ r: 252, g: 0, b: 0 }, // NES red
|
||||
{ r: 188, g: 0, b: 0 }, // NES dark red
|
||||
// ... more NES colors
|
||||
]
|
||||
})
|
||||
|
||||
// Apply ordered dithering for that authentic NES texture
|
||||
mcp__aseprite__apply_dithering({
|
||||
algorithm: "ordered",
|
||||
matrix: "4x4"
|
||||
})
|
||||
|
||||
// Add selective AA only on character face/important details
|
||||
mcp__aseprite__draw_pixels({
|
||||
pixels: [
|
||||
// Very minimal AA - just on face curves
|
||||
{ x: 14, y: 9, colorIndex: 8 }, // Subtle blend pixel
|
||||
{ x: 18, y: 9, colorIndex: 8 }
|
||||
]
|
||||
})
|
||||
|
||||
// Enhance shading with existing palette
|
||||
mcp__aseprite__draw_pixels({
|
||||
pixels: [
|
||||
// Use existing dark colors for better form definition
|
||||
{ x: 17, y: 13, colorIndex: 4 }, // Existing dark red for shadow
|
||||
{ x: 17, y: 14, colorIndex: 4 },
|
||||
{ x: 17, y: 15, colorIndex: 4 }
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
An enhanced retro sprite that looks sharper and more dimensional while maintaining authentic NES aesthetic.
|
||||
|
||||
**Visual Description:**
|
||||
The sprite still screams "NES game" with its authentic palette and ordered dithering patterns. However, the shading is more sophisticated, with better form definition and deeper shadows. Subtle antialiasing on the face makes the character more expressive without looking out of place. It feels like a high-quality NES game rather than a amateur homebrew project.
|
||||
|
||||
---
|
||||
|
||||
### Example 15: Modern Indie Game Polish
|
||||
|
||||
**User Request:**
|
||||
> "Give my sprite a modern indie pixel art look - smooth, colorful, professional"
|
||||
|
||||
**Approach:**
|
||||
1. Use expanded color palette (64+ colors)
|
||||
2. Apply smooth gradient shading
|
||||
3. Add antialiasing liberally
|
||||
4. Include ambient occlusion
|
||||
5. Add rim lighting for extra pop
|
||||
|
||||
**Tool Calls:**
|
||||
```javascript
|
||||
// Create rich palette with many shades
|
||||
mcp__aseprite__set_palette({
|
||||
colors: [
|
||||
// Skin gradient (8 shades)
|
||||
{ r: 255, g: 230, b: 200 },
|
||||
{ r: 245, g: 215, b: 185 },
|
||||
{ r: 235, g: 200, b: 170 },
|
||||
{ r: 225, g: 185, b: 155 },
|
||||
{ r: 210, g: 170, b: 140 },
|
||||
{ r: 195, g: 155, b: 125 },
|
||||
{ r: 180, g: 140, b: 110 },
|
||||
{ r: 165, g: 125, b: 95 },
|
||||
|
||||
// Hair gradient (8 shades)
|
||||
{ r: 180, g: 140, b: 80 },
|
||||
{ r: 160, g: 120, b: 65 },
|
||||
{ r: 140, g: 100, b: 50 },
|
||||
{ r: 120, g: 85, b: 40 },
|
||||
{ r: 100, g: 70, b: 30 },
|
||||
{ r: 80, g: 55, b: 20 },
|
||||
{ r: 60, g: 40, b: 15 },
|
||||
{ r: 40, g: 25, b: 10 },
|
||||
|
||||
// Clothing with saturation gradient...
|
||||
// Plus AO color, rim light color...
|
||||
]
|
||||
})
|
||||
|
||||
// Apply smooth gradient shading
|
||||
mcp__aseprite__draw_pixels({
|
||||
pixels: [
|
||||
// Face with smooth gradient left to right
|
||||
{ x: 14, y: 9, colorIndex: 0 }, // Lightest
|
||||
{ x: 15, y: 9, colorIndex: 1 },
|
||||
{ x: 16, y: 9, colorIndex: 2 },
|
||||
{ x: 17, y: 9, colorIndex: 3 }, // Mid
|
||||
{ x: 18, y: 9, colorIndex: 4 },
|
||||
{ x: 19, y: 9, colorIndex: 5 }, // Shadow
|
||||
// Continue for whole sprite...
|
||||
]
|
||||
})
|
||||
|
||||
// Add generous antialiasing
|
||||
mcp__aseprite__draw_pixels({
|
||||
pixels: [
|
||||
// AA all around character outline
|
||||
// Many blend pixels creating smooth silhouette
|
||||
]
|
||||
})
|
||||
|
||||
// Add ambient occlusion
|
||||
mcp__aseprite__draw_pixels({
|
||||
pixels: [
|
||||
// Dark pixels in all crevices and contact points
|
||||
{ x: 15, y: 11, colorIndex: 60 }, // AO under chin
|
||||
// ... many more AO pixels
|
||||
]
|
||||
})
|
||||
|
||||
// Add rim lighting on left edge (opposite main light)
|
||||
mcp__aseprite__draw_pixels({
|
||||
pixels: [
|
||||
// Bright pixels on left edge for rim light effect
|
||||
{ x: 13, y: 9, colorIndex: 61 }, // Bright rim
|
||||
{ x: 13, y: 10, colorIndex: 61 },
|
||||
{ x: 13, y: 13, colorIndex: 62 }, // Rim on body
|
||||
{ x: 13, y: 14, colorIndex: 62 }
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
**Result:**
|
||||
A modern, polished indie game character with smooth shading, rich colors, and professional lighting.
|
||||
|
||||
**Visual Description:**
|
||||
The sprite has a contemporary pixel art aesthetic like Celeste or Hyper Light Drifter. Smooth gradient shading creates realistic volume. Generous antialiasing makes all edges smooth. Ambient occlusion adds depth to every crevice. A subtle rim light on the left edge makes the character pop against backgrounds. The rich palette and professional techniques create that "modern indie" look.
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
This examples collection demonstrates the pixel-art-professional skill's advanced techniques:
|
||||
|
||||
- **Dithering** (Examples 1-4): Floyd-Steinberg, Bayer, ordered patterns, and subtle applications
|
||||
- **Palette optimization** (Examples 5-7): Color reduction, unification, and palette swapping setup
|
||||
- **Shading** (Examples 8-10): Cell shading, soft gradients, and ambient occlusion
|
||||
- **Antialiasing** (Examples 11-12): Edge smoothing and selective AA for readability
|
||||
- **Complete workflows** (Examples 13-15): Draft-to-polish, retro enhancement, modern indie polish
|
||||
|
||||
Each example shows complete MCP tool call syntax with professional techniques that transform amateur pixel art into polished, professional assets.
|
||||
450
skills/pixel-art-professional/reference.md
Normal file
450
skills/pixel-art-professional/reference.md
Normal file
@@ -0,0 +1,450 @@
|
||||
# Pixel Art Professional - Technical Reference
|
||||
|
||||
## Dithering Algorithms
|
||||
|
||||
### Ordered Dithering (Bayer Matrix)
|
||||
|
||||
**Bayer 2x2 Matrix:**
|
||||
```
|
||||
0/4 2/4
|
||||
3/4 1/4
|
||||
```
|
||||
|
||||
**Bayer 4x4 Matrix:**
|
||||
```
|
||||
0/16 8/16 2/16 10/16
|
||||
12/16 4/16 14/16 6/16
|
||||
3/16 11/16 1/16 9/16
|
||||
15/16 7/16 13/16 5/16
|
||||
```
|
||||
|
||||
**Bayer 8x8 Matrix:**
|
||||
```
|
||||
0 32 8 40 2 34 10 42
|
||||
48 16 56 24 50 18 58 26
|
||||
12 44 4 36 14 46 6 38
|
||||
60 28 52 20 62 30 54 22
|
||||
3 35 11 43 1 33 9 41
|
||||
51 19 59 27 49 17 57 25
|
||||
15 47 7 39 13 45 5 37
|
||||
63 31 55 23 61 29 53 21
|
||||
```
|
||||
|
||||
**Usage**: For pixel at (x, y) with color value C (0-255):
|
||||
1. Get threshold T from matrix[y % size][x % size]
|
||||
2. If C > T, use lighter color; else use darker color
|
||||
|
||||
### Error Diffusion Dithering
|
||||
|
||||
**Floyd-Steinberg Algorithm:**
|
||||
|
||||
Distributes quantization error to neighboring pixels:
|
||||
```
|
||||
X 7/16
|
||||
3/16 5/16 1/16
|
||||
```
|
||||
|
||||
Where X is current pixel.
|
||||
|
||||
**Process:**
|
||||
1. Quantize current pixel to nearest palette color
|
||||
2. Calculate error = original_color - quantized_color
|
||||
3. Distribute error to neighbors:
|
||||
- Right pixel: error × 7/16
|
||||
- Bottom-left: error × 3/16
|
||||
- Bottom: error × 5/16
|
||||
- Bottom-right: error × 1/16
|
||||
|
||||
**Jarvis-Judice-Ninke Algorithm:**
|
||||
|
||||
More distributed error diffusion:
|
||||
```
|
||||
X 7/16 5/16
|
||||
3/16 5/16 7/16 5/16 3/16
|
||||
1/16 3/16 5/16 3/16 1/16
|
||||
```
|
||||
|
||||
**Atkinson Algorithm:**
|
||||
|
||||
Simplified error diffusion (popularized by Apple):
|
||||
```
|
||||
X 1/8 1/8
|
||||
1/8 1/8 1/8
|
||||
1/8
|
||||
```
|
||||
|
||||
Note: Only distributes 6/8 of error, allows some to "bleed off" for lighter appearance.
|
||||
|
||||
## Color Ramp Theory
|
||||
|
||||
### Creating Smooth Ramps
|
||||
|
||||
**5-Step Ramp Example (Skin Tone):**
|
||||
1. **Deep Shadow**: #3a2419 (dark brown, shifted toward cool)
|
||||
2. **Shadow**: #5c3a28 (brown)
|
||||
3. **Base/Midtone**: #8d5a3e (medium brown)
|
||||
4. **Highlight**: #b8825c (light brown, shifted toward warm)
|
||||
5. **Bright Highlight**: #e6b896 (very light, warm)
|
||||
|
||||
**Hue Shifting Pattern:**
|
||||
- Deep shadow: Hue -10°, Saturation -10%, Value -40%
|
||||
- Shadow: Hue -5°, Saturation -5%, Value -20%
|
||||
- Base: Original color
|
||||
- Highlight: Hue +5°, Saturation -5%, Value +20%
|
||||
- Bright Highlight: Hue +10°, Saturation -10%, Value +40%
|
||||
|
||||
### Metal Shading
|
||||
|
||||
**Characteristics:**
|
||||
- High contrast (very dark shadows, very bright highlights)
|
||||
- Sharp transitions
|
||||
- Reflected environment colors
|
||||
- Minimal mid-tones
|
||||
|
||||
**Example Ramp (Steel):**
|
||||
1. Deep Shadow: #1a1a24 (dark blue-gray)
|
||||
2. Shadow: #3a3a4a (medium blue-gray)
|
||||
3. Base: #6a6a7a (light blue-gray)
|
||||
4. Highlight: #aaaabb (very light blue-gray)
|
||||
5. Specular: #ffffff (pure white reflection)
|
||||
|
||||
### Fabric Shading
|
||||
|
||||
**Characteristics:**
|
||||
- Soft transitions
|
||||
- Subsurface scattering simulation (lighter shadows)
|
||||
- Texture can be suggested with dithering
|
||||
- Less contrast than metal
|
||||
|
||||
**Example Ramp (Red Fabric):**
|
||||
1. Deep Shadow: #5a1a1a (dark red)
|
||||
2. Shadow: #8a2a2a (medium-dark red)
|
||||
3. Base: #c43a3a (medium red)
|
||||
4. Highlight: #e66a6a (light red)
|
||||
5. Bright Highlight: #ff9a9a (very light red)
|
||||
|
||||
## Classic Palettes
|
||||
|
||||
### NES Palette
|
||||
|
||||
**Total Colors**: 54 usable colors (64 total, but some are identical or unusable)
|
||||
|
||||
**Sprite Limitation**: 3 colors + transparent per sprite (4 total palette entries)
|
||||
|
||||
**Common NES Palettes:**
|
||||
- **Mario**: #000000, #ff0000, #a64400, #ffc864
|
||||
- **Megaman**: #000000, #0078f8, #89d7ff, #ffffff
|
||||
- **Zelda Gold**: #000000, #b8b800, #fcfc00, #a8a080
|
||||
|
||||
### Game Boy Palette
|
||||
|
||||
**Original Game Boy (DMG):**
|
||||
- 4 shades of green
|
||||
- Palette: #0f380f, #306230, #8bac0f, #9bbc0f
|
||||
|
||||
**Game Boy Pocket (MGB):**
|
||||
- 4 shades of gray
|
||||
- Palette: #000000, #555555, #aaaaaa, #ffffff
|
||||
|
||||
### SNES Palette
|
||||
|
||||
**Capabilities**: 32,768 total colors (15-bit)
|
||||
**Per Background**: 16-256 colors depending on mode
|
||||
**Per Sprite**: 16 colors (15 + transparent)
|
||||
|
||||
**Common SNES Style:**
|
||||
- Rich, vibrant colors
|
||||
- Smooth gradients
|
||||
- Up to 256 simultaneous colors on screen
|
||||
|
||||
### Commodore 64 Palette
|
||||
|
||||
**Total Colors**: 16 fixed colors
|
||||
|
||||
**Palette**:
|
||||
- Black: #000000
|
||||
- White: #ffffff
|
||||
- Red: #880000
|
||||
- Cyan: #aaffee
|
||||
- Purple: #cc44cc
|
||||
- Green: #00cc55
|
||||
- Blue: #0000aa
|
||||
- Yellow: #eeee77
|
||||
- Orange: #dd8855
|
||||
- Brown: #664400
|
||||
- Light Red: #ff7777
|
||||
- Dark Gray: #333333
|
||||
- Medium Gray: #777777
|
||||
- Light Green: #aaff66
|
||||
- Light Blue: #0088ff
|
||||
- Light Gray: #bbbbbb
|
||||
|
||||
## Antialiasing Techniques
|
||||
|
||||
### Single-Pixel AA
|
||||
|
||||
**Before:**
|
||||
```
|
||||
. . . . . .
|
||||
. . X X X .
|
||||
. X . . . .
|
||||
X . . . . .
|
||||
```
|
||||
|
||||
**After (with AA):**
|
||||
```
|
||||
. . . . . .
|
||||
. . X X X .
|
||||
. X a . . .
|
||||
X a . . . .
|
||||
```
|
||||
|
||||
Where:
|
||||
- X = edge color
|
||||
- . = background
|
||||
- a = antialiased intermediate color
|
||||
|
||||
### Double-Pixel AA (Softer)
|
||||
|
||||
**Before:**
|
||||
```
|
||||
. . . . . .
|
||||
. X X X X .
|
||||
X . . . . .
|
||||
```
|
||||
|
||||
**After:**
|
||||
```
|
||||
. . . a a .
|
||||
. X X X X .
|
||||
X a . . . .
|
||||
```
|
||||
|
||||
### Selective AA
|
||||
|
||||
**Rule**: Only AA where necessary:
|
||||
- Long diagonal lines
|
||||
- Visible curves
|
||||
- High-contrast edges
|
||||
|
||||
**Don't AA:**
|
||||
- Horizontal/vertical lines (already smooth)
|
||||
- Intentional jagged details
|
||||
- Very small sprites
|
||||
|
||||
## Shading from Different Light Sources
|
||||
|
||||
### Top-Left Light (Most Common)
|
||||
|
||||
```
|
||||
☀️
|
||||
↙
|
||||
[Sprite]
|
||||
↘
|
||||
(shadow)
|
||||
```
|
||||
|
||||
- Highlights: top and left surfaces
|
||||
- Shadows: bottom and right surfaces
|
||||
|
||||
### Top-Down Light (Dramatic)
|
||||
|
||||
```
|
||||
☀️
|
||||
↓
|
||||
[Sprite]
|
||||
```
|
||||
|
||||
- Highlights: top surfaces
|
||||
- Shadows: all vertical surfaces
|
||||
- Strong cast shadows on ground
|
||||
|
||||
### Rim Lighting (Backlit)
|
||||
|
||||
```
|
||||
[Sprite] ← ☀️
|
||||
```
|
||||
|
||||
- Highlights: edges facing light
|
||||
- Most of sprite in shadow
|
||||
- Dramatic silhouette effect
|
||||
|
||||
### Multiple Light Sources
|
||||
|
||||
**Example: Fire + Moonlight**
|
||||
- Fire (warm orange): bottom and left
|
||||
- Moon (cool blue): top and right
|
||||
- Mixing creates interesting color interplay
|
||||
|
||||
## Texture Suggestions with Dithering
|
||||
|
||||
### Stone/Rock Texture
|
||||
|
||||
Use irregular dithering pattern:
|
||||
```
|
||||
A A B A A B A
|
||||
A B A A B A A
|
||||
B A A B A A B
|
||||
A A B A B A A
|
||||
```
|
||||
|
||||
Mix 2-3 related gray/brown tones.
|
||||
|
||||
### Metal Texture
|
||||
|
||||
Use horizontal line dithering:
|
||||
```
|
||||
A A A A A A A
|
||||
B B B B B B B
|
||||
A A A A A A A
|
||||
A A A A A A A
|
||||
B B B B B B B
|
||||
```
|
||||
|
||||
Creates brushed metal effect.
|
||||
|
||||
### Fabric Texture
|
||||
|
||||
Use soft checkerboard:
|
||||
```
|
||||
A A B A A B A
|
||||
A A A A A A A
|
||||
B A A B A A B
|
||||
A A A A A A A
|
||||
```
|
||||
|
||||
Suggests woven or cloth texture.
|
||||
|
||||
### Wood Grain
|
||||
|
||||
Use wavy vertical lines:
|
||||
```
|
||||
A B A A B A A
|
||||
A A B A A B A
|
||||
A B A A B A A
|
||||
A A B A B A A
|
||||
```
|
||||
|
||||
Suggests wood grain direction.
|
||||
|
||||
## Performance Benchmarks
|
||||
|
||||
**Color Quantization:**
|
||||
- 64x64 sprite, 100 colors → 16 colors: ~150ms
|
||||
- 128x128 sprite, 500 colors → 32 colors: ~400ms
|
||||
- 256x256 sprite, 1000 colors → 64 colors: ~1200ms
|
||||
|
||||
**Dithering:**
|
||||
- Floyd-Steinberg, 64x64: ~200ms
|
||||
- Floyd-Steinberg, 128x128: ~600ms
|
||||
- Bayer 4x4, 64x64: ~80ms
|
||||
- Bayer 4x4, 128x128: ~250ms
|
||||
|
||||
**Manual Pixel Operations:**
|
||||
- Drawing single pixel: <5ms
|
||||
- Drawing 100 pixels (batch): ~20ms
|
||||
- Palette update: ~15ms
|
||||
|
||||
## Common Mistakes and Fixes
|
||||
|
||||
### Mistake: Pillow Shading
|
||||
|
||||
**Problem**: Shading around edges instead of from light source.
|
||||
|
||||
**Looks Like:**
|
||||
```
|
||||
. . . X X X . .
|
||||
. X x x x x X .
|
||||
X x o o o o x X
|
||||
X x o o o o x X
|
||||
. X x x x x X .
|
||||
. . . X X X . .
|
||||
```
|
||||
|
||||
Where o = base, x = shadow, X = dark shadow (all around edge).
|
||||
|
||||
**Fix**: Shade from consistent light direction:
|
||||
```
|
||||
. . H H H X X .
|
||||
. H h o o x X .
|
||||
H h o o o o x X
|
||||
H h o o o o x X
|
||||
. H h x x x X .
|
||||
. . H X X X . .
|
||||
```
|
||||
|
||||
Where H = highlight, h = light, o = base, x = shadow, X = dark shadow (directional).
|
||||
|
||||
### Mistake: Pure Black Shadows
|
||||
|
||||
**Problem**: Using #000000 for shadows makes them look flat and dead.
|
||||
|
||||
**Fix**: Use dark version of base color with hue shift:
|
||||
- Base: #ff6b6b (red)
|
||||
- Bad shadow: #000000 (pure black)
|
||||
- Good shadow: #5a1a1a (dark red with slight purple shift)
|
||||
|
||||
### Mistake: Banding in Gradients
|
||||
|
||||
**Problem**: Visible steps in gradients due to too few colors.
|
||||
|
||||
**Fix**: Apply dithering between color steps:
|
||||
```
|
||||
Bad:
|
||||
AAAABBBBCCCCDDDD
|
||||
|
||||
Good (with dithering):
|
||||
AAAAA/BBA/BB/CCB/CCC/DCD/DDDD
|
||||
```
|
||||
|
||||
Where / represents dithered transition.
|
||||
|
||||
### Mistake: Over-Antialiasing
|
||||
|
||||
**Problem**: Too many AA pixels make edges blurry.
|
||||
|
||||
**Fix**: Use 1-pixel wide AA only where needed:
|
||||
- Bad: 2-3 pixels of intermediate colors (blurry)
|
||||
- Good: 1 pixel of intermediate color at steps only
|
||||
|
||||
## Color Harmony Examples
|
||||
|
||||
### Monochromatic (Blue)
|
||||
|
||||
```
|
||||
#001f3f (dark blue)
|
||||
#0074D9 (medium blue)
|
||||
#7FDBFF (light blue)
|
||||
#aef3ff (very light blue)
|
||||
```
|
||||
|
||||
### Analogous (Red-Orange-Yellow)
|
||||
|
||||
```
|
||||
#ff4136 (red)
|
||||
#ff851b (orange)
|
||||
#ffdc00 (yellow)
|
||||
```
|
||||
|
||||
### Complementary (Blue-Orange)
|
||||
|
||||
```
|
||||
#0074D9 (blue)
|
||||
#ff851b (orange)
|
||||
```
|
||||
|
||||
### Triadic (Red-Yellow-Blue)
|
||||
|
||||
```
|
||||
#ff4136 (red)
|
||||
#ffdc00 (yellow)
|
||||
#0074D9 (blue)
|
||||
```
|
||||
|
||||
### Split Complementary (Blue + Red-Orange + Yellow-Orange)
|
||||
|
||||
```
|
||||
#0074D9 (blue)
|
||||
#ff4136 (red-orange)
|
||||
#ffdc00 (yellow-orange)
|
||||
```
|
||||
Reference in New Issue
Block a user