Plugin

etchasketch.js

The classic 1960s toy as a drop-in web plugin. Arrow keys spin the knobs, the pen follows on a red bezel with an aluminum-gray screen. Click a knob — or shake your phone — to clear.

npm install @goboldlyforward/etchasketch

Playground

Try every knob

Adjust the controls — the code block updates with the exact options to recreate this configuration. Hit Copy and paste into your project.

Settings

Screen color aluminum
Live code

Press ↑ ↓ ← → (or WASD) to move the pen — the knobs spin to match. Hold two arrows for diagonals. Click either knob to clear.

Install

Drop it in

No build step, no framework — one stylesheet, one script, one container.

<link rel="stylesheet" href="path/to/etchasketch.css">
<script src="path/to/etchasketch.js"></script>

<div id="toy"></div>

<script>
  const sketch = new EtchASketch('#toy', {
    penColor:    '#1f1f1f',
    penWidth:    2,
    stepPx:      1.8,
    screenColor: '#b8b8a9',
  });

  // Live tuning — every option is hot-swappable.
  sketch.setOptions({ cursor: true });
</script>

new EtchASketch(target, options?) mounts the red bezel + knobs + canvas into target (a selector or element) and starts listening for arrow keys. Mount as many as you like on a page — each is its own instance.

Controls

What every input does

The left knob is the horizontal axis; the right knob is the vertical axis — just like the real toy.

InputEffect
→ / DPen right; left knob spins clockwise
← / APen left; left knob spins counterclockwise
↓ / SPen down; right knob spins clockwise
↑ / WPen up; right knob spins counterclockwise
Hold two arrowsDiagonal — normalized so it's the same speed as a single arrow
Click either knobClear the screen (with shake animation)
Shake the phoneClear (via DeviceMotionEvent; iOS needs enableShake())
Mouse / touch dragDraw — only when cursor: true

Reference

Options

Pass these at construction, or pass any of them later via setOptions().

new EtchASketch('#toy', {
  penColor:          '#1f1f1f',  // CSS color of the line
  penWidth:          2,          // stroke width in CSS px
  stepPx:            1.8,        // pen pixels per frame per held arrow
  screenColor:       '#b8b8a9',  // background fill (defaults to aluminum gray)
  chrome:            true,       // render the red bezel + knobs (false = headless canvas)
  cursor:            false,      // allow mouse/touch drag to draw (off = classic mode)
  shakeToErase:      true,       // listen for devicemotion and clear on a hard shake
  shakeThreshold:    22,         // accelerometer magnitude required (m/s²)
  knobsClickToClear: true,       // click either knob to clear
  knobDegPerPx:      2.2,        // how fast each knob spins per pen pixel
});

Methods

sketch.clear();                        // wipe the screen + run the shake animation
sketch.setOptions({ ... });            // merge + apply (hot-swap any option)
sketch.getDataURL('image/png');        // PNG data URL of the current drawing
sketch.enableShake();                  // call from a user gesture on iOS to grant motion access
sketch.resetPenTo(x, y);               // move the pen without drawing a line
sketch.destroy();                      // tear down DOM + listeners

Recipes

Cursor mode

By default, only the keyboard moves the pen. That keeps the experience faithful to the original 1960s Magic Screen — and means mouse/touch input on the canvas does nothing. To enable click-drag and finger-drag drawing:

const sketch = new EtchASketch('#toy', { cursor: true });
// ...or toggle it later:
sketch.setOptions({ cursor: true });

When cursor: true, the canvas shows a crosshair cursor, the pen jumps to wherever the user presses, and dragging strokes a line that the knobs also follow.

Headless mode

Skip the red bezel + knobs entirely and paint the interaction model onto your own design:

new EtchASketch('#raw', { chrome: false });

Your host element gets just the canvas. Arrow keys still draw; cursor: true still enables drag drawing.

Phone shake to clear (iOS)

Android and desktop browsers fire devicemotion events without a permission grant — shake works out of the box. iOS 13+ requires a one-time grant tied to a user gesture:

document.getElementById('btn-enable').addEventListener('click', () => {
  sketch.enableShake();   // shows the iOS permission dialog
});