A lightweight library for building expressive Scratch interactions.
Scratcher.js lets you drop a "scratchcard experience" into your product with a few lines of config β event reveals, coupon codes, game-style reward UIs, anywhere user engagement matters.
Docs: English Β· νκ΅μ΄ Β· ...
Building a scratch UI from scratch means handling input events, progress calculation, completion thresholds, rendering performance, and reimplementing it for every framework. Scratcher.js consolidates that work into a single core engine and ships thin bindings for each framework.
- π±οΈ Mouse & touch scratch interaction
- π¨ Adjustable brush size, sensitivity, cover/background images, custom rendering
- π Progress tracking, completion detection, and lifecycle callbacks
- π― Measure progress over the whole canvas or a specific area (rect / image mask)
- π§© Framework bindings for React, Vue, and React Native β same options everywhere
- π¦ Written in TypeScript with full type definitions
| Package | Description |
|---|---|
@scratcher.js/core |
Framework-agnostic scratch engine and types |
@scratcher.js/react |
React bindings |
@scratcher.js/vue |
Vue bindings |
@scratcher.js/svelte |
Svelte bindings |
# Vanilla JS
npm i @scratcher.js/core
# React
npm i @scratcher.js/react
# Vue
npm i @scratcher.js/vue
# Svelte
npm i @scratcher.js/svelteThe same config object works across every binding β only the way you pass it in changes.
const scratcherConfig = {
width: 300,
height: 150,
brushSize: 30,
completionThreshold: 0.7,
cover: '#ccc',
onProgress: snap => console.log('Progress:', snap.progress),
onComplete: () => alert('Scratching complete!'),
};import { Scratcher } from '@scratcher.js/react';
<Scratcher {...scratcherConfig}>
<div className="reward">You found it!</div>
</Scratcher>;<Scratcher v-bind="scratcherConfig">
<div class="reward">You found it!</div>
</Scratcher><script lang="ts">
import { Scratcher } from '@scratcher.js/svelte';
</script>
<Scratcher {...scratcherConfig}>
<div class="reward">You found it!</div>
</Scratcher>import { Scratcher } from '@scratcher.js/core';
const canvas = document.getElementById('my-canvas') as HTMLCanvasElement;
const scratcher = new Scratcher(scratcherConfig);
scratcher.bindCanvas(canvas);| Option | Type | Description | Default |
|---|---|---|---|
width * |
number |
Canvas width (px). Drawing-buffer size; framework wrappers can opt into responsive sizing via responsive prop. |
β |
height * |
number |
Canvas height (px). Drawing-buffer size. | β |
brushSize * |
number |
Brush diameter (px) | β |
cellSize |
number |
Grid cell size (px) for progress tracking. Lower = finer. | 16 |
completionThreshold |
number (0~1) |
Progress at which onComplete fires |
0.5 |
revealOnCompletion |
boolean |
Auto-clear the cover when threshold is reached | false |
cover |
string |
Cover color or image URL | '#b9c2ce' |
area |
RectArea | ImageArea |
Restrict progress measurement to a region | β |
callbacks |
object |
onProgress, onComplete, onScratchStart, etc |
β |
See the Configuration guide and API Reference for the full list.
You can also implement deeper features by utilizing Scratcher's basic functions.
- Default
- Custom Cover
- Custom Scratch
- Custom Area β Rect
- Custom Area β Image
- Using Images
- Async Reward
- Completion Animation
Issues and PRs are welcome. For bugs, please include a minimal reproduction. For feature ideas, open an issue first so we can align on scope.
MIT Β© 2026
