Claude Code for PixiJS: High-Performance 2D WebGL Rendering — Claude Skills 360 Blog
Blog / Frontend / Claude Code for PixiJS: High-Performance 2D WebGL Rendering
Frontend

Claude Code for PixiJS: High-Performance 2D WebGL Rendering

Published: May 2, 2027
Read time: 7 min read
By: Claude Skills 360

PixiJS is the fastest 2D WebGL renderer for the web — new Application() creates a renderer with automatic WebGL/WebGPU detection. app.stage is the root Container. Sprite.from(url) loads and displays a texture. new Graphics() draws rectangles, circles, and paths procedurally. new Text("hello", style) renders text with web fonts. app.ticker.add(delta => update(delta)) runs the game loop at 60fps. Assets.load(manifest) handles async asset loading with progress. sprite.on("pointerdown", handler) enables interaction — set sprite.interactive = true. ParticleContainer renders thousands of sprites efficiently. ColorMatrixFilter and BlurFilter apply post-process effects. RenderTexture.create({ width, height }) renders to an off-screen surface. @pixi/react provides <Application>, <Sprite>, <Container>, and useTick for React integration. Claude Code generates PixiJS game loops, particle effects, interactive dashboards, sprite animation systems, and map overlays.

CLAUDE.md for PixiJS

## PixiJS Stack
- Version: pixi.js >= 8.4, @pixi/react >= 8.0
- App: const app = new Application(); await app.init({ width, height, background: 0x1a1a2e, resizeTo: window })
- Sprite: const sprite = Sprite.from("/assets/ship.png"); sprite.anchor.set(0.5); app.stage.addChild(sprite)
- Graphics: const g = new Graphics(); g.rect(x, y, w, h).fill(0x3b82f6).stroke({ color: 0xffffff, width: 2 })
- Ticker: app.ticker.add((ticker) => { sprite.rotation += 0.01 * ticker.deltaTime })
- Events: sprite.interactive = true; sprite.on("pointerdown", handler)
- Assets: await Assets.load([{ alias: "ship", src: "/ship.png" }])
- React: <Application width={800} height={600}><Sprite texture={texture} x={400} y={300} /></Application>

PixiJS Application Setup

// lib/pixi/app.ts — PixiJS application with resize and cleanup
import { Application, Assets, Container, Ticker } from "pixi.js"

export async function createPixiApp(canvas: HTMLCanvasElement): Promise<Application> {
  const app = new Application()

  await app.init({
    canvas,
    background: 0x0f172a,
    antialias: true,
    autoDensity: true,      // Retina/HiDPI support
    resolution: window.devicePixelRatio || 1,
    resizeTo: canvas.parentElement ?? window,
    powerPreference: "high-performance",
  })

  return app
}

// Preload all game assets
export async function loadAssets(
  onProgress?: (progress: number) => void,
): Promise<void> {
  Assets.addBundle("game", [
    { alias: "ship", src: "/assets/ship.png" },
    { alias: "asteroid", src: "/assets/asteroid.png" },
    { alias: "explosion", src: "/assets/explosion-sheet.json" },
    { alias: "starfield", src: "/assets/starfield.png" },
  ])

  await Assets.loadBundle("game", (progress) => {
    onProgress?.(Math.round(progress * 100))
  })
}

Sprite Animation System

// lib/pixi/SpriteAnimator.ts — animated sprite with state machine
import { AnimatedSprite, Assets, Texture, Container } from "pixi.js"

type AnimationState = "idle" | "walk" | "run" | "attack" | "death"

const FRAME_COUNTS: Record<AnimationState, number> = {
  idle: 8,
  walk: 12,
  run: 8,
  attack: 6,
  death: 10,
}

const ANIMATION_SPEEDS: Record<AnimationState, number> = {
  idle: 0.12,
  walk: 0.18,
  run: 0.25,
  attack: 0.22,
  death: 0.15,
}

export class CharacterSprite extends Container {
  private sprite: AnimatedSprite
  private state: AnimationState = "idle"
  private onDeathComplete?: () => void

  constructor() {
    super()

    // Build textures from sprite sheet
    const idleTextures = Array.from({ length: FRAME_COUNTS.idle }, (_, i) =>
      Texture.from(`idle_${String(i).padStart(2, "0")}.png`),
    )

    this.sprite = new AnimatedSprite(idleTextures)
    this.sprite.anchor.set(0.5, 1)  // Feet anchor
    this.sprite.animationSpeed = ANIMATION_SPEEDS.idle
    this.sprite.play()
    this.addChild(this.sprite)
  }

  setState(next: AnimationState, onComplete?: () => void): void {
    if (this.state === next) return

    this.state = next
    const frameCount = FRAME_COUNTS[next]

    const textures = Array.from({ length: frameCount }, (_, i) =>
      Texture.from(`${next}_${String(i).padStart(2, "0")}.png`),
    )

    this.sprite.textures = textures
    this.sprite.animationSpeed = ANIMATION_SPEEDS[next]
    this.sprite.loop = next !== "death" && next !== "attack"
    this.sprite.gotoAndPlay(0)

    if (next === "death") {
      this.sprite.onComplete = () => onComplete?.()
    } else {
      this.sprite.onComplete = undefined
    }
  }

  get currentState(): AnimationState {
    return this.state
  }
}

Particle System

// lib/pixi/ParticleSystem.ts — high-performance particles with ParticleContainer
import { ParticleContainer, Sprite, Ticker, Assets } from "pixi.js"

interface Particle {
  sprite: Sprite
  vx: number
  vy: number
  gravity: number
  life: number
  maxLife: number
  startScale: number
  endScale: number
}

export class ParticleSystem {
  container: ParticleContainer
  private particles: Particle[] = []
  private pool: Sprite[] = []

  constructor(maxParticles = 2000) {
    this.container = new ParticleContainer(maxParticles, {
      position: true,
      alpha: true,
      scale: true,
      rotation: true,
    })
  }

  emit(x: number, y: number, count = 20, config?: Partial<{
    spread: number
    speed: number
    gravity: number
    life: number
    startScale: number
    endScale: number
  }>): void {
    const {
      spread = Math.PI * 2,
      speed = 4,
      gravity = 0.15,
      life = 60,
      startScale = 0.8,
      endScale = 0.1,
    } = config ?? {}

    for (let i = 0; i < count; i++) {
      const sprite = this.pool.pop() ?? Sprite.from("particle")
      sprite.anchor.set(0.5)
      sprite.tint = 0xff6b35

      const angle = (Math.random() - 0.5) * spread
      const v = speed * (0.5 + Math.random() * 0.5)

      this.container.addChild(sprite)
      this.particles.push({
        sprite,
        vx: Math.sin(angle) * v,
        vy: -Math.cos(angle) * v,
        gravity,
        life,
        maxLife: life,
        startScale,
        endScale,
      })

      sprite.x = x
      sprite.y = y
      sprite.scale.set(startScale)
      sprite.alpha = 1
    }
  }

  update(ticker: Ticker): void {
    const delta = ticker.deltaTime

    for (let i = this.particles.length - 1; i >= 0; i--) {
      const p = this.particles[i]

      p.vx *= 0.98
      p.vy += p.gravity * delta
      p.sprite.x += p.vx * delta
      p.sprite.y += p.vy * delta
      p.life -= delta

      const progress = 1 - p.life / p.maxLife
      p.sprite.alpha = 1 - progress
      p.sprite.scale.set(p.startScale + (p.endScale - p.startScale) * progress)

      if (p.life <= 0) {
        this.container.removeChild(p.sprite)
        this.pool.push(p.sprite)
        this.particles.splice(i, 1)
      }
    }
  }
}

React Integration

// components/pixi/StarfieldBackground.tsx — @pixi/react integration
"use client"
import { Application, extend } from "@pixi/react"
import { Container, TilingSprite, Graphics, Ticker as PixiTicker } from "pixi.js"
import { useCallback, useRef } from "react"

// Register components with @pixi/react
extend({ Container, TilingSprite, Graphics })

interface StarfieldProps {
  width: number
  height: number
}

export function StarfieldBackground({ width, height }: StarfieldProps) {
  const offsetRef = useRef({ x: 0, y: 0 })

  const drawStars = useCallback((g: InstanceType<typeof Graphics>) => {
    g.clear()
    // Static star field — drawn once
    for (let i = 0; i < 200; i++) {
      const x = Math.random() * width
      const y = Math.random() * height
      const size = Math.random() * 1.5 + 0.5
      const alpha = Math.random() * 0.6 + 0.4
      const color = Math.random() > 0.9 ? 0xffd700 : 0xffffff

      g.circle(x, y, size).fill({ color, alpha })
    }
  }, [width, height])

  return (
    <Application width={width} height={height} background={0x020617}>
      <pixiGraphics draw={drawStars} />
    </Application>
  )
}

Interactive Data Visualization

// lib/pixi/BubbleChart.ts — interactive PixiJS bubble chart
import { Application, Container, Graphics, Text, TextStyle, FederatedPointerEvent } from "pixi.js"

interface DataPoint {
  label: string
  value: number
  color: number
  x: number
  y: number
}

export function createBubbleChart(app: Application, data: DataPoint[]): Container {
  const chart = new Container()
  const maxValue = Math.max(...data.map(d => d.value))

  data.forEach(point => {
    const radius = 20 + (point.value / maxValue) * 60
    const group = new Container()
    group.position.set(point.x, point.y)
    group.interactive = true
    group.cursor = "pointer"

    // Bubble
    const bubble = new Graphics()
    bubble.circle(0, 0, radius)
    bubble.fill({ color: point.color, alpha: 0.7 })
    bubble.stroke({ color: point.color, width: 2, alpha: 1 })

    const labelStyle = new TextStyle({
      fontSize: Math.max(11, Math.min(16, radius * 0.35)),
      fill: 0xffffff,
      fontFamily: "Inter, sans-serif",
      align: "center",
    })
    const label = new Text({ text: point.label, style: labelStyle })
    label.anchor.set(0.5)

    group.addChild(bubble, label)

    // Hover effect
    group.on("pointerenter", () => {
      bubble.clear()
      bubble.circle(0, 0, radius + 4)
      bubble.fill({ color: point.color, alpha: 0.9 })
      bubble.stroke({ color: 0xffffff, width: 2 })
    })

    group.on("pointerleave", () => {
      bubble.clear()
      bubble.circle(0, 0, radius)
      bubble.fill({ color: point.color, alpha: 0.7 })
      bubble.stroke({ color: point.color, width: 2, alpha: 1 })
    })

    chart.addChild(group)
  })

  app.stage.addChild(chart)
  return chart
}

For the Konva alternative when a React-friendly 2D canvas library with built-in drag-and-drop, Transformer selection handles, and simpler state management for document editor use cases is preferred — Konva’s react-konva integration is more idiomatic for React developers, while PixiJS is better for games and high-performance rendering with thousands of objects, see the Konva guide. For the Three.js/React Three Fiber alternative when 3D WebGL rendering with geometry, lighting, physics, and PBR materials is needed — PixiJS only does 2D while Three.js handles the full 3D scene graph with cameras, shaders, and post-processing, see the React Three Fiber guide. The Claude Skills 360 bundle includes PixiJS skill sets covering game loops, particle systems, and interactive graphics. Start with the free tier to try 2D WebGL generation.

Keep Reading

Frontend

Claude Code for Chart.js Advanced: Custom Plugins and Mixed Charts

Advanced Chart.js patterns with Claude Code — chart.register() for tree-shaking, mixed chart types combining bar and line, custom plugin API with beforeDraw and afterDatasetsDraw hooks, ScriptableContext for computed colors, ChartDataLabels plugin for value labels, chartjs-plugin-zoom for pan and zoom, custom gradient fills via ctx.createLinearGradient, ChartJS annotation plugin for threshold lines, streaming data with chartjs-plugin-streaming, and react-chartjs-2 with useRef and chart instance.

6 min read Jun 27, 2027
Frontend

Claude Code for Nivo: Rich SVG and Canvas Charts

Build rich data visualizations with Nivo and Claude Code — ResponsiveLine and ResponsiveBar for adaptive charts, ResponsiveHeatMap for matrix data, ResponsiveTreeMap for hierarchal data, ResponsiveSunburst for nested proportions, ResponsiveChord for relationship diagrams, ResponsiveCalendar for activity heat maps, ResponsiveNetwork for force graphs, NivoTheme for consistent styling, tooltip customization with sliceTooltip, and motion config for spring animations.

6 min read Jun 26, 2027
Frontend

Claude Code for Victory Charts: React Native and Web Charts

Build cross-platform charts with Victory and Claude Code — VictoryChart, VictoryLine, VictoryBar, and VictoryScatter for web and React Native, VictoryPie for donut charts, VictoryArea for stacked areas, VictoryAxis for custom axes, VictoryTooltip and VictoryVoronoiContainer for hover tooltips, VictoryBrushContainer for range selection, VictoryZoomContainer for pan and zoom, VictoryLegend for series labels, custom theme with VictoryTheme, and VictoryStack for grouped bars.

6 min read Jun 25, 2027

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free