P

Pro Canvas Design Tool Suite

Professional-grade skill designed for create visual art in PNG and PDF formats. Built for Claude Code with best practices and real-world patterns.

SkillCommunitycreativev1.0.0MIT
0 views0 copies

Canvas Design Tool Suite

Full-featured HTML5 Canvas design toolkit for building interactive graphics editors, image manipulation tools, drawing applications, and visual design systems using Canvas API and WebGL.

When to Use This Skill

Choose Canvas Design Tool when:

  • Building interactive image editors or drawing tools
  • Creating custom canvas-based UI components
  • Implementing image filters, transformations, and effects
  • Building annotation or markup tools for web applications
  • Creating games or interactive visual experiences

Consider alternatives when:

  • Need vector graphics — use SVG or a library like Paper.js
  • Need 3D rendering — use Three.js or WebGL directly
  • Need print-quality output — use PDF generation libraries

Quick Start

# Activate canvas design tool claude skill activate pro-canvas-design-tool-suite # Build a drawing tool claude "Build a canvas-based drawing tool with brush, eraser, and shape tools" # Create an image editor claude "Create a canvas image editor with crop, rotate, and filter capabilities"

Example: Interactive Drawing Canvas

class DrawingCanvas { private canvas: HTMLCanvasElement; private ctx: CanvasRenderingContext2D; private isDrawing = false; private lastPoint: { x: number; y: number } | null = null; private tool: 'brush' | 'eraser' | 'line' | 'rect' = 'brush'; private color = '#000000'; private lineWidth = 3; private history: ImageData[] = []; private historyIndex = -1; constructor(container: HTMLElement, width: number, height: number) { this.canvas = document.createElement('canvas'); this.canvas.width = width; this.canvas.height = height; this.ctx = this.canvas.getContext('2d')!; container.appendChild(this.canvas); this.setupEvents(); this.saveState(); } private setupEvents() { this.canvas.addEventListener('pointerdown', (e) => { this.isDrawing = true; this.lastPoint = this.getPoint(e); this.ctx.beginPath(); this.ctx.moveTo(this.lastPoint.x, this.lastPoint.y); }); this.canvas.addEventListener('pointermove', (e) => { if (!this.isDrawing || !this.lastPoint) return; const point = this.getPoint(e); this.ctx.strokeStyle = this.tool === 'eraser' ? '#ffffff' : this.color; this.ctx.lineWidth = this.lineWidth; this.ctx.lineCap = 'round'; this.ctx.lineJoin = 'round'; this.ctx.lineTo(point.x, point.y); this.ctx.stroke(); this.lastPoint = point; }); this.canvas.addEventListener('pointerup', () => { this.isDrawing = false; this.lastPoint = null; this.saveState(); }); } private getPoint(e: PointerEvent) { const rect = this.canvas.getBoundingClientRect(); return { x: (e.clientX - rect.left) * (this.canvas.width / rect.width), y: (e.clientY - rect.top) * (this.canvas.height / rect.height), }; } saveState() { this.historyIndex++; this.history = this.history.slice(0, this.historyIndex); this.history.push(this.ctx.getImageData(0, 0, this.canvas.width, this.canvas.height)); } undo() { if (this.historyIndex > 0) { this.historyIndex--; this.ctx.putImageData(this.history[this.historyIndex], 0, 0); } } redo() { if (this.historyIndex < this.history.length - 1) { this.historyIndex++; this.ctx.putImageData(this.history[this.historyIndex], 0, 0); } } }

Core Concepts

Canvas API Categories

CategoryMethodsUse Case
DrawingfillRect, strokeRect, arc, bezierCurveToShapes and paths
TextfillText, strokeText, measureTextText rendering
ImagesdrawImage, getImageData, putImageDataImage manipulation
Transformstranslate, rotate, scale, transformPositioning and rotation
CompositingglobalCompositeOperation, globalAlphaBlending and layering
Clippingclip, save, restoreMasked rendering
GradientscreateLinearGradient, createRadialGradientColor gradients
PatternscreatePatternRepeating textures

Image Filters

FilterDescriptionImplementation
GrayscaleConvert to grayscale(r + g + b) / 3 per pixel
BrightnessAdjust brightnessAdd/subtract constant per channel
ContrastAdjust contrast((value - 128) * factor) + 128
BlurGaussian blurConvolution kernel averaging
SharpenEnhance edgesConvolution with center-weighted kernel
SepiaVintage warm toneMatrix transformation on RGB
InvertColor inversion255 - value per channel
// Image filter implementation function applyFilter(ctx: CanvasRenderingContext2D, filter: string) { const { width, height } = ctx.canvas; const imageData = ctx.getImageData(0, 0, width, height); const data = imageData.data; for (let i = 0; i < data.length; i += 4) { const r = data[i], g = data[i+1], b = data[i+2]; switch (filter) { case 'grayscale': const gray = 0.299 * r + 0.587 * g + 0.114 * b; data[i] = data[i+1] = data[i+2] = gray; break; case 'sepia': data[i] = Math.min(255, r * 0.393 + g * 0.769 + b * 0.189); data[i+1] = Math.min(255, r * 0.349 + g * 0.686 + b * 0.168); data[i+2] = Math.min(255, r * 0.272 + g * 0.534 + b * 0.131); break; case 'invert': data[i] = 255 - r; data[i+1] = 255 - g; data[i+2] = 255 - b; break; } } ctx.putImageData(imageData, 0, 0); }

Configuration

ParameterDescriptionDefault
canvas_widthCanvas width in pixels800
canvas_heightCanvas height in pixels600
backgroundBackground color#ffffff
default_toolInitial active toolbrush
max_historyMaximum undo history states50
export_qualityJPEG export quality (0-1)0.92
pixel_ratioDevice pixel ratio for HiDPIwindow.devicePixelRatio
smoothingImage smoothing enabledtrue

Best Practices

  1. Handle device pixel ratio for sharp rendering on HiDPI displays — Scale the canvas backing store by devicePixelRatio while keeping CSS size unchanged. Without this, canvas content appears blurry on retina displays: canvas.width = cssWidth * dpr; canvas.style.width = cssWidth + 'px'.

  2. Use offscreen canvases for complex compositing — Render layers, filters, and temporary drawings on offscreen canvases, then composite them onto the main canvas. This enables non-destructive editing and layer-based workflows.

  3. Implement efficient undo/redo with state snapshots — Store ImageData snapshots for simple editors, but for complex editors with many objects, store command objects (command pattern) that can be applied or reversed without storing full pixel data.

  4. Throttle rendering to requestAnimationFrame — Never render on every mouse event. Batch drawing operations into requestAnimationFrame callbacks to maintain 60fps smoothness and prevent janky, dropped-frame behavior.

  5. Use pointer events instead of mouse events — Pointer events handle mouse, touch, and stylus input uniformly. They also provide pressure sensitivity data for stylus-aware drawing applications and handle multi-touch gestures naturally.

Common Issues

Canvas appears blurry on high-DPI (retina) displays. The canvas element's internal resolution defaults to CSS pixels, not device pixels. Set canvas.width = displayWidth * devicePixelRatio and ctx.scale(devicePixelRatio, devicePixelRatio) while keeping CSS dimensions at the display size.

Memory usage grows unbounded with undo history. Each ImageData snapshot for a 1920x1080 canvas is ~8MB. Limit history depth to 30-50 states, or compress older states to PNG blobs (via canvas.toBlob()) which are 10-50x smaller. For production editors, use delta encoding that stores only changed regions.

Touch drawing is laggy compared to mouse drawing. Touch events fire at lower frequency than mouse events on many devices. Use PointerEvent.getCoalescedEvents() to access all intermediate points between event firings, then draw smooth curves through all points for responsive, gap-free strokes.

Community

Reviews

Write a review

No reviews yet. Be the first to review this template!

Similar Templates