{"_id":"a-character-ctrlr","name":"a-character-ctrlr","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"a-character-ctrlr","version":"0.1.0","description":"A React Three Fiber third-person controller library with a primitive player, follow camera, and ragdoll debugging sandbox.","license":"MIT","type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","sideEffects":false,"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"repository":{"type":"git","url":"git+https://github.com/kyambuthia/a-character-ctrlr.git"},"homepage":"https://github.com/kyambuthia/a-character-ctrlr#readme","bugs":{"url":"https://github.com/kyambuthia/a-character-ctrlr/issues"},"keywords":["react-three-fiber","threejs","character-controller","ragdoll","game-dev","physics"],"engines":{"node":">=20"},"publishConfig":{"access":"public"},"scripts":{"dev":"vite","dev:lan":"vite --host 0.0.0.0 --port 4173","test":"vitest run","typecheck":"tsc --noEmit","build:lib":"tsup src/lib/index.ts --clean --format esm,cjs --dts --external react,react-dom,three,@react-three/fiber,@react-three/rapier,@react-three/drei,zustand","build:demo":"vite build","build":"npm run typecheck && npm run test && npm run build:lib && npm run build:demo","prepublishOnly":"npm run typecheck && npm run test && npm run build:lib","preview":"vite preview","preview:lan":"vite preview --host 0.0.0.0 --port 4173"},"dependencies":{"zustand":"^5.0.8"},"peerDependencies":{"@react-three/drei":"^10.7.4","@react-three/fiber":"^9.4.0","@react-three/rapier":"^2.1.0","react":"^19.0.0","react-dom":"^19.0.0","three":"^0.181.1"},"devDependencies":{"@react-three/drei":"^10.7.4","@react-three/fiber":"^9.4.0","@react-three/rapier":"^2.1.0","@types/react":"^19.2.2","@types/react-dom":"^19.2.2","@vitejs/plugin-react":"^5.1.0","react":"^19.2.0","react-dom":"^19.2.0","three":"^0.181.1","tsup":"^8.5.0","typescript":"^5.9.3","vite":"^7.1.12","vitest":"^3.2.4"},"gitHead":"6ac1b647c80f078843f3313859fd0e324ae20b08","_id":"a-character-ctrlr@0.1.0","_nodeVersion":"24.12.0","_npmVersion":"11.9.0","dist":{"integrity":"sha512-vNMc2QwaaK2mj45lkA4Ui0mQOG4Hs324NVQY46LHAcAQHeD67jK+bw/pa+BL3jeL3Ttp+6AOU3oD5hoSFaBKjg==","shasum":"d06c7f0f78bf0e3013d5742290d5a3a0d1ecf900","tarball":"https://registry.npmjs.org/a-character-ctrlr/-/a-character-ctrlr-0.1.0.tgz","fileCount":7,"unpackedSize":410257,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCID8dvk1FCsM5FuLuxY5dyRreK5TbE1GDiy3JMlvE6PmzAiA2bS1dCCupa7HsKNMvc6z5vDhv9ocX9tFPZKi/QHCGug=="}]},"_npmUser":{"name":"kyambuthia","email":"kyambuthia@gmail.com"},"directories":{},"maintainers":[{"name":"kyambuthia","email":"kyambuthia@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/a-character-ctrlr_0.1.0_1774043486477_0.49179025885744143"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-20T21:51:26.328Z","0.1.0":"2026-03-20T21:51:26.681Z","modified":"2026-03-20T21:51:26.938Z"},"maintainers":[{"name":"kyambuthia","email":"kyambuthia@gmail.com"}],"description":"A React Three Fiber third-person controller library with a primitive player, follow camera, and ragdoll debugging sandbox.","homepage":"https://github.com/kyambuthia/a-character-ctrlr#readme","keywords":["react-three-fiber","threejs","character-controller","ragdoll","game-dev","physics"],"repository":{"type":"git","url":"git+https://github.com/kyambuthia/a-character-ctrlr.git"},"bugs":{"url":"https://github.com/kyambuthia/a-character-ctrlr/issues"},"license":"MIT","readme":"# CharacterCtrlr\n\n`CharacterCtrlr` is a hybrid `library + demo` project for a React Three Fiber third-person controller stack. It ships a reusable primitive player, a follow camera with camera-occlusion handling, scoped controller state, a humanoid ragdoll dummy, and an in-world ragdoll debug lab.\n\n## Production active-ragdoll direction\n\nThe repo is now explicitly being pushed toward a production-capable active ragdoll for mobile and PC.\n\nImportant boundaries:\n\n- `src/lib` is the shipping codepath\n- `src/components` is demo-only support code\n- the demo is used to inspect and reproduce behavior, not to host one-off controller logic\n- visual debugging is treated as part of the runtime engineering surface, not as optional polish\n\nThe chosen controller family is:\n\n- deterministic `SIMBICON`-style gait control\n- `capture-point` stepping heuristics for balance recovery\n- later directional locomotion expansion informed by `Generalized Biped Walking Control`\n\nSee:\n\n- [RESEARCH.md](./RESEARCH.md)\n- [ROADMAP.md](./ROADMAP.md)\n\n## Production baseline\n\nThe library is now in a solid packageable baseline for:\n\n- third-person movement with `idle`, `walk`, `run`, `crouch`, `jump`, and `fall`\n- external or keyboard-driven input\n- follow-camera control with pointer lock and scene-occlusion avoidance\n- state snapshots and movement lifecycle callbacks\n- a separate humanoid ragdoll test dummy with in-world debug visualization\n\nWhat is not finished yet:\n\n- step-up and slope-specialized controller handling\n- tuned production active-ragdoll walking, running, and recovery behavior\n- authored interaction systems for doors, vehicles, weapons, and golf\n- skinned-character animation or motion-matching backends\n\n## Install\n\n```bash\nnpm install a-character-ctrlr react react-dom three @react-three/fiber @react-three/rapier @react-three/drei\n```\n\n## Quick start\n\n```tsx\nimport { Canvas } from \"@react-three/fiber\";\nimport { Physics } from \"@react-three/rapier\";\nimport { CharacterCtrlrCameraRig, CharacterCtrlrPlayer, CharacterCtrlrProvider } from \"a-character-ctrlr\";\n\nexport function Scene() {\n  return (\n    <CharacterCtrlrProvider initialState={{ playerPosition: [0, 2.5, 6] }}>\n      <Canvas shadows camera={{ fov: 42, near: 0.1, far: 250, position: [0, 3.5, 8] }}>\n        <Physics gravity={[0, -9.81, 0]}>\n          <CharacterCtrlrPlayer controls=\"keyboard\" position={[0, 2.5, 6]} />\n        </Physics>\n        <CharacterCtrlrCameraRig />\n      </Canvas>\n    </CharacterCtrlrProvider>\n  );\n}\n```\n\n## Controlled input example\n\nUse `controls=\"none\"` when you want to drive the player from your own touch, gamepad, AI, or network state.\n\n```tsx\nimport { useEffect } from \"react\";\nimport { Canvas } from \"@react-three/fiber\";\nimport { Physics } from \"@react-three/rapier\";\nimport {\n  CharacterCtrlrCameraRig,\n  CharacterCtrlrPlayer,\n  CharacterCtrlrProvider,\n  useCharacterCtrlrInputController,\n} from \"a-character-ctrlr\";\n\nfunction BotDriver() {\n  const controller = useCharacterCtrlrInputController();\n\n  useEffect(() => {\n    controller.replaceInput({ forward: true, run: true });\n    return () => controller.resetInput();\n  }, [controller]);\n\n  return (\n    <>\n      <CharacterCtrlrPlayer\n        controls=\"none\"\n        inputRef={controller.inputRef}\n        onGroundedChange={(grounded) => {\n          if (!grounded) {\n            controller.pressInput(\"jump\", false);\n          }\n        }}\n      />\n      <CharacterCtrlrCameraRig />\n    </>\n  );\n}\n\nexport function Scene() {\n  return (\n    <CharacterCtrlrProvider>\n      <Canvas>\n        <Physics>\n          <BotDriver />\n        </Physics>\n      </Canvas>\n    </CharacterCtrlrProvider>\n  );\n}\n```\n\n## Exported API\n\n- `CharacterCtrlrProvider`\n- `createCharacterCtrlrStore`\n- `useCharacterCtrlrStore`\n- `useCharacterCtrlrStoreApi`\n- `useCharacterCtrlrKeyboardInput`\n- `useCharacterCtrlrInputController`\n- `CharacterCtrlrActiveRagdollPlayer` experimental\n- `CharacterCtrlrPlayer`\n- `CharacterCtrlrCameraRig`\n- `CharacterCtrlrRagdollDummy`\n- `DEFAULT_CHARACTER_CTRLR_INPUT`\n- `mergeCharacterCtrlrInput`\n\nUseful exported types:\n\n- `CharacterCtrlrControllerState`\n- `CharacterCtrlrStoreApi`\n- `CharacterCtrlrStoreInit`\n- `CharacterCtrlrInputState`\n- `CharacterCtrlrMovementMode`\n- `CharacterCtrlrPlayerSnapshot`\n- `CharacterCtrlrSupportState`\n- `CharacterCtrlrVec3`\n\n## Key component props\n\n`CharacterCtrlrPlayer` supports:\n\n- `controls=\"keyboard\" | \"none\"`\n- `input` and `inputRef` for additive external input\n- tunables for `walkSpeed`, `runSpeed`, `crouchSpeed`, `jumpVelocity`, `acceleration`, `deceleration`, and `airControl`\n- `onSnapshotChange`, `onMovementModeChange`, `onGroundedChange`, `onJump`, and `onLand`\n- `debug` for the in-world player debug overlay\n- emitted snapshots currently report `supportState` as a simple `\"double\"` or `\"none\"` fallback for the capsule baseline\n\n`CharacterCtrlrActiveRagdollPlayer` supports:\n\n- the same input and lifecycle callback shape as `CharacterCtrlrPlayer`\n- optional `mixamoSource` loading for hidden animation-target retargeting into the active ragdoll joint motors\n- experimental tunables for `jumpImpulse`, `uprightTorque`, `turnTorque`, and `balanceDamping`\n- experimental camera-target tuning with `cameraFocusSmoothing`, `cameraFocusHeight`, and `cameraFocusLead`\n- `debug` to view the articulated rig through the ragdoll debug overlay\n- emitted snapshots report articulated foot support as `\"none\"`, `\"left\"`, `\"right\"`, or `\"double\"`\n\nProduction note:\n\n- active-ragdoll work is still marked experimental, but the implementation now has the intended long-term control architecture in place:\n  - explicit gait FSM\n  - phase-based pose targets\n  - COM and capture-point feedback\n  - step length, width, and clearance targets\n  - locomotion family configs\n  - recovery and deterministic gait re-entry\n- grounded-state recovery now uses:\n  - contact hysteresis for grounded/airborne transitions\n  - delayed jump-contact clearing\n  - downward Rapier ground probes under the feet as a fallback when foot contact callbacks are unreliable\n- standing is now handled as a dedicated support problem rather than just an idle gait:\n  - pelvis support is solved relative to the foot sole plane\n  - idle and low-speed double-support use a stand-assist path\n  - feet are planted and leveled while standing so the rig can hold posture before stepping\n- new locomotion, balance, and recovery work should land in the library runtime first and only then be exposed through the demo\n\n`CharacterCtrlrCameraRig` supports:\n\n- `followOffset`, `focusHeight`, and `smoothing`\n- `pointerLock`, `yawSensitivity`, and `pitchSensitivity`\n- `collisionEnabled`, `collisionPadding`, and `minCollisionDistance`\n\n`CharacterCtrlrRagdollDummy` supports:\n\n- `position`\n- `debug`\n- paused/manual-step demo debugging props for the in-repo sandbox\n\n## Repo layout\n\n- `src/lib`: publishable library source\n- `src/components`: demo-only scene pieces\n- `dist`: library build output\n- `demo-dist`: demo build output\n- `RESEARCH.md`: academic basis for the active-ragdoll architecture\n- `ROADMAP.md`: production implementation plan and phase breakdown\n\n## Scripts\n\n- `npm run dev`: run the demo locally\n- `npm run dev:lan`: run the demo on your LAN\n- `npm run test`: run the library smoke tests\n- `npm run build:lib`: build the package into `dist`\n- `npm run build:demo`: build the demo into `demo-dist`\n- `npm run build`: typecheck, test, and build both library and demo\n- `npm run preview:lan`: preview the demo build on your LAN\n\nDemo tip:\n\n- the demo now defaults to the active ragdoll player\n- add `?player=capsule` to the dev URL to load the capsule baseline instead\n- add `?motion=mixamo` to enable the optional Mixamo target path in the ragdoll demo once the FBX files are placed in `public/mixamo`\n- the current ragdoll debugging/tuning path is `http://localhost:5173/?player=ragdoll&motion=mixamo`\n\nMixamo tip:\n\n- see [docs/MIXAMO.md](./docs/MIXAMO.md) for the expected FBX downloads, file layout, and `mixamoSource` usage\n\n## Design direction\n\nThe current shipping strategy is deliberate: keep control, camera, state, and interaction logic deterministic first, then add more sophisticated animation systems later. For the active ragdoll specifically, that now means a production-focused finite-state controller with explicit support, foot planting, COM, capture-point, and balance diagnostics before any learned or mocap-heavy runtime is considered.\n\nSee also:\n\n- [ROADMAP.md](./ROADMAP.md)\n- [RESEARCH.md](./RESEARCH.md)\n","readmeFilename":"README.md","_rev":"1-9d2b3ca6c6b37fc298b269a5eb29d86f"}