|
| 1 | +<h1 align="center"> |
| 2 | + pixel-draw.renderer |
| 3 | +</h1> |
| 4 | + |
| 5 | +<p align="center"> |
| 6 | + JollyPixel Pixel Art canvas renderer |
| 7 | +</p> |
| 8 | + |
| 9 | +## About |
| 10 | + |
| 11 | +`@jolly-pixel/pixel-draw.renderer` is a browser-based library for editing pixel-art textures. It provides zoom, pan, brush painting, right-click color picking, and an SVG cursor overlay, built around a SOLID-structured class architecture. |
| 12 | + |
| 13 | +## Features |
| 14 | + |
| 15 | +- **Zoom & pan** — smooth mouse-wheel zoom with configurable sensitivity and range; middle-click pan in any mode |
| 16 | +- **Brush painting** — configurable square brush with adjustable size, color, and opacity |
| 17 | +- **Color picking** — right-click eyedropper that reads the master canvas pixel |
| 18 | +- **Transparency support** — configurable checkerboard background renders beneath transparent pixels |
| 19 | +- **SVG brush highlight** — grid-aligned SVG overlay tracks the cursor in real time |
| 20 | +- **Dual-canvas architecture** — a master canvas (full resolution, off-screen) and a working canvas (viewport-cropped, on-screen) maintain pixel-perfect fidelity at any zoom level |
| 21 | +- **Mode switching** — `"paint"` and `"move"` modes control how mouse events are interpreted |
| 22 | + |
| 23 | +## Getting Started |
| 24 | + |
| 25 | +This package is available in the Node Package Repository and can be easily installed with [npm][npm] or [yarn][yarn]. |
| 26 | + |
| 27 | +```bash |
| 28 | +$ npm i @jolly-pixel/pixel-draw.renderer |
| 29 | +# or |
| 30 | +$ yarn add @jolly-pixel/pixel-draw.renderer |
| 31 | +``` |
| 32 | + |
| 33 | +## Usage Examples |
| 34 | + |
| 35 | +### Minimal setup |
| 36 | + |
| 37 | +```ts |
| 38 | +import { CanvasManager } from "@jolly-pixel/pixel-draw.renderer"; |
| 39 | + |
| 40 | +const manager = new CanvasManager({ |
| 41 | + texture: { size: 64 }, |
| 42 | + zoom: { |
| 43 | + range: [0.5, 40], |
| 44 | + sensitivity: 0.002 |
| 45 | + }, |
| 46 | +}); |
| 47 | + |
| 48 | +const container = document.getElementById("editor-container")!; |
| 49 | +manager.reparentCanvasTo(container); |
| 50 | +manager.resize(); |
| 51 | +manager.centerTexture(); |
| 52 | +``` |
| 53 | + |
| 54 | +### Drawing pixels programmatically |
| 55 | + |
| 56 | +```ts |
| 57 | +import { CanvasManager } from "@jolly-pixel/pixel-draw.renderer"; |
| 58 | + |
| 59 | +const manager = new CanvasManager({ |
| 60 | + texture: { size: 32 } |
| 61 | +}); |
| 62 | +manager.reparentCanvasTo(document.body); |
| 63 | + |
| 64 | +// Draw a red pixel at texture position (10, 10) |
| 65 | +manager.textureBuffer.drawPixels( |
| 66 | + [{ x: 10, y: 10 }], |
| 67 | + { r: 255, g: 0, b: 0, a: 255 } |
| 68 | +); |
| 69 | +manager.render(); |
| 70 | +``` |
| 71 | + |
| 72 | +### Loading an existing texture |
| 73 | + |
| 74 | +```ts |
| 75 | +const img = new Image(); |
| 76 | +img.src = "/assets/sprite.png"; |
| 77 | +await img.decode(); |
| 78 | + |
| 79 | +manager.setTexture(img); |
| 80 | +``` |
| 81 | + |
| 82 | +### Configuring the brush |
| 83 | + |
| 84 | +```ts |
| 85 | +manager.brush.setColor("#FF6600"); |
| 86 | +manager.brush.setOpacity(0.8); |
| 87 | +manager.brush.setSize(3); |
| 88 | +``` |
| 89 | + |
| 90 | +### Switching modes |
| 91 | + |
| 92 | +```ts |
| 93 | +manager.setMode("move"); // left-click pans |
| 94 | +manager.setMode("paint"); // left-click draws |
| 95 | +``` |
| 96 | + |
| 97 | +## Running the Examples |
| 98 | + |
| 99 | +```bash |
| 100 | +npm run dev -w @jolly-pixel/pixel-draw.renderer |
| 101 | +``` |
| 102 | + |
| 103 | +Open `http://localhost:5173` to see the interactive demo. |
| 104 | + |
| 105 | +## API |
| 106 | + |
| 107 | +| Class | Description | |
| 108 | +|---|---| |
| 109 | +| [`CanvasManager`](./docs/CanvasManager.md) | Top-level coordinator — the primary public API | |
| 110 | +| [`Viewport`](./docs/Viewport.md) | Camera position, zoom level, and coordinate transforms | |
| 111 | +| [`BrushManager`](./docs/BrushManager.md) | Brush size, color, opacity, and affected-pixel computation | |
| 112 | +| `TextureBuffer` | Dual-canvas pixel storage and image-data access | |
| 113 | +| `CanvasRenderer` | Visible canvas drawing and checkerboard background | |
| 114 | +| `InputController` | Mouse event routing to drawing and pan actions | |
| 115 | +| `SvgManager` | SVG brush-highlight overlay | |
| 116 | + |
| 117 | +## Troubleshooting |
| 118 | + |
| 119 | +**Canvas is blank after mounting** |
| 120 | +Call `manager.resize()` after `reparentCanvasTo()` to let the renderer read the parent element's dimensions, then call `manager.centerTexture()`. |
| 121 | + |
| 122 | +**Pixels appear at the wrong position** |
| 123 | +Pass `{ bounds: canvas.getBoundingClientRect() }` when calling `viewport.getMouseTexturePosition()`. Stale bounding rects cause offset errors. |
| 124 | + |
| 125 | +**Master canvas is slow to initialize** |
| 126 | +`TextureBuffer` pre-allocates a canvas at `maxSize` (default `2048`). In test environments or when large textures are unnecessary, set `texture.maxSize` to a smaller value such as `64`. |
| 127 | + |
| 128 | +## Contributors Guide |
| 129 | + |
| 130 | +If you are a developer **looking to contribute** to the project, you must first read the [CONTRIBUTING][contributing] guide. |
| 131 | + |
| 132 | +Once you have finished your development, check that the tests (and linter) are still good by running the following script: |
| 133 | + |
| 134 | +```bash |
| 135 | +$ npm run test |
| 136 | +$ npm run lint |
| 137 | +``` |
| 138 | + |
| 139 | +> [!CAUTION] |
| 140 | +> In case you introduce a new feature or fix a bug, make sure to include tests for it as well. |
| 141 | +
|
| 142 | +## License |
| 143 | + |
| 144 | +MIT |
| 145 | + |
| 146 | +<!-- Reference-style links for DRYness --> |
| 147 | + |
| 148 | +[npm]: https://docs.npmjs.com/getting-started/what-is-npm |
| 149 | +[yarn]: https://yarnpkg.com |
| 150 | +[contributing]: ../../CONTRIBUTING.md |
0 commit comments