{"_id":"@andromanpro/cyberpunk-captcha","name":"@andromanpro/cyberpunk-captcha","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@andromanpro/cyberpunk-captcha","version":"0.1.0","description":"Six cyberpunk-style captcha mechanics for comment forms or anti-bot challenges. Vanilla JS, zero deps.","main":"./dist/cyberpunk-captcha.js","module":"./dist/cyberpunk-captcha.esm.js","type":"module","exports":{".":{"import":"./dist/cyberpunk-captcha.esm.js","default":"./dist/cyberpunk-captcha.js"},"./style.css":"./dist/cyberpunk-captcha.css"},"scripts":{"build":"node tools/build.mjs","dev":"node tools/build.mjs --watch","serve":"python -m http.server 8000"},"peerDependencies":{"@andromanpro/lava-orb":"^0.1.0"},"peerDependenciesMeta":{"@andromanpro/lava-orb":{"optional":true}},"devDependencies":{"esbuild":"^0.24.2"},"keywords":["captcha","cyberpunk","anti-spam","anti-bot","vanilla-js","zero-deps","decoder","honeypot"],"author":{"name":"Roman Andriyanov","email":"andromanpro@gmail.com","url":"androman"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/andromanpro/cyberpunk-captcha.git"},"homepage":"https://andromanpro.github.io/cyberpunk-captcha","bugs":{"url":"https://github.com/andromanpro/cyberpunk-captcha/issues"},"gitHead":"aa2cdd465508b426f7cec3c96e75586ab1d40721","_id":"@andromanpro/cyberpunk-captcha@0.1.0","_nodeVersion":"24.12.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-m2HIkJ7zdcD8Fy0tOerrWw+EBSX8v8fhpWMn56bGp/iSF9T9RpTKcvtNiFgahfzj3eENnssDXlACSe4EfCGjOw==","shasum":"94904c31c41a8fb3470d39209612ee495372172c","tarball":"https://registry.npmjs.org/@andromanpro/cyberpunk-captcha/-/cyberpunk-captcha-0.1.0.tgz","fileCount":18,"unpackedSize":189083,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDa7uqlR3j7Qczkd9VPnXTfcpfAmAtgoAouFVLrEuE1xwIgb4ONdr5R4YPm/EAjOs3K0Q5KHx0efjnXWWU8HCRGmYw="}]},"_npmUser":{"name":"andromanch","email":"andromanpro@gmail.com"},"directories":{},"maintainers":[{"name":"andromanch","email":"andromanpro@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/cyberpunk-captcha_0.1.0_1777968476015_0.7524833654551975"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-05T08:07:55.941Z","0.1.0":"2026-05-05T08:07:56.171Z","modified":"2026-05-05T08:07:56.367Z"},"maintainers":[{"name":"andromanch","email":"andromanpro@gmail.com"}],"description":"Six cyberpunk-style captcha mechanics for comment forms or anti-bot challenges. Vanilla JS, zero deps.","homepage":"https://andromanpro.github.io/cyberpunk-captcha","keywords":["captcha","cyberpunk","anti-spam","anti-bot","vanilla-js","zero-deps","decoder","honeypot"],"repository":{"type":"git","url":"git+https://github.com/andromanpro/cyberpunk-captcha.git"},"author":{"name":"Roman Andriyanov","email":"andromanpro@gmail.com","url":"androman"},"bugs":{"url":"https://github.com/andromanpro/cyberpunk-captcha/issues"},"license":"MIT","readme":"# cyberpunk-captcha\n\n> Six cyberpunk-style captcha mechanics for comment forms or anti-bot challenges.\n> Vanilla JS, zero deps (lava-orb optional peer). Reduced-motion respected.\n\n## Demo\n\n[Live demo](https://andromanpro.github.io/cyberpunk-captcha) · [Article](https://androman.pro/cyberpunk-captcha)\n\n## What's inside\n\n| # | Name | Mechanics | Friction | Bot resistance |\n|---|---|---|---|---|\n| 01 | **Decoder Lock** | Type word that morphs from noise | Medium | High |\n| 02 | **Lava-Orb Temperature** | Drag slider into target band (optional `@andromanpro/lava-orb`) | Low | Medium |\n| 03 | **Sequence Decode** | Simon-style: repeat flashed sequence | Medium | High |\n| 04 | **Honeypot + Time** | Invisible (hidden field + timestamp) | None | High |\n| 05 | **1С Code Spot the Bug** | Click broken 1С code snippet | High | Very High (gated) |\n| 06 | **Scrub Reveal** | Slider into sweet-spot window (target ±N%) | Medium | Medium-High |\n\n## Install\n\n```bash\nnpm install @andromanpro/cyberpunk-captcha\n# Optional peer (only for LavaOrbTemp):\nnpm install @andromanpro/lava-orb\n```\n\nOr via CDN:\n```html\n<link rel=\"stylesheet\" href=\"https://unpkg.com/@andromanpro/cyberpunk-captcha/dist/cyberpunk-captcha.css\">\n<script src=\"https://unpkg.com/@andromanpro/cyberpunk-captcha/dist/cyberpunk-captcha.min.js\"></script>\n```\n\n## Quick start\n\n```html\n<div id=\"captcha-mount\"></div>\n<button id=\"submit\">Submit</button>\n\n<script type=\"module\">\n  import { DecoderLock } from '@andromanpro/cyberpunk-captcha';\n  import '@andromanpro/cyberpunk-captcha/style.css';\n\n  const captcha = new DecoderLock(document.getElementById('captcha-mount'));\n\n  document.getElementById('submit').addEventListener('click', () => {\n    if (captcha.isValid()) {\n      console.log('Pass!');\n    } else {\n      console.log('Captcha failed');\n      captcha.replay();\n    }\n  });\n</script>\n```\n\n## All six — usage\n\n### DecoderLock\n```js\nimport { DecoderLock } from '@andromanpro/cyberpunk-captcha';\n\nconst captcha = new DecoderLock(mount, {\n  pool: ['ANDROMAN', 'CYBER', 'NEON'],   // word pool (default included)\n  noise: '#@$%&*+=...',                   // noise chars (default included)\n  stepMs: 60                              // animation speed per char\n});\n```\n\n### LavaOrbTemp\n```js\nimport { LavaOrbTemp } from '@andromanpro/cyberpunk-captcha';\n\n// Without lava-orb — styled gradient slider\nconst captcha = new LavaOrbTemp(mount);\n\n// With lava-orb (optional peer dependency)\nimport LavaOrb from '@andromanpro/lava-orb';\nconst captcha = new LavaOrbTemp(mount, {\n  lavaOrb: LavaOrb,    // pass the imported library\n  orbSize: 70          // diameter in pixels\n});\n```\n\n### SequenceDecode\n```js\nimport { SequenceDecode } from '@andromanpro/cyberpunk-captcha';\n\nconst captcha = new SequenceDecode(mount, {\n  minLen: 3,   // min sequence length (default 3)\n  maxLen: 5    // max sequence length (default 5)\n});\n```\n\n### HoneypotTime\n```js\nimport { HoneypotTime } from '@andromanpro/cyberpunk-captcha';\n\nconst captcha = new HoneypotTime(mount, {\n  minElapsed: 3,         // min seconds since render (default 3)\n  fieldName: 'website2', // honeypot field name (default 'website2')\n  showDebug: false       // show debug overlay (default true for demos)\n});\n```\n\n### CodeBug1C\n```js\nimport { CodeBug1C } from '@andromanpro/cyberpunk-captcha';\n\nconst captcha = new CodeBug1C(mount, {\n  // optional: own snippet sets (each set: 3 snippets, one with bug:true)\n  sets: [[\n    { code: 'Процедура Тест()\\n  ...\\nКонецПроцедуры', bug: false },\n    { code: 'Если а > 0 Тогда\\n  ...', bug: true /* missing КонецЕсли */ },\n    { code: '...', bug: false }\n  ]]\n});\n```\n\n### ScrubReveal\n```js\nimport { ScrubReveal } from '@andromanpro/cyberpunk-captcha';\n\nconst captcha = new ScrubReveal(mount, {\n  pool: ['LAVA', 'ORB', 'NEON'],   // word pool\n  windowSize: 3,                    // half-width of sweet spot (default 3 → window ±3 → 6%)\n  targetMin: 30,                    // random target range\n  targetMax: 89\n});\n```\n\n### CaptchaRotation\nRandom pick from a set of variants per render:\n```js\nimport { CaptchaRotation } from '@andromanpro/cyberpunk-captcha';\n\nconst captcha = new CaptchaRotation(mount, {\n  variants: ['decoder-lock', 'scrub-reveal', 'sequence-decode'],\n  pickStrategy: 'random',     // or 'session' (sticky per session via sessionStorage)\n  sessionKey: 'cpcap-pick',   // sessionStorage key\n  options: {\n    'decoder-lock': { stepMs: 50 }\n  }\n});\n```\n\n## Common API (BaseCaptcha)\n\nAll captchas extend `BaseCaptcha` and share this interface:\n\n```js\ncaptcha.isValid();        // → boolean (sync validation, fires 'pass' or 'fail' event)\ncaptcha.validate();       // → { pass: boolean, message: string } (no events)\ncaptcha.replay();         // reset state, new round, re-render\ncaptcha.destroy();        // remove from DOM, clear listeners\n\ncaptcha.on('change', fn); // user interaction\ncaptcha.on('pass', fn);   // validation passed\ncaptcha.on('fail', fn);   // validation failed\ncaptcha.on('replay', fn); // round reset\n```\n\nCommon options:\n```js\nnew XCaptcha(mount, {\n  onChange: (...args) => {},          // fired on user interaction\n  onValidate: (passed, verdict) => {} // after isValid() called\n});\n```\n\n## Accessibility\n\nAll captchas respect `prefers-reduced-motion: reduce`:\n- **DecoderLock** — instant fallback (word shown statically, no morph animation)\n- **LavaOrbTemp** — slider works as plain range input\n- **SequenceDecode** — numbered list of buttons instead of flash sequence\n- **HoneypotTime** — already invisible, no a11y impact\n- **CodeBug1C** — purely click-based, no animation\n- **ScrubReveal** — gradient transitions disabled\n\n## Browser support\n\nES2017+ baseline (Chrome 58+, Firefox 53+, Safari 11+, Edge 14+). No IE11.\nFor older browsers, transpile via Babel using your own bundler.\n\n## License\n\nMIT © [Roman Andriyanov (androman)](https://androman.pro)\n","readmeFilename":"README.md","_rev":"1-097787332a35a8662670263952f768a9"}