Skip to content

kyechan99/scratcher.js

Repository files navigation

scratcher.js

@scratcher.js

@scratcher.js/core @scratcher.js/react @scratcher.js/vue @scratcher.js/svelte
codecov license TypeScript

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 Β· ν•œκ΅­μ–΄ Β· ...

Why?

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.

Features

  • πŸ–±οΈ 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

Packages

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

Installation

# Vanilla JS
npm i @scratcher.js/core

# React
npm i @scratcher.js/react

# Vue
npm i @scratcher.js/vue

# Svelte
npm i @scratcher.js/svelte

Quick Start

The 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!'),
};

React

import { Scratcher } from '@scratcher.js/react';

<Scratcher {...scratcherConfig}>
  <div className="reward">You found it!</div>
</Scratcher>;

Vue

<Scratcher v-bind="scratcherConfig">
  <div class="reward">You found it!</div>
</Scratcher>

Svelte

<script lang="ts">
  import { Scratcher } from '@scratcher.js/svelte';
</script>

<Scratcher {...scratcherConfig}>
  <div class="reward">You found it!</div>
</Scratcher>

Vanilla JS

import { Scratcher } from '@scratcher.js/core';

const canvas = document.getElementById('my-canvas') as HTMLCanvasElement;
const scratcher = new Scratcher(scratcherConfig);
scratcher.bindCanvas(canvas);

Configuration

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.

Examples

You can also implement deeper features by utilizing Scratcher's basic functions.

Contributing

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.

License

MIT Β© 2026

About

🎟️ A lightweight library for building expressive Scratch interactions

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Sponsor this project

 

Contributors