Library / SDK
mortspace/playcaptcha avatar
mortspace/playcaptcha

playcaptcha: a claw-machine captcha for React

A claw-machine human check for React — grab the right toy to prove you're human

527 stars31 forksTypeScriptMIT

At a glance

What is it?
playcaptcha replaces the checkbox with a claw machine: the user drives a joystick, grabs a toy and drops it in a hatch. It is a React component, MIT licensed, and it checks that someone is playing, not who they are.
Who is it for?
Adopt playcaptcha when you want a friction-light, keyboard-accessible interaction in front of a signup or download form, and you already have server-side verification behind it. Do not adopt it as your only bot defence, and do not adopt it if you cannot serve static files under /toys/ and /playcaptcha.svg, or if you need a challenge that adapts to risk.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 35 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 8, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What playcaptcha is for, and who it is not for

The README is blunt about the scope: "this checks that someone is *playing*, not who they are. Keep it in front of your real checks, don't replace them with it." That sentence is the whole product decision. playcaptcha is an interaction gate, not an identity check and not a risk score. It sits in front of a signup form, a download button or a comment box and makes the first action cost a few seconds of hand-eye coordination.

The audience is React teams that already run server-side verification and find the standard checkbox or image grid hostile to their users. It is a poor fit for anyone who needs a captcha to scale its difficulty with traffic patterns, because nothing in the README describes a scoring signal, a token, or a callback that returns anything other than a successful grab. It is also a poor fit for non-React front ends: the package ships a React component and a CSS file, and the peer dependencies are react and react-dom at version 18 or above.

How the claw machine works under the hood

There is no physics engine. The README states the motion is "damped springs and scripted phases in one rAF loop". That is the architecture in one line: a phase machine advances through states, and each phase computes a transform per frame, written directly to the DOM through refs. React state changes only when the phase changes, so the component does not re-render sixty times a second while the claw swings.

The consequence is that the difficulty is authored, not simulated. The claw does not collide with the toy pile in a general sense; the phases decide when the claw is over a toy and what happens next. The README describes the outcome: the claw dives, grabs whatever is under it, and if it is the wrong toy the catch "bounces off the lid and goes back on the pile". A right toy verifies. That also means the interaction is deterministic enough to reason about, which matters if you ever need to explain to a support team why a user failed.

The loop is also the reason the README claims it stays smooth on weak devices. Whether that holds on your target hardware is something only your own profiling can answer; the repository does not publish frame timings.

Installing playcaptcha and getting a first verification

The package is on npm and installs with a single command. The README gives this exact line:

bash
npm install playcaptcha

After that, the step people miss is the assets. The component does not bundle the toy renders into the JavaScript; it fetches them at runtime from static paths. The README says to copy the `assets/` folder "into whatever your app serves statically", because the component looks for toy renders under `/toys/` and the logo at `/playcaptcha.svg`. If those paths 404, you get a captcha with missing art. The `assetBase` prop moves that root if your static layout differs.

With the assets in place, the component is a normal import. Note the separate CSS entry point, which is exported as `playcaptcha/clawcaptcha.css` in package.json:

tsx
import { ClawCaptcha } from 'playcaptcha'
import 'playcaptcha/clawcaptcha.css'

<ClawCaptcha onVerify={() => unlock()} />

Leaving `target` off means every mount asks for a different random toy. Pinning one is a single prop, and the README lists the 12 valid ids as duck, bear, panda, bunny, dino, penguin, fox, frog, whale, cat, puppy and unicorn:

tsx
<ClawCaptcha target="duck" onVerify={() => unlock()} />

The remaining props are `title`, `assetBase` and `className`. The README states that is all of them, so there is no configuration surface beyond those four plus `target` and `onVerify`.

Theming and accessibility, including what reduced motion actually changes

Styling runs through CSS custom properties set on any ancestor, so you do not need to override component classes. The README lists five: `--clawcap-bg` for the card, `--clawcap-ink` for text, `--clawcap-muted`, `--clawcap-accent` for the dialog button and focus ring, and `--clawcap-action` for the big red button.

css
:root {
  --clawcap-bg: #ffffff;
  --clawcap-ink: #1c1c1e;
  --clawcap-muted: #8a8a8e;
  --clawcap-accent: #1c1c1e;
  --clawcap-action: #ff5159;
}

Accessibility is handled more carefully than most novelty captchas. The README says keyboard runs the whole thing with arrows plus space or enter, the joystick is exposed as a real slider role, and `prefers-reduced-motion` swaps the decorative pieces (entrance tumble, confetti, ring pulse) for instant state changes. That last point is worth reading precisely: reduced motion removes decoration, not the challenge itself. The claw still has to be driven and the toy still has to be dropped. A user who cannot perform the drag is not accommodated by this setting, and the README does not describe an audio or text fallback.

Where playcaptcha fails, and when to pick something else

The honest limitation is the one the README volunteers: it proves play, not identity. A scripted agent that can read the DOM, find the target toy id and issue the same pointer or key events a human would is not obviously stopped by a claw machine. There is no mention of a server-issued token, a time limit, or a behavioural signal in the package. The `onVerify` callback is a client-side event, so treating it as proof on its own would be a mistake; the README's own advice is to keep it in front of real checks.

The second limitation is operational. Because the toy renders are fetched from static paths rather than imported, the component has a runtime dependency on your asset pipeline. A build that hashes filenames or serves assets from a CDN prefix will need `assetBase` set correctly, and the README does not document a bundler plugin that does this for you.

For a different approach, consider hCaptcha. The difference is not cosmetic: hCaptcha returns a response token that your server verifies against a remote endpoint, and it can serve harder challenges to traffic it distrusts. playcaptcha returns a callback in the browser and always asks the same kind of question. If your threat model is casual scripted abuse in front of a low-value form, the claw machine is cheaper to integrate and far less annoying. If your threat model includes determined automation, the token-and-verification model is the one you want, and playcaptcha should sit behind it rather than in place of it.

Licence, maintenance and what upgrading costs

The licence is MIT, declared in package.json and in the repository's LICENSE file, and the README closes with the same identifier. MIT permits commercial use and modification with the copyright notice retained; it also means there is no patent grant, which some legal teams care about. This is a description of the licence text, not legal advice, and the toy renders under `assets/toys` ship under the same terms according to the README.

The version is 0.1.0. That is a pre-1.0 package, so the usual semver expectation applies: a minor bump may contain breaking changes. The practical upgrade cost is low in surface area, since the public API is one component with six props and one stylesheet, but the asset contract is the fragile part. If a future release adds, renames or removes toy ids, your pinned `target` value and your copied `assets/` folder both need to move together.

The last push to the default branch was on 2026-09-07, which is recent. The repository is not archived. There are no releases retrieved for this project, so there is no changelog to read before upgrading; you are comparing commits. The build is tsup, and `prepublishOnly` runs the build, which tells you the published `dist` is generated rather than committed. Peer dependencies are React 18 or newer, while the dev dependencies type against React 19, so the component is expected to work on both.

Editorial conclusion

Adopt playcaptcha when you want a friction-light, keyboard-accessible interaction in front of a signup or download form, and you already have server-side verification behind it. Do not adopt it as your only bot defence, and do not adopt it if you cannot serve static files under /toys/ and /playcaptcha.svg, or if you need a challenge that adapts to risk. Before wiring it in, verify that the assets folder is copied into your static output and that the 12 toy ids match the files you ship, then decide whether target should be pinned or left random.

Frequently asked questions

Which CAPTCHA app is real?

playcaptcha is a real published npm package, MIT licensed, with source in the mortspace/playcaptcha repository and a live demo linked from the README at feralui.vercel.app. It is a front-end interaction gate rather than a verification service, so it does not issue a server-checked token the way hosted captcha providers do.

How to enter a CAPTCHA in playcaptcha?

Use the joystick or the arrow keys to move the claw over the requested toy, press the red button or space or enter to grab it, then carry the catch to the hatch and drop it in. The README states that keyboard input runs the whole interaction.

Can a bot solve CAPTCHA?

The README does not claim playcaptcha resists automated solving; it states that the check proves someone is playing, not who they are, and asks you to keep it in front of your real checks. Nothing in the package description mentions a server token or a risk signal, so it should not be your only defence.

How to find a CAPTCHA in playcaptcha?

The README points to a live demo at feralui.vercel.app/#/captcha and to the source at github.com/mortspace/playcaptcha, which is part of the FeralUI project. The component itself is found in your app wherever you render ClawCaptcha.

Official sources

  1. Issues
  2. License: MIT
  3. mortspace/playcaptcha on GitHub
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/mortspace-playcaptcha.svg)](https://hysenlabs.com/projects/mortspace-playcaptcha)