KQ-1485 · PAPER/BALL

Paper Ball

A discard control you crumple and throw: holding the note folds a 6×6 mesh of the sheet inward along seeded creases into a lumpy paper ball, the facets that turn over going dark and the handwriting twisting with the paper, while letting go early springs it flat on springs.snap. A formed ball is tossed on a true ballistic arc into a wire basket, or dragged 1:1 and thrown with the release velocity into a small room whose floor, walls and the basket's rim lips it bounces off; a miss rolls to rest and glides home on springs.glide, and a ball that drops between the lips rocks the basket on springs.recoil. Space or Enter held crumples like a press, Delete crumples and tosses in one motion, and Escape smooths the sheet out.

KQ-1485 · PAPER/BALL
Hold to crumple, release to toss. Delete crumples and tosses. Escape smooths it out.

note up · hold it to crumple

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/paper-ball

Props

text
string
default "Call the printer about Friday's proofs"
What the note says, wrapped to three short lines on the sheet.
label
string
default "Discard note"
The note's accessible name, read before its text.
discardedLabel
string
default "Note discarded"
The accessible name once the note is in the basket.
discarded / defaultDiscarded
boolean
default — / false
Whether the note is in the basket. Setting it back to false puts a fresh note up; setting it true drops the ball straight in.
onDiscardedChange
(discarded: boolean) => void
default —
Fires with true when the ball lands in the basket.
onThrow
(result: "in" | "miss") => void
default —
Fires when a throw ends: in the basket, or at rest on the floor.
onCrumpleChange
(crumpled: boolean) => void
default —
Fires when the ball forms and when the sheet is smoothed out again.
onProgressChange
(progress: number) => void
default —
Fires while the hold charges or the sheet smooths, with how crumpled it is in tenths (0–10).
hold
number
default 600
How long a hold takes to make a ball, in ms; a re-press continues from where the sheet is.
crumple
number
default 0.8
How tight the ball is, 0 to 1: a loose wad (bigger, softer creases) to a small, hard, deeply creased ball.
arc
number
default 0.5
The toss's height, 0 to 1: a flat line drive to a high lob. The arc is solved so it always drops through the mouth.
bounce
number
default 0.5
How lively the floor, walls and rim lips are, 0 to 1 (restitution 0.2 to 0.72).
gravity
number
default 1800
Gravity in scene units per second squared; the scene is 300 units wide.
seed
number
default 7
The crease pattern and the ball's lumps.
paper
string
default "oklch(from var(--warn) 0.93 0.07 h)"
The note's paper, any CSS colour; a pigment at fixed lightness so it reads the same in both themes.
ink
string
default "oklch(from var(--warn) 0.36 0.07 h)"
The handwriting's colour.
size
"sm" | "md" | "lg"
default "md"
The scene's max width: 260, 300 or 340px; its height follows the 5:3 scene.
sound
boolean
default false
Play a crinkle at every fifth of the hold, a crisp one on the toss and a thud on every landing, scaled by how hard it hits.
disabled
boolean
default false
Takes the note out of the tab order and ignores presses.
className
string
default —
Classes for the root, which is w-full up to its size's max width.