npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@r3dacted42/shape-puzzle-captcha

v0.0.6

Published

Web component for a shape puzzle based captcha UI, based on the square hole meme. Drag and drop shapes into the correct holes to pass!

Readme

shape-puzzle-captcha

npm version npm downloads bundle size License: MIT

An interactive 3D Web Component captcha UI inspired by the (in)famous "Square Hole" meme. Users must drag and drop 3D shapes into their ~~in~~correct holes to pass the verification. Built with Lit, Three.js, and CSG (Constructive Solid Geometry).

shape-puzzle-captcha-recording

Demo Page

[!WARNING]
This component provides the UI for a puzzle. Because the verification happens in the browser, it can be bypassed via the developer console. Do not use this as your sole line of defense against bot attacks on sensitive endpoints.

Features

  • Built as a standard Web Component using Lit, it just works anywhere.
  • Uses Three.js for real-time rendering and physics interactions.
  • Native dark mode support, customizable colors using CSS variables and attributes.
  • Portal based popup for the puzzle, no messing around with the z-index.

Register the component

Using a Package Manager (Recommended)

  • Install the package and its dependencies via npm, yarn, or pnpm.
    npm install @r3dacted42/shape-puzzle-captcha
  • Import it once in the file containing your application's main entry point (e.g., main.js, app.js, or index.js) to register the Web Component:
    import "@r3dacted42/shape-puzzle-captcha";

Support for SSR depends on whether an integratio for Lit is available. If you're using Astro or something similar, consider using the CDN method below.

Using a CDN (Vanilla HTML)

If you aren't using a bundler, you can use the component directly in the browser. Because modern ES modules are used, you must include an import map to resolve the dependencies.

<script type="importmap">
  {
    "imports": {
      "lit": "https://cdn.jsdelivr.net/gh/lit/dist@3/core/lit-core.min.js",
      "three": "https://unpkg.com/[email protected]/build/three.module.js",
      "three-bvh-csg": "https://unpkg.com/[email protected]/build/index.module.js",
      "three-mesh-bvh": "https://unpkg.com/[email protected]/build/index.module.js"
    }
  }
</script>
<script
  type="module"
  src="https://unpkg.com/@r3dacted42/shape-puzzle-captcha@latest/dist/shape-puzzle-captcha.js"
></script>

Alternatively, if you can't or don't want to use import maps, you can use the bundle version:

<script
  type="module"
  src="https://unpkg.com/@r3dacted42/shape-puzzle-captcha@latest/dist/bundle/shape-puzzle-captcha.js"
></script>

Usage

Once registered, use the <shape-puzzle-captcha> tag anywhere in your HTML or JSX templates, and listen for events.

<shape-puzzle-captcha auto-dark> </shape-puzzle-captcha>

<button id="submit-btn" disabled>Humans Only Please!</button>

<script>
  const submitBtn = document.getElementById("submit-btn");

  document.addEventListener("shapepuzzlecaptcha:solved", (e) => {
    // A backend is essential for a truly secure captcha!
    // if (someBackendCall(clientInfo).isVerified)
    submitBtn.disabled = false;
  });
</script>

API Reference

Attributes / Properties

| Attribute | Type | Default | Description | | --------- | ---- | ------- | ----------- | | event-key | String | "shapepuzzlecaptcha" | The namespace for the custom events emitted by the component. | | shape-color | Number (Hex) | 0xa83232 | Hex color code for the default, unselected shapes. | | selected-shape-color | Number (Hex) | 0xc27502 | Hex color code for the shape currently being dragged. | | disable-audio | Boolean | false | Set true to hide the audio button | | auto-dark | Boolean | "data" | false | Set it true to follow the browser's color scheme. |

[!TIP] Use class="dark" or data-dark on <shape-puzzle-captcha> to use the dark color scheme. See Advanced Theming for details. The auto-dark attribute uses class="dark" by default. Set it to "data" to use the data-dark attribute for dark theme.

Methods

| Method | Returns | Description | | ------ | ------- | ----------- | | reset() | undefined | Reset the 3D scene and returns the component to the "unsolved" state. Also emits the shapepuzzlecaptcha:reset event. |

Events

The component emits global events that bubble up to the document/window. | Event Name | Description | | ---------- | ----------- | | shapepuzzlecaptcha:solved | User clicks "Verify" and all shapes are in the correct holes. | | shapepuzzlecaptcha:failed | User clicks "Verify" but the shapes are placed incorrectly. | | shapepuzzlecaptcha:reset | User clicks the reset button or the reset() function is called. | | shapepuzzlecaptcha:audio | User clicks the audio button. | | shapepuzzlecaptcha:info | User clicks the info button. |

[!TIP] The event names are dynamically prefixed by your event-key, so if you have event-key="meow" on the component, then you'll get events like meow:solved, meow:failed, meow:reset, etc.

Advanced Theming

The component uses CSS variables for easy styling. You can override these variables on the <shape-puzzle-captcha> element to match your brand. The internal popup component will automatically inherit these styles.

shape-puzzle-captcha {
  --font-family: system-ui, -apple-system, sans-serif;
  --bg-color: #ffffff;
  --canvas-bg-color: #f0f0f0;
  --text-color: #000;
  --primary-color: #1a73e9;
  --on-primary-color: #ffffff;
  --primary-hover-color: #1669c1;
  --border-color: #cccccc;
  --image-btn-color: #737373;
}

shape-puzzle-captcha(.dark),
shape-puzzle-captcha([data-dark]) {
  --bg-color: #1f1f1f;
  --canvas-bg-color: #292929;
  --text-color: #ffffff;
  --primary-color: #611c99;
  --on-primary-color: #ffffff;
  --primary-hover-color: #6e16c1;
  --border-color: #505050;
  --image-btn-color: #8d8d8d;
}

MIT License © 2026 r3dacted42