{"_id":"@aeonlabs/ecctrl","name":"@aeonlabs/ecctrl","dist-tags":{"latest":"0.0.1"},"versions":{"0.0.1":{"name":"@aeonlabs/ecctrl","version":"0.0.1","author":{"name":"Oreo"},"license":"MIT","description":"A floating rigibody character controller for R3F","keywords":["react","three","threejs","react-three-fiber","control","character-control"],"repository":{"type":"git","url":"git+https://github.com/pmndrs/ecctrl.git"},"type":"module","types":"./dist/Ecctrl.d.ts","main":"./dist/Ecctrl.cjs","module":"./dist/Ecctrl.js","exports":{"types":"./dist/Ecctrl.d.ts","require":"./dist/Ecctrl.cjs","import":"./dist/Ecctrl.js"},"sideEffects":false,"devDependencies":{"@react-three/drei":"^9.92.7","@react-three/fiber":"^8.15.13","@types/react":"^18.2.28","@types/react-dom":"^18.2.8","@vitejs/plugin-react":"^4.1.0","r3f-perf":"^7.1.2","three":"^0.164.1","typescript":"^5.4.3","vite":"^4.3.9"},"dependencies":{"@react-spring/three":"^9.7.3","leva":"^0.9.34","zustand":"^4.4.7"},"peerDependencies":{"@aeonlabs/rapier":"latest","@react-three/drei":">=9.0","@react-three/fiber":">=8.0","react":">=18","react-dom":">=18.0"},"scripts":{"dev":"vite","build":"vite build && tsc","preview":"vite preview"},"publishConfig":{"access":"public"},"bugs":{"url":"https://github.com/pmndrs/ecctrl/issues"},"homepage":"https://github.com/pmndrs/ecctrl#readme","_id":"@aeonlabs/ecctrl@0.0.1","_nodeVersion":"16.19.0","_npmVersion":"8.19.3","dist":{"integrity":"sha512-TFMUiA5s2Y6xiYdsosEChmR8zHuY0LoAqhpUFnatgRRChiOfp104Oq3kYpJuuai4xZ82gOzdNh+AO9Z9pm+1HQ==","shasum":"d10b9a31f5876c981141c865d69d3982dab3197c","tarball":"https://registry.npmjs.org/@aeonlabs/ecctrl/-/ecctrl-0.0.1.tgz","fileCount":13,"unpackedSize":340396,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHNlSX+HesII1aojHEp9CLv4RCqn7O0oIMXGGTxcjpefAiEAuWQe3qis2lDgqI35hO0UB2gns1TaS/NNrS5YSiahRKU="}]},"_npmUser":{"name":"lt502676921","email":"2742054698@qq.com"},"directories":{},"maintainers":[{"name":"lt502676921","email":"2742054698@qq.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ecctrl_0.0.1_1715678296964_0.7119732939709884"},"_hasShrinkwrap":false}},"time":{"created":"2024-05-14T09:18:16.876Z","0.0.1":"2024-05-14T09:18:17.133Z","modified":"2024-05-14T09:18:17.467Z"},"maintainers":[{"name":"lt502676921","email":"2742054698@qq.com"}],"description":"A floating rigibody character controller for R3F","homepage":"https://github.com/pmndrs/ecctrl#readme","keywords":["react","three","threejs","react-three-fiber","control","character-control"],"repository":{"type":"git","url":"git+https://github.com/pmndrs/ecctrl.git"},"author":{"name":"Oreo"},"bugs":{"url":"https://github.com/pmndrs/ecctrl/issues"},"license":"MIT","readme":"# Ecctrl Floating Capsule Character Controller\n\n[![screenshot](example/FloatingCharacterControl.png)](https://character-control.vercel.app/)\n\n[Pmndrs/ecctrl](https://github.com/pmndrs/ecctrl) is a simple web based character controller build on [react-three-fiber](https://github.com/pmndrs/react-three-fiber) and [react-three-rapier](https://github.com/pmndrs/react-three-rapier). It provides a playground demo where you can experience the following features:\n\n1. Seamless movement over small obstacles\n2. Enhanced control with floating force incorporating spring and damping forces\n3. Rigidbody character functionality for interaction with the game environment\n4. Customizable ground friction for tailored control\n5. Realistic simulation with applied mass on supporting surfaces\n6. Smooth integration with moving and rotating platforms\n\n## New Features\n\n### (2024-1-1) EcctrlMode:\n\n- Now you can seamlessly switch between different modes by adding \"mode\" inside Ecctrl.\n\n`<Ecctrl mode=\"PointToMove\">`\n\n- \"PointToMove\" mode is designed for click-to-move or path following features. (no needs for keyboard controls)\n\n```js\nimport { useGame } from \"ecctrl\";\n// ...\nconst setMoveToPoint = useGame((state) => state.setMoveToPoint);\n// ...\n// call function setMoveToPoint(), whenever character needs to move\nsetMoveToPoint(point); // \"point\" is a vec3 value\n```\n\n- Here is a simple click-to-move example: [Ecctrl CodeSandbox](https://codesandbox.io/p/sandbox/ecctrl-pointtomove-m9z6xh)\n\n[![screenshot](example/ecctrlClickToMove.png)](https://codesandbox.io/p/sandbox/ecctrl-pointtomove-m9z6xh)\n\nCheck out the [featurelog.md](/featurelog.md) for details on previous updates and features.\n\n## Project Link\n\nLive Demo: [Floating Capsule Character Controller](https://character-control.vercel.app/)\n\n## Local Setup\n\nDownload [Node.js](https://nodejs.org/en/download). Run this followed commands:\n\n```bash\n# Install dependencies (only the first time)\nnpm install\n\n# Run the local server at localhost:5173\nnpm run dev\n\n# Build for production in the example/exampleDist/ directory\nvite build -c vercelVite.config.js\n```\n\n## How To Use\n\n### Basic Controls ([CodeSandbox Demo](https://codesandbox.io/s/ecctrl-w-o-animations-3k3zxt))\n\n```bash\nnpm install ecctrl\n```\n\n```js\nimport Ecctrl, { EcctrlAnimation } from \"ecctrl\";\n```\n\nTo get started, set up your keyboard map using [KeyboardControls](https://github.com/pmndrs/drei#keyboardcontrols). Then, wrap your character model within `<Ecctrl>`:\n\n```js\n/**\n * Keyboard control preset\n */\nconst keyboardMap = [\n  { name: \"forward\", keys: [\"ArrowUp\", \"KeyW\"] },\n  { name: \"backward\", keys: [\"ArrowDown\", \"KeyS\"] },\n  { name: \"leftward\", keys: [\"ArrowLeft\", \"KeyA\"] },\n  { name: \"rightward\", keys: [\"ArrowRight\", \"KeyD\"] },\n  { name: \"jump\", keys: [\"Space\"] },\n  { name: \"run\", keys: [\"Shift\"] },\n  // Optional animation key map\n  { name: \"action1\", keys: [\"1\"] },\n  { name: \"action2\", keys: [\"2\"] },\n  { name: \"action3\", keys: [\"3\"] },\n  { name: \"action4\", keys: [\"KeyF\"] },\n];\n\nreturn (\n  <>\n    ...\n    <Physics debug={physics} timeStep=\"vary\">\n      {/* Keyboard preset */}\n      <KeyboardControls map={keyboardMap}>\n        {/* Character Control */}\n        <Ecctrl>\n          {/* Replace your model here */}\n          <CharacterModel />\n        </Ecctrl>\n      </KeyboardControls>\n      ...\n    </Physics>\n  </>\n);\n```\n\nHere are all the default properties you can play with for `<Ecctrl>`:\n\n```js\n// Default properties for Ecctrl\nEcctrlProps: {\n  children, // ReactNode\n  debug: false, // Enable debug mode (require leva package)\n  capsuleHalfHeight: 0.35, // Half-height of the character capsule\n  capsuleRadius: 0.3, // Radius of the character capsule\n  floatHeight: 0.3, // Height of the character when floating\n  characterInitDir: 0, // Character initial facing direction (in rad)\n  followLight: false, // Enable follow light mode (name your light \"followLight\" before turn this on)\n  disableFollowCam: false, // Disable follow camera feature\n  disableFollowCamPos: { x: 0, y: 0, z: -5 }, // Camera position when the follow camera feature is disabled\n  disableFollowCamTarget: { x: 0, y: 0, z: 0 }, // Camera lookAt target when the follow camera feature is disabled\n  // Follow camera setups\n  camInitDis: -5, // Initial camera distance\n  camMaxDis: -7, // Maximum camera distance\n  camMinDis: -0.7, // Minimum camera distance\n  camInitDir: { x: 0, y: 0 }, // Camera initial rotation direction (in rad)\n  camTargetPos: { x: 0, y: 0, z: 0 }, // Camera target position\n  camMoveSpeed: 1, // Camera moving speed multiplier\n  camZoomSpeed: 1, // Camera zooming speed multiplier\n  camCollision: true, // Camera collision active/deactive\n  camCollisionOffset: 0.7, // Camera collision offset\n   // Follow light setups\n  followLightPos: { x: 20, y: 30, z: 10 }, // Follow light position\n  // Base control setups\n  maxVelLimit: 2.5, // Maximum velocity limit\n  turnVelMultiplier: 0.2, // Turn velocity multiplier\n  turnSpeed: 15, // Turn speed\n  sprintMult: 2, // Sprint speed multiplier\n  jumpVel: 4, // Jump velocity\n  jumpForceToGroundMult: 5, // Jump force to ground object multiplier\n  slopJumpMult: 0.25, // Slope jump affect multiplier\n  sprintJumpMult: 1.2, // Sprint jump multiplier\n  airDragMultiplier: 0.2, // Air drag multiplier\n  dragDampingC: 0.15, // Drag damping coefficient\n  accDeltaTime: 8, // Acceleration delta time\n  rejectVelMult: 4, // Reject velocity multiplier\n  moveImpulsePointY: 0.5, // Move impulse point Y offset\n  camFollowMult: 11, // Camera follow speed multiplier\n  fallingGravityScale: 2.5, // Character is falling, apply higher gravity\n  fallingMaxVel: -20, // Limit character max falling velocity\n  wakeUpDelay: 200, // Wake up character delay time after window visibility change to visible (in ms)\n  // Floating Ray setups\n  rayOriginOffest: { x: 0, y: -capsuleHalfHeight, z: 0 }, // Ray origin offset\n  rayHitForgiveness: 0.1, // Ray hit forgiveness\n  rayLength: capsuleRadius + 2, // Ray length\n  rayDir: { x: 0, y: -1, z: 0 }, // Ray direction\n  floatingDis: capsuleRadius + floatHeight, // Floating distance\n  springK: 1.2, // Spring constant\n  dampingC: 0.08, // Damping coefficient\n  // Slope Ray setups\n  showSlopeRayOrigin: false, // Show slope ray origin\n  slopeMaxAngle: 1, // in rad, the max walkable slope angle\n  slopeRayOriginOffest: capsuleRadius - 0.03, // Slope ray origin offset\n  slopeRayLength: capsuleRadius + 3, // Slope ray length\n  slopeRayDir: { x: 0, y: -1, z: 0 }, // Slope ray direction\n  slopeUpExtraForce: 0.1, // Slope up extra force\n  slopeDownExtraForce: 0.2, // Slope down extra force\n  // AutoBalance Force setups\n  autoBalance: true, // Enable auto-balance\n  autoBalanceSpringK: 0.3, // Auto-balance spring constant\n  autoBalanceDampingC: 0.03, // Auto-balance damping coefficient\n  autoBalanceSpringOnY: 0.5, // Auto-balance spring on Y-axis \n  autoBalanceDampingOnY: 0.015, // Auto-balance damping on Y-axis \n  // Animation temporary setups\n  animated: false, // Enable animation\n  // Mode setups\n  mode: null, // Activate different ecctrl modes\n  // Customizable controller key setups\n  controllerKeys: { forward: 12, backward: 13, leftward: 14, rightward: 15, jump: 2, action1: 11, action2: 3, action3: 1, action4: 0 },\n  // Other rigibody props from parent\n  // Rigidbody props can be used here,\n  // such as position, friction, gravityScale, etc.\n  ...props\n}\n\n// Simply change the value by doing this\n<Ecctrl maxVelLimit={5} jumpVel={4} position={[0,10,0]}>\n  <CharacterModel />\n</Ecctrl>\n```\n\n### Apply Character Animations ([CodeSandbox Demo](https://codesandbox.io/s/ecctrl-with-animations-nr4493))\n\nIf you want to apply character animations, prepare the character url and customize the `animationSet` with your own animation names. Change the `Ecctrl` property `animated` to true and wrap your character model inside `<EcctrlAnimation>` tag:\n\n```js\n// Prepare character model url\nconst characterURL = \"./ReplaceWithYourCharacterURL\";\n\n// Prepare and rename your character animations here\n// Note: idle, walk, run, jump, jumpIdle, jumpLand and fall names are essential\n// Missing any of these names might result in an error: \"cannot read properties of undifined (reading 'reset')\"\nconst animationSet = {\n  idle: \"Idle\",\n  walk: \"Walk\",\n  run: \"Run\",\n  jump: \"Jump_Start\",\n  jumpIdle: \"Jump_Idle\",\n  jumpLand: \"Jump_Land\",\n  fall: \"Climbing\", // This is for falling from high sky\n  // Currently support four additional animations\n  action1: \"Wave\",\n  action2: \"Dance\",\n  action3: \"Cheer\",\n  action4: \"Attack(1h)\", // This is special action which can be trigger while walking or running\n};\n\nreturn (\n  <>\n    ...\n    <Physics debug={physics} timeStep=\"vary\">\n      {/* Keyboard preset */}\n      <KeyboardControls map={keyboardMap}>\n        {/* Character Control */}\n        <Ecctrl animated>\n          {/* Character Animations */}\n          <EcctrlAnimation\n            characterURL={characterURL} // Must have property\n            animationSet={animationSet} // Must have property\n          >\n            {/* Replace your model here */}\n            <CharacterModel />\n          </EcctrlAnimation>\n        </Ecctrl>\n      </KeyboardControls>\n      ...\n    </Physics>\n  </>\n);\n```\n\n### (Advanced) Add and Personalize Additional Animations\n\nFor advanced animation setups, download all files and follow these steps:\n\n1. In `CharacterModel.jsx`, expand the `animationSet` with additional animations:\n\n```js\n// Rename your character animations here\nconst animationSet = {\n  idle: \"Idle\",\n  walk: \"Walk\",\n  run: \"Run\",\n  jump: \"Jump_Start\",\n  jumpIdle: \"Jump_Idle\",\n  jumpLand: \"Jump_Land\",\n  fall: \"Climbing\",\n  action1: \"Wave\",\n  action2: \"Dance\",\n  action3: \"Cheer\",\n  action4: \"Attack(1h)\", // This is special action which can be trigger while walking or running\n  //additinalAnimation: \"additinalAnimationName\",\n};\n```\n\n2. In `useGame.jsx`, create a trigger function for the new animation:\n\n```js\n  return {\n      /**\n       * Character animations state manegement\n       */\n      // Initial animation\n      curAnimation: null,\n      animationSet: {},\n\n      ...\n\n      action1: () => {\n        set((state) => {\n          if (state.curAnimation === state.animationSet.idle) {\n            return { curAnimation: state.animationSet.action1 };\n          }\n          return {};\n        });\n      },\n\n      /**\n       * Additional animations\n       */\n      // triggerFunction: ()=>{\n      //    set((state) => {\n      //        return { curAnimation: state.animationSet.additionalAnimation };\n      //    });\n      // }\n    };\n```\n\n3. In `CharacterController.jsx`, initialize the trigger function and call it when needed:\n\n```js\n// Animation change functions\nconst idleAnimation = useGame((state) => state.idle);\nconst walkAnimation = useGame((state) => state.walk);\nconst runAnimation = useGame((state) => state.run);\nconst jumpAnimation = useGame((state) => state.jump);\nconst jumpIdleAnimation = useGame((state) => state.jumpIdle);\nconst jumpLandAnimation = useGame((state) => state.jumpLand);\nconst fallAnimation = useGame((state) => state.fall);\nconst action1Animation = useGame((state) => state.action1);\nconst action2Animation = useGame((state) => state.action2);\nconst action3Animation = useGame((state) => state.action3);\nconst action4Animation = useGame((state) => state.action4);\n//const additionalAnimation = useGame((state) => state.triggerFunction);\n```\n\n### EcctrlJoystick and Touch buttons\n\nTo get start, simply import `EcctrlJoystick` from `ecctrl`\n\n```js\nimport { EcctrlJoystick } from \"ecctrl\";\n```\n\nPlace `<EcctrlJoystick>` outside of your canvas component, and you're done!\n\n```js\n//...\n  <EcctrlJoystick />\n  <Canvas>\n    {/* ... */}\n  </Canvas>\n//...\n```\n\nYou can also add lights or additional meshs like so (note: this will create components twice, once inside the joystick's scene, another inside the buttons' scene, so keep an eye on performance):\n\n```js\n//...\n  <EcctrlJoystick>\n    <ambientLight />\n    <mesh>\n      <boxGeometry args={[1,1,1]} />\n    </mesh>\n  </EcctrlJoystick>\n  <Canvas>\n    {/* ... */}\n  </Canvas>\n//...\n```\n\nAdditionally, you can change components' material, geometry, or texture as you like:\n\n```js\n//...\n  <EcctrlJoystick\n    joystickBaseProps={{\n      receiveShadow: true,\n      material: new THREE.MeshStandardMaterial({ color: \"grey\" })\n    }}\n  />\n  <Canvas>\n    {/* ... */}\n  </Canvas>\n//...\n```\n\nHere are all the properties you can play with for `<EcctrlJoystick>`:\n\n```js\nEcctrlJoystickProps: {\n    // Joystick props\n    children?: ReactNode;\n    joystickPositionLeft?: number; // joystick div container position left\n    joystickPositionBottom?: number; // joystick div container position bottom\n    joystickHeightAndWidth?: number; // joystick div container height and width\n    joystickCamZoom?: number; // camera zoom level for the joystick\n    joystickCamPosition?: [x: number, y: number, z: number]; // camera position for the joystick\n    joystickBaseProps?: ThreeElements['mesh']; // custom properties for the joystick's base mesh\n    joystickStickProps?: ThreeElements['mesh']; // custom properties for the joystick's stick mesh\n    joystickHandleProps?: ThreeElements['mesh']; // custom properties for the joystick's handle mesh\n\n    // Touch buttons props\n    buttonNumber?: number; // Number of buttons (max 5)\n    buttonPositionRight?: number; // buttons div container position right\n    buttonPositionBottom?: number; // buttons div container position bottom\n    buttonHeightAndWidth?: number; // buttons div container height and width\n    buttonCamZoom?: number; // camera zoom level for the buttons\n    buttonCamPosition?: [x: number, y: number, z: number]; // camera position for the buttons\n    buttonGroup1Position?: [x: number, y: number, z: number]; // button 1 posiiton in 3D scene\n    buttonGroup2Position?: [x: number, y: number, z: number]; // button 2 posiiton in 3D scene\n    buttonGroup3Position?: [x: number, y: number, z: number]; // button 3 posiiton in 3D scene\n    buttonGroup4Position?: [x: number, y: number, z: number]; // button 4 posiiton in 3D scene\n    buttonGroup5Position?: [x: number, y: number, z: number]; // button 5 posiiton in 3D scene\n    buttonLargeBaseProps?: ThreeElements['mesh']; // custom properties for the buttons' large base mesh\n    buttonSmallBaseProps?: ThreeElements['mesh']; // custom properties for the buttons' small base mesh\n    buttonTop1Props?: ThreeElements['mesh']; // custom properties for the button 1 top mesh (large button)\n    buttonTop2Props?: ThreeElements['mesh']; // custom properties for the button 2 top mesh (large button)\n    buttonTop3Props?: ThreeElements['mesh']; // custom properties for the button 3 top mesh (small button)\n    buttonTop4Props?: ThreeElements['mesh']; // custom properties for the button 4 top mesh (small button)\n    buttonTop5Props?: ThreeElements['mesh']; // custom properties for the button 5 top mesh (small button)\n};\n```\n\n### Using your own joystick or buttons\n\nIf you prefer to use your custom joystick or buttons, you can leverage the `useJoystickControls` hook from `ecctrl`. Import the hook and call the appropriate functions::\n\n```js\nimport { useJoystickControls } from \"ecctrl\";\n//...\nconst setJoystick = useJoystickControls((state) => state.setJoystick);\nconst resetJoystick = useJoystickControls((state) => state.resetJoystick);\nconst pressButton1 = useJoystickControls((state) => state.pressButton1);\nconst releaseAllButtons = useJoystickControls(\n  (state) => state.releaseAllButtons\n);\n//...\n// call the proper fuctions\nsetJoystick(joystickDis, joystickAng, runState);\n// or\npressButton1();\n```\n\n### Ecctrl Mode\n\nActivate different modes in Ecctrl by including the desired mode inside Ecctrl component: \n`<Ecctrl mode=\"PointToMove\">`.\n\n#### 1. \"PointToMove\" Mode ([CodeSandbox Demo](https://codesandbox.io/p/sandbox/ecctrl-pointtomove-m9z6xh?file=%2Fsrc%2FMap.js%3A46%2C19))\n\nThis mode doesn't require keyboard controls and is designed for click-to-move or path-following features.\n\n```js\nimport { useGame } from \"ecctrl\";\n// ...\nconst setMoveToPoint = useGame((state) => state.setMoveToPoint);\n// ...\n// call function setMoveToPoint(), whenever character needs to move\nsetMoveToPoint(point); // \"point\" is a vec3 value\n```\n\n### (Optional) First-person view setup\n\nIf you would like to quickly set up a first-person mode, you can modify these props to achieve that:\n\n```js\n<Ecctrl\n  camInitDis={-0.01} // camera intial position\n  camMinDis={-0.01} // camera zoom in closest position\n  camFollowMult={100} // give any big number here, so the camera follows the character instantly\n  turnVelMultiplier={1} // Turning speed same as moving speed\n  turnSpeed={100} // give it big turning speed to prevent turning wait time\n  mode=\"CameraBasedMovement\" // character's rotation will follow camera's rotation in this mode\n>\n```\n\n## Contributions\n\nI appreciate your interest in this project! If you have any feedback, suggestions, or resources related to the controller, please feel free to share.\n\nThank you!\n","readmeFilename":"readme.md"}