Skip to content

r3dacted42/shape-puzzle-captcha

Repository files navigation

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 incorrect 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/three@0.183.2/build/three.module.js",
      "three-bvh-csg": "https://unpkg.com/three-bvh-csg@0.0.18/build/index.module.js",
      "three-mesh-bvh": "https://unpkg.com/three-mesh-bvh@0.9.9/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

About

An interactive 3D Web Component captcha UI inspired by the (in)famous "Square Hole" meme.

Topics

Resources

License

Stars

Watchers

Forks

Contributors