0.0.3 • Published 6 months ago

react-pixel-art-canvas v0.0.3

Weekly downloads
-
License
MIT
Repository
github
Last release
6 months ago

Alpha status - expect breaking changes

Demo https://stackblitz.com/edit/react-pixel-art-canvas

React Pixel Art Canvas

Demo https://stackblitz.com/edit/react-pixel-art-canvas

A simple, customizable, and headless pixel art canvas component for React applications.

Installation

npm install react-pixel-art-canvas
# or
yarn add react-pixel-art-canvas

Basic Concept

This is a "as headless as possible" HTML Canvas pixel art creator React component. It was originally embedded into an app I was building but I wanted something less tied to a particular UI/CSS/Component framework so I abstracted it out into it's own thing. It's very much built for my current usecase but I figured it might work for someone else too (or at least have some copy/pastable bits).

It's composed of 3 canvas elements all stacked up as "layers"

background | drawing | foreground

background - is used to add background images that you want to "trace" or reference. It can be toggled on/off.

drawing - this is were all the actually drawing happens. Cannot be toggled on/off. Has an optional history for undo functionality.

foreground - this is where we create a grid based on the pixel size set/selected. It can be toggled on/off

Usage

See demo/src/App.tsx for a working example

import { useRef } from "react";
import {
  ReactPixelArtCanvas,
  BackgroundCanvas,
  DrawingCanvas,
  ForegroundCanvas
} from "react-pixel-art-canvas";
import type { CanvasRef, Tool } from "react-pixel-art-canvas";

function App() {
  // Canvas setup - this could be stored in state
  // canvas width/height should be divisible by GRID_SIZE(s)
  const GRID_SIZE = 16;
  const CANVAS_SIZE = {
    width: 896,
    height: 896,
  };
  // This will give you a direct React.ref to each canvas type
  const drawingCanvasRef = useRef<CanvasRef>(null);
  const backgroundCanvasRef = useRef<CanvasRef>(null);
  const foregroundCanvasRef = useRef<CanvasRef>(null);

  // All canvasRefs share a common interafce (CanvasRef)
  // type CanvasRef = {
  //   clearCanvas: () => void;
  //   exportSVG: () => string | undefined;
  //   exportPNG: () => string | undefined;
  //   undoHistory: () => void; // only available for the drawing canvas
  //   canvas: HTMLCanvasElement | null;
  // };

  // Example of using the CanvasRef actions
  const handleClear = () => {
    drawingCanvasRef.current.clearCanvas();
  }

  const handleExportToSVG = () => {
    drawingCanvasRef.current.exportSVG();
  }

  const handleExportPNG = () => {
    drawingCanvasRef.current.exportPNG;
  }

  const handleUndo = () => {
    // history must be set to `true` in the DrawingCanvas props for undo functionality
    drawingCanvasRef.current.undoHistory();
  }

  const drawingCanvasCtx = drawingCanvasRef.current.canvas.getContext("2d");
  // use any Canvas API methods
  // https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API
  drawingCanvasCtx.putImage(...)

  // Use the Canvas components with your desired settings
  // Feel free to only use one or some of the child Canvas components
  return (
    <>
      <ReactPixelArtCanvas
        width={CANVAS_SIZE.width}
        height={CANVAS_SIZE.height}
        styles={{ border: "1px solid #ccc" }}
      >
        <BackgroundCanvas
          ref={backgroundCanvasRef}
          gridSize={gridSize}
          width={CANVAS_SIZE.width}
          height={CANVAS_SIZE.height}
          backgroundImage={backgroundImage}
          backgroundOpacity={backgroundOpacity}
          backgroundVisible={showBackground}
        />
        <DrawingCanvas
          ref={drawingCanvasRef}
          gridSize={gridSize}
          width={CANVAS_SIZE.width}
          height={CANVAS_SIZE.height}
          selectedColor={color}
          selectedTool={tool}
          history={true} // defaults to `false`
        />
        <ForegroundCanvas
          ref={foregroundCanvasRef}
          gridSize={gridSize}
          width={CANVAS_SIZE.width}
          height={CANVAS_SIZE.height}
          foregroundVisible={showForeground}
          gridStrokeColor="#d1d1d1"
        />
      </ReactPixelArtCanvas>
    </>
  );
}

Online Demo

Online Demo https://stackblitz.com/edit/react-pixel-art-canvas

Running the Demo Locally

Demo created with the default Vite React-TS template npm create vite@latest my-app -- --template react-ts

To run the demo application locally:

  1. Clone the repository
git clone https://github.com/geoffmiller/react-pixel-art-canvas.git
cd react-pixel-art-canvas
  1. Change to the demo directoy
cd demo
  1. Start the demo app
npm install
npm start

The demo will be available at http://localhost:5173

It's "unstyled" in the sense that I did not modify the default CSS that ships with the Vite react-ts template

TODO

  • Add undo/history
  • Fix undo with "clear" canvas state. History breaks after a sencond undo action if a clear action happened.
  • Add a max history size setting (each history state item is ~30kb).
  • Write tests.
  • Work on responsive design.
  • Decide if the image importer/cropper/alignment code should live in here.
  • Research better flood fill algorithm performance (plenty fast as is).
0.0.3

6 months ago

0.0.2

6 months ago

0.0.1

6 months ago