MCPInstall

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
  1. 01

    Install

    Run the command in your project. The CLI asks which agents to install for.

  2. 02

    Describe the task

    Ask your agent for something this skill covers. It loads pixel-agents-vscode automatically when relevant.

  3. 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

  1. Open VS Code
  2. Go to Extensions (Ctrl+Shift+X / Cmd+Shift+X)
  3. Search for "Pixel Agents"
  4. 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: Redo
  • Delete: 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:

  1. JSONL file not found: Claude Code session hasn't created transcript yet

    # Check if file exists
    ls ~/.claude/projects/*/transcript.jsonl
    
  2. Polling lag: Extension polls every 500ms, brief delays are normal

  3. 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

View all →

agency-agents-zh-skill

reason-machines/ai-agent-skills

Open the skill to read its SKILL.md instructions.

AI & Agents322 installs

agent-reach-internet-access

reason-machines/ai-agent-skills

Open the skill to read its SKILL.md instructions.

AI & Agents228 installs

agent-sprite-forge-2d-game-assets

reason-machines/ai-agent-skills

Open the skill to read its SKILL.md instructions.

Media & Creative216 installs

agentmemory-persistent-memory

reason-machines/ai-agent-skills

Add persistent memory to AI coding agents using agentmemory - remembers context, preferences, and decisions across sessions

AI & Agents216 installs

awesome-agent-skills

reason-machines/ai-agent-skills

Open the skill to read its SKILL.md instructions.

AI & Agents214 installs

oh-my-openagent-orchestration

reason-machines/ai-agent-skills

Open the skill to read its SKILL.md instructions.

AI & Agents211 installs

Popular ai & agents skills

View category →

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).

AI & Agents513.9K installs

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).

AI & Agents513.5K installs

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.

OfficialAI & Agents416.4K installs

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.

AI & Agents402.1K installs

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.

AI & Agents401K installs

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

AI & Agents245.7K installs