Skip to main content
Paint embeds jspaint.app, a web-based recreation of MS Paint, providing a full-featured drawing and image editing experience.

Features

  • Drawing Tools: Pencil, brush, line, curve, rectangle, ellipse, polygon
  • Selection Tools: Rectangular and free-form selection
  • Text Tool: Add text with different fonts
  • Color Picker: Full color palette and custom colors
  • Fill Tool: Bucket fill with color
  • Eraser: Multiple eraser sizes
  • Zoom: Magnifier tool and zoom controls
  • Image Operations: Flip, rotate, stretch/skew
  • File Operations: Open, save (PNG, BMP, JPEG)
  • Undo/Redo: Full history support

Component Structure

Location: src/WinXP/apps/Paint/index.jsx
function Paint({ onClose, isFocus }) {
  return (
    <div
      style={{
        width: '100%',
        height: '100%',
        position: 'relative',
      }}
    >
      <iframe
        src="https://jspaint.app"
        frameBorder="0"
        title="paint"
        style={{
          display: 'block',
          width: '100%',
          height: '100%',
          backgroundColor: 'rgb(192,192,192)',
        }}
      />
      {!isFocus && (
        <div
          style={{
            width: '100%',
            height: '100%',
            position: 'absolute',
            left: 0,
            top: 0,
          }}
        />
      )}
    </div>
  );
}

Configuration

From apps/index.jsx:
Paint: {
  name: 'Paint',
  header: { icon: paint, title: 'Untitled - Paint' },
  component: Paint,
  defaultSize: { width: 660, height: 500 },
  defaultOffset: getCenter(660, 500),
  resizable: true,
  minimized: false,
  maximized: shouldMaximize(660, 500, true),
  multiInstance: true, // Can open multiple instances
}

Focus Handling

The component uses an overlay to prevent iframe interaction when the window is not focused:
{!isFocus && (
  <div
    style={{
      width: '100%',
      height: '100%',
      position: 'absolute',
      left: 0,
      top: 0,
      // Transparent overlay blocks clicks
    }}
  />
)}
This is necessary because:
  • Iframes can capture all mouse events
  • Without the overlay, users couldn’t drag/resize the window
  • The overlay is removed when the window has focus

jspaint.app Features

Drawing Tools

  • Free-Form Select: Irregular selection areas
  • Select: Rectangular selection
  • Eraser: Multiple sizes
  • Fill With Color: Bucket fill
  • Pick Color: Eyedropper tool
  • Magnifier: Zoom in/out
  • Pencil: Single-pixel drawing
  • Brush: Various brush sizes
  • Airbrush: Spray paint effect
  • Text: Add text labels
  • Line: Draw straight lines
  • Curve: Draw bezier curves
  • Rectangle: Draw rectangles
  • Polygon: Draw polygons
  • Ellipse: Draw circles and ellipses
  • Rounded Rectangle: Draw rounded corners

File Menu

  • New
  • Open (from local filesystem)
  • Save (PNG, BMP, JPEG, GIF, TIFF, WebP)
  • Save As
  • Print
  • From Scanner or Camera
  • Exit

Edit Menu

  • Undo (Ctrl+Z)
  • Redo (Ctrl+Y)
  • Cut (Ctrl+X)
  • Copy (Ctrl+C)
  • Paste (Ctrl+V)
  • Clear Selection (Delete)
  • Select All (Ctrl+A)
  • Copy To
  • Paste From

View Menu

  • Tool Box
  • Color Box
  • Status Bar
  • Text Toolbar
  • Zoom submenu (Normal Size, Large Size, Custom, Show Grid, Show Thumbnail)
  • View Bitmap

Image Menu

  • Flip/Rotate (Flip horizontal, Flip vertical, Rotate 90°, Rotate 180°)
  • Stretch/Skew
  • Invert Colors
  • Attributes (Width, Height, Units)
  • Clear Image
  • Draw Opaque

Colors Menu

  • Edit Colors
  • Get Colors (import palette)
  • Save Colors (export palette)

Help Menu

  • Help Topics
  • About Paint

Keyboard Shortcuts

  • Ctrl+Z: Undo
  • Ctrl+Y: Redo
  • Ctrl+X: Cut
  • Ctrl+C: Copy
  • Ctrl+V: Paste
  • Ctrl+A: Select All
  • Delete: Clear Selection
  • Ctrl+N: New Image
  • Ctrl+O: Open File
  • Ctrl+S: Save
  • Ctrl+P: Print

Color Palette

The color palette includes:
  • 28 default colors
  • Custom color editor with RGB/HSV controls
  • Recent colors
  • Primary and secondary color selection

Usage Example

import { Paint } from 'src/WinXP/apps';

function Desktop() {
  const [focusedWindow, setFocusedWindow] = useState(null);
  
  return (
    <Window 
      title="Untitled - Paint"
      onFocus={() => setFocusedWindow('paint')}
    >
      <Paint 
        onClose={handleClose}
        isFocus={focusedWindow === 'paint'}
      />
    </Window>
  );
}

Iframe Security

The iframe uses standard security attributes:
<iframe
  src="https://jspaint.app"
  frameBorder="0"
  title="paint"
  // No sandbox restrictions - jspaint needs full access
/>

Limitations

  • Requires internet connection (loads from jspaint.app)
  • Cannot customize the jspaint UI
  • File operations use browser download/upload APIs
  • No direct integration with Web XP file system
  • Iframe communication is limited

Offline Alternative

To use Paint offline, you could:
  1. Host jspaint locally:
git clone https://github.com/1j01/jspaint
cd jspaint
npm install
npm run build
  1. Update the iframe source:
<iframe
  src="/local-jspaint/index.html"
  frameBorder="0"
  title="paint"
/>

Styling

The component sets the iframe background to match classic Paint:
backgroundColor: 'rgb(192,192,192)'
This gray color matches the Windows XP Paint application.

Multi-Instance Support

Paint supports multiple instances, allowing users to:
  • Edit multiple images simultaneously
  • Copy/paste between Paint windows
  • Work on different canvases at the same time

Performance

Since Paint is an iframe:
  • Loads independently from main application
  • Runs in its own rendering context
  • Doesn’t block main thread
  • Has its own memory allocation

Future Enhancements

Possible improvements:
  • PostMessage integration with Web XP file system
  • Save images to virtual file system
  • Open images from My Computer
  • Custom color palette persistence
  • Integration with clipboard across Web XP

Build docs developers (and LLMs) love