
pixel-agents-vscode
Visualize and manage Claude Code AI agents as pixel art characters in a VS Code extension office interface
- Installs
- 187
- Last 24h
- —
- Trending rank
- —
- Security
- Not audited
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/reason-machines/ai-agent-skills --skill pixel-agents-vscode- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads pixel-agents-vscode automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
SKILL.md
The instructions your agent reads when the skill is triggered.
Pixel Agents VSCode Extension
Skill by ara.so — AI Agent Skills collection.
Pixel Agents is a VS Code extension that visualizes multi-agent AI systems (currently Claude Code) as pixel art characters in a customizable office environment. Each agent becomes an animated character that reflects its real-time activity — typing when writing code, reading when searching files, and displaying speech bubbles when waiting for input.
Installation
From VS Code Marketplace
- Open VS Code
- Go to Extensions (Ctrl+Shift+X / Cmd+Shift+X)
- Search for "Pixel Agents"
- Click Install
Or install via command line:
code --install-extension pablodelucca.pixel-agents
From Source
git clone https://github.com/pablodelucca/pixel-agents.git
cd pixel-agents
npm install
cd webview-ui && npm install && cd ..
npm run build
Then press F5 in VS Code to launch the Extension Development Host.
Prerequisites
- VS Code: Version 1.105.0 or later
- Claude Code CLI: Must be installed and configured
# Install Claude Code (if not already installed) npm install -g @anthropic-ai/claude-code
Key Features and Usage
Spawning Agents
Open the Pixel Agents panel (appears in bottom panel area alongside terminal):
Create normal agent:
// Click "+ Agent" button in Pixel Agents panel
// This spawns a new Claude Code terminal with a character
Create agent with skip permissions:
// Right-click "+ Agent" button
// Select "Launch with --dangerously-skip-permissions"
// Agent will bypass all tool approval prompts
Managing Characters
Assign character to a seat:
// 1. Click a character to select it
// 2. Click an empty seat to reassign the character
View agent status:
- Walking: Agent is navigating to desk/idle
- Typing: Writing code, creating files, making changes
- Reading: Searching files, analyzing code
- Speech bubble: Waiting for user input or permission
- Idle: No current activity
Office Layout Editor
Open editor:
// Click "Layout" button in Pixel Agents panel
Editor tools:
- Select (S): Select and move furniture
- Paint (P): Paint floor tiles
- Erase (E): Remove items
- Place (F): Add furniture
- Eyedropper (I): Pick colors/tiles
- Pick (K): Select furniture type
Keyboard shortcuts:
Ctrl+Z/Cmd+Z: Undo (50 levels)Ctrl+Y/Cmd+Y: RedoDelete: Remove selected item- Arrow keys: Fine-tune placement
Expand grid:
// Click the ghost border outside current grid
// Grid expands up to 64×64 tiles
Configuration
Access settings via gear icon in Pixel Agents panel:
Sound notifications:
// Toggle sound when agent finishes turn
// Settings → Enable Sound Notifications
Debug view:
// Settings → Debug View
// Shows per-agent diagnostics:
// - JSONL file status
// - Lines parsed
// - Last data timestamp
// - File path
Export/Import layouts:
// Settings → Export Layout (saves as JSON)
// Settings → Import Layout (load from JSON file)
Add external assets:
// Settings → Add Asset Directory
// Point to folder with custom furniture packs
Working with Assets
Asset Structure
All assets are in webview-ui/public/assets/:
assets/
├── furniture/
│ ├── desk-01/
│ │ ├── manifest.json
│ │ └── sprite.png
│ └── chair-01/
│ ├── manifest.json
│ └── sprite.png
├── floors/
│ └── tile-wood.png
└── walls/
└── brick/
├── manifest.json
└── tileset.png
Creating Custom Furniture
Manifest structure:
{
"id": "desk-modern",
"name": "Modern Desk",
"category": "desks",
"width": 2,
"height": 1,
"isSeat": true,
"seatOffset": { "x": 0, "y": -16 },
"rotationGroups": [
{
"rotations": ["north", "east", "south", "west"],
"sprite": "desk-modern.png"
}
],
"stateGroups": [
{
"state": "off",
"sprite": "desk-modern-off.png"
},
{
"state": "on",
"sprite": "desk-modern-on.png"
}
]
}
Add to project:
# 1. Create folder in assets/furniture/
mkdir webview-ui/public/assets/furniture/desk-modern
# 2. Add sprite PNG and manifest.json
# 3. Rebuild extension
npm run build
Using External Asset Directories
// 1. Create asset directory structure:
// /my-assets/
// furniture/
// custom-desk/
// manifest.json
// sprite.png
// 2. In Pixel Agents Settings → Add Asset Directory
// 3. Select /my-assets/
// 4. Assets appear in furniture picker
External manifest.json:
{
"id": "custom-plant",
"name": "Custom Plant",
"category": "decorations",
"width": 1,
"height": 1,
"isSeat": false,
"rotationGroups": [
{
"rotations": ["north"],
"sprite": "plant.png"
}
]
}
Code Examples
Monitoring Agent Activity (Extension Side)
import * as vscode from 'vscode';
import * as fs from 'fs';
import * as path from 'path';
// Watch Claude Code JSONL transcript for agent activity
function watchAgentTranscript(projectPath: string, agentId: string): vscode.Disposable {
const jsonlPath = path.join(
projectPath,
'.claude',
'projects',
agentId,
'transcript.jsonl'
);
let lastPosition = 0;
const interval = setInterval(() => {
if (!fs.existsSync(jsonlPath)) {
return;
}
const stats = fs.statSync(jsonlPath);
if (stats.size <= lastPosition) {
return;
}
const buffer = Buffer.alloc(stats.size - lastPosition);
const fd = fs.openSync(jsonlPath, 'r');
fs.readSync(fd, buffer, 0, buffer.length, lastPosition);
fs.closeSync(fd);
const lines = buffer.toString('utf-8').split('\n').filter(l => l.trim());
lines.forEach(line => {
try {
const record = JSON.parse(line);
handleAgentRecord(agentId, record);
} catch (err) {
console.error('[Pixel Agents] Failed to parse JSONL:', err);
}
});
lastPosition = stats.size;
}, 500);
return new vscode.Disposable(() => clearInterval(interval));
}
function handleAgentRecord(agentId: string, record: any): void {
// Detect agent activity from JSONL record type
if (record.type === 'tool_use') {
const toolName = record.content?.name;
if (toolName === 'write_file' || toolName === 'edit_file') {
updateAgentState(agentId, 'typing');
} else if (toolName === 'search_files' || toolName === 'read_file') {
updateAgentState(agentId, 'reading');
} else if (toolName === 'run_command') {
updateAgentState(agentId, 'typing');
}
} else if (record.type === 'user_message') {
updateAgentState(agentId, 'idle');
}
}
function updateAgentState(agentId: string, state: string): void {
// Send message to webview
webviewPanel.webview.postMessage({
command: 'updateAgentState',
agentId,
state
});
}
Character Animation (Webview Side)
interface Character {
id: string;
x: number;
y: number;
targetX: number;
targetY: number;
state: 'idle' | 'walking' | 'typing' | 'reading';
direction: 'north' | 'south' | 'east' | 'west';
frame: number;
spriteSheet: HTMLImageElement;
}
class CharacterRenderer {
private characters: Map<string, Character> = new Map();
private readonly TILE_SIZE = 16;
private readonly FRAME_RATE = 8; // frames per second
private frameCounter = 0;
update(deltaTime: number): void {
this.frameCounter += deltaTime;
const frameInterval = 1000 / this.FRAME_RATE;
this.characters.forEach(char => {
// Update position if walking
if (char.state === 'walking') {
const dx = char.targetX - char.x;
const dy = char.targetY - char.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 1) {
char.x = char.targetX;
char.y = char.targetY;
char.state = 'idle';
} else {
const speed = 2; // pixels per frame
char.x += (dx / distance) * speed;
char.y += (dy / distance) * speed;
// Update direction based on movement
if (Math.abs(dx) > Math.abs(dy)) {
char.direction = dx > 0 ? 'east' : 'west';
} else {
char.direction = dy > 0 ? 'south' : 'north';
}
}
}
// Advance animation frame
if (this.frameCounter >= frameInterval) {
char.frame = (char.frame + 1) % this.getFrameCount(char.state);
}
});
if (this.frameCounter >= frameInterval) {
this.frameCounter = 0;
}
}
render(ctx: CanvasRenderingContext2D): void {
this.characters.forEach(char => {
const spriteX = this.getSpriteX(char);
const spriteY = this.getSpriteY(char);
ctx.drawImage(
char.spriteSheet,
spriteX, spriteY,
this.TILE_SIZE, this.TILE_SIZE * 2, // source
Math.floor(char.x), Math.floor(char.y),
this.TILE_SIZE, this.TILE_SIZE * 2 // destination
);
});
}
private getSpriteX(char: Character): number {
return char.frame * this.TILE_SIZE;
}
private getSpriteY(char: Character): number {
const directionOffsets = {
'south': 0,
'west': 1,
'east': 2,
'north': 3
};
const stateOffsets = {
'idle': 0,
'walking': 0,
'typing': 4,
'reading': 8
};
return (stateOffsets[char.state] + directionOffsets[char.direction])
* this.TILE_SIZE * 2;
}
private getFrameCount(state: string): number {
if (state === 'walking') return 4;
if (state === 'typing' || state === 'reading') return 3;
return 1; // idle
}
moveCharacter(id: string, targetX: number, targetY: number): void {
const char = this.characters.get(id);
if (char) {
char.targetX = targetX;
char.targetY = targetY;
char.state = 'walking';
}
}
setCharacterState(id: string, state: Character['state']): void {
const char = this.characters.get(id);
if (char) {
char.state = state;
char.frame = 0;
}
}
}
Pathfinding (BFS for Agent Movement)
interface Point {
x: number;
y: number;
}
class Pathfinder {
private grid: boolean[][]; // true = walkable
private width: number;
private height: number;
constructor(width: number, height: number) {
this.width = width;
this.height = height;
this.grid = Array(height).fill(null).map(() => Array(width).fill(true));
}
setObstacle(x: number, y: number, blocked: boolean): void {
if (x >= 0 && x < this.width && y >= 0 && y < this.height) {
this.grid[y][x] = !blocked;
}
}
findPath(start: Point, end: Point): Point[] | null {
if (!this.isWalkable(end.x, end.y)) return null;
const queue: { point: Point; path: Point[] }[] = [
{ point: start, path: [start] }
];
const visited = new Set<string>();
visited.add(`${start.x},${start.y}`);
const directions = [
{ x: 0, y: -1 }, // north
{ x: 1, y: 0 }, // east
{ x: 0, y: 1 }, // south
{ x: -1, y: 0 } // west
];
while (queue.length > 0) {
const { point, path } = queue.shift()!;
if (point.x === end.x && point.y === end.y) {
return path;
}
for (const dir of directions) {
const next = { x: point.x + dir.x, y: point.y + dir.y };
const key = `${next.x},${next.y}`;
if (
this.isWalkable(next.x, next.y) &&
!visited.has(key)
) {
visited.add(key);
queue.push({
point: next,
path: [...path, next]
});
}
}
}
return null; // No path found
}
private isWalkable(x: number, y: number): boolean {
return (
x >= 0 &&
x < this.width &&
y >= 0 &&
y < this.height &&
this.grid[y][x]
);
}
}
// Usage
const pathfinder = new Pathfinder(32, 32);
// Mark furniture as obstacles
pathfinder.setObstacle(5, 5, true); // desk
pathfinder.setObstacle(6, 5, true); // desk continuation
// Find path from spawn to desk
const path = pathfinder.findPath({ x: 1, y: 1 }, { x: 5, y: 6 });
if (path) {
// Move character along path
path.forEach((point, index) => {
setTimeout(() => {
renderer.moveCharacter('agent-1', point.x * 16, point.y * 16);
}, index * 200);
});
}
Troubleshooting
Agent Not Appearing
Enable Debug View:
// Settings → Debug View (toggle on)
// Check per-agent diagnostics:
// - "JSONL not found" = extension can't locate session file
// - "Lines parsed: 0" = no activity detected
// - Verify file path matches expected location
Check Debug Console:
// If running from source (F5 Development Host):
// View → Debug Console
// Search for "[Pixel Agents]"
// Look for:
// - Project directory resolution errors
// - JSONL polling status
// - Path encoding mismatches
Agent Stuck on Idle
Common causes:
-
JSONL file not found: Claude Code session hasn't created transcript yet
# Check if file exists ls ~/.claude/projects/*/transcript.jsonl -
Polling lag: Extension polls every 500ms, brief delays are normal
-
Unrecognized record type: Claude Code may emit new JSONL types
// Check Debug Console for "Unrecognized JSONL record type: X"
Agent-Terminal Desync
Symptoms:
- Character appears but terminal is closed
- Terminal exists but no character
- Multiple characters for one terminal
Fixes:
// 1. Close all Claude Code terminals
// 2. In Pixel Agents panel, click each character
// 3. Press Delete or click trash icon
// 4. Spawn fresh agent with "+ Agent"
Speech Bubble Not Clearing
Heuristic-based detection limitations:
The extension uses idle timers to detect when agents wait for input. If speech bubble persists:
// 1. Type something in the Claude Code terminal
// 2. Wait 2-3 seconds for polling to update
// 3. If stuck, close and reopen Pixel Agents panel
Linux/macOS Home Directory Confusion
If you launch VS Code without opening a folder:
# Agent starts in home directory
code
# Sessions tracked under:
~/.claude/projects/<home-directory-hash>/
Solution:
# Always open VS Code with a folder
code /path/to/project
Common Patterns
Multi-Agent Workflow
// 1. Spawn multiple agents for parallel work
// Right-click "+ Agent" → create 3 agents
// 2. Assign each to different task
// Agent 1: "Refactor authentication module"
// Agent 2: "Write unit tests for API"
// Agent 3: "Update documentation"
// 3. Monitor all agents visually in office
// Watch characters move between typing/reading states
// 4. Intervene when speech bubble appears
// Click terminal to provide input or approval
Custom Office for Team Visualization
// 1. Design office layout per team structure
// Layout → Create 4 desk clusters for 4 teams
// 2. Export layout for sharing
// Settings → Export Layout → save as team-office.json
// 3. Team members import same layout
// Settings → Import Layout → select team-office.json
// 4. Everyone sees agents in same office structure
Sub-Agent Visualization
When Claude Code uses the task tool to spawn sub-agents:
// Parent agent spawns sub-agent
// Example: Main agent delegates "write tests" to sub-agent
// Visual behavior:
// - New character appears linked to parent
// - Sub-agent character animates independently
// - Both visible until sub-task completes
// - Sub-agent disappears when task done
External Asset Workflow
// 1. Create asset pack structure
mkdir -p /my-assets/furniture/custom-furniture
// 2. Add manifest and sprites
cat > /my-assets/furniture/custom-furniture/manifest.json << 'EOF'
{
"id": "gaming-chair",
"name": "Gaming Chair",
"category": "seats",
"width": 1,
"height": 1,
"isSeat": true,
"seatOffset": { "x": 0, "y": -8 },
"rotationGroups": [
{
"rotations": ["north", "south", "east", "west"],
"sprite": "chair.png"
}
]
}
EOF
// 3. Link in Pixel Agents
// Settings → Add Asset Directory → /my-assets
// 4. Use in layout editor
// Layout → Place → Select "Gaming Chair"
Extension Commands
Pixel Agents registers the following VS Code commands:
// Open Pixel Agents panel
"pixelAgents.openPanel"
// Spawn new agent (normal)
"pixelAgents.spawnAgent"
// Spawn agent with skip permissions
"pixelAgents.spawnAgentSkipPermissions"
// Open layout editor
"pixelAgents.openLayoutEditor"
// Open settings modal
"pixelAgents.openSettings"
// Toggle debug view
"pixelAgents.toggleDebug"
Access via Command Palette (Ctrl+Shift+P / Cmd+Shift+P):
> Pixel Agents: Open Panel
> Pixel Agents: Spawn Agent
Performance Considerations
JSONL polling:
- Polls every 500ms per agent
- Minimal CPU impact for <10 agents
- For 10+ agents, consider increasing interval in source
Canvas rendering:
- 60 FPS target, degrades gracefully
- Tested up to 64×64 grid with 20 characters
- Use integer zoom levels for pixel-perfect rendering
Memory usage:
- ~5-10 MB per agent (JSONL tracking + character state)
- Asset cache: ~20-50 MB depending on furniture count
Future Roadmap
Pixel Agents is evolving toward a fully agent-agnostic, platform-agnostic interface:
- Agent-agnostic adapters: Support for Codex, Cursor, Copilot, Gemini
- Platform flexibility: Electron app, web app, beyond VS Code
- Advanced features:
- Desks as directories (drag agent to desk = assign to project)
- Kanban board for autonomous task picking
- Deep agent inspection (model, context, history, prompts)
- Token health bars (rate limits, context windows)
- 3D/VR office environments
See GitHub Discussions for ongoing architecture work.
FAQ
What does the pixel-agents-vscode skill do?
Visualize and manage Claude Code AI agents as pixel art characters in a VS Code extension office interface
How do I install pixel-agents-vscode?
Run npx skills add https://github.com/reason-machines/ai-agent-skills --skill pixel-agents-vscode in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/pixel-agents-vscode/ (personal) or .claude/skills/pixel-agents-vscode/ (project).
Which AI agents can use pixel-agents-vscode?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is pixel-agents-vscode safe to install?
No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.
Who maintains pixel-agents-vscode?
It is published by reason-machines in reason-machines/ai-agent-skills. It has 187 recorded installs.
More from reason-machines/ai-agent-skills
agency-agents-zh-skill
reason-machines/ai-agent-skills
Open the skill to read its SKILL.md instructions.
agent-reach-internet-access
reason-machines/ai-agent-skills
Open the skill to read its SKILL.md instructions.
agent-sprite-forge-2d-game-assets
reason-machines/ai-agent-skills
Open the skill to read its SKILL.md instructions.
agentmemory-persistent-memory
reason-machines/ai-agent-skills
Add persistent memory to AI coding agents using agentmemory - remembers context, preferences, and decisions across sessions
awesome-agent-skills
reason-machines/ai-agent-skills
Open the skill to read its SKILL.md instructions.
oh-my-openagent-orchestration
reason-machines/ai-agent-skills
Open the skill to read its SKILL.md instructions.
Popular ai & agents skills
google-agents-cli-publish
google/agents-cli
This skill should be used when the user wants to "publish an agent", "publish my ADK agent", "register an agent with Gemini", "publish to Gemini" (formerly Gemini Enterprise), or needs guidance on the agents-cli publish gemini command. Also use when the user wants to "manage agents in Agent Registry", "list/update/delete registered agents", or "register an MCP server". Covers ADK vs A2A registration modes, programmatic and interactive usage, flag reference, auto-detection from deployment metadata, Agent Registry fleet management, and troubleshooting. Part of the agents-cli skills suite. Do NOT use for deployment (use google-agents-cli-deploy).
google-agents-cli-eval
google/agents-cli
This skill should be used when the user wants to "run an evaluation", "evaluate my agent", "evaluate my ADK agent", "write an eval dataset", "analyze eval failures", "compare eval results", "optimize agent", or needs guidance on the Gemini platform eval methodology and the Quality Flywheel. Covers eval metrics, dataset schema, LLM-as-judge scoring, and common failure causes. Applies to any agents-cli project, whatever framework the agent is written in. Do NOT use for agent API code patterns (ADK: use google-agents-cli-adk-code), deployment (use google-agents-cli-deploy), or project scaffolding (use google-agents-cli-scaffold).
skill-creator
anthropics/skills
Create new skills, modify and improve existing skills, and measure skill performance. Use when users want to create a skill from scratch, edit, or optimize an existing skill, run evals to test a skill, benchmark skill performance with variance analysis, or optimize a skill's description for better triggering accuracy.
codex-pet
prime-skills/runcomfy-agent-skills
Codex Pet generator on RunComfy. Build a Codex-compatible Codex Pet spritesheet.webp + pet.json from a single reference image, drop it into ${CODEXHOME:-$HOME/.codex}/pets/ / and Codex picks it up as a custom Codex Pet next to the 8 built-ins. This skill produces the exact Codex Pet atlas Codex expects (1536x1872 PNG/WebP, 8 cols x 9 rows, 192x208 cells, 9 animation states — idle, running-right, running-left, waving, jumping, failed, waiting, running, review). Calls OpenAI GPT Image 2 edit ONCE via the local RunComfy CLI as runcomfy run openai/gpt-image-2/edit to produce a canonical Codex Pet pose, then assembles all 9 animation rows programmatically with ImageMagick micro-transforms — no Codex Pro, no $imagegen, no OPENAIAPIKEY required, only RUNCOMFYTOKEN. Triggers on "codex pet", "create codex pet", "make codex pet", "hatch codex pet", "/hatch image", "desktop pet codex", "codex pets", "spritesheet.webp", or any explicit ask to build a custom pet for OpenAI Codex.
full-output-enforcement
leonxlnx/taste-skill
Overrides default LLM truncation behavior. Enforces complete code generation, bans placeholder patterns, and handles token-limit splits cleanly. Apply to any task requiring exhaustive, unabridged output.
executing-plans
obra/superpowers
Use when executing an implementation plan in the current session as the implementer yourself — your human partner chose inline execution, or no subagent tool is available