[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6GD7XBV2S1B6ZFZ9XSYEP7M":3,"skill-same:01M6GD7XBV2S1B6ZFZ9XSYEP7M":64},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":36,"linkOnly":37,"markdownContent":38,"markdownBody":39,"frontMatter":40,"refName":42,"commitSha":43,"skillDirectory":44,"forksCount":45,"repositoryHtmlUrl":46,"repositoryHomepageUrl":46,"ownerHtmlUrl":47,"ownerBlogUrl":6,"ownerDescription":48,"updatedAt":49,"install":50,"resources":63},"01M6GD7XBV2S1B6ZFZ9XSYEP7M","threejs-interaction",null,"Three.js interaction - raycasting, controls, mouse\u002Ftouch input, object selection. Use when handling user input, implementing click detection, adding camera controls, or creating interactive 3D experiences.","Sam-06060\u002Fjarvis-assistant","Sam-06060","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F208600848?v=4","01M6CRKT7C7FXD21V6HXF293S0","Samson Frank Ganta","01M6CRKTBEKYFD8YX5Z1GT99EE",6,"Apache-2.0","https:\u002F\u002Fgithub.com\u002FSam-06060\u002Fjarvis-assistant\u002Fblob\u002Fmain\u002Fmodules\u002Fagent_skills\u002Fawesome-skills\u002Fplaybooks\u002Fthreejs-interaction\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35],"threejs","interaction","threejs interaction","community","touch","controls","input","click","three","selection","detection","camera","use","user","interactive","js","3D","2026-11-10 10:12:30",false,"---\nname: threejs-interaction\ndescription: Three.js interaction - raycasting, controls, mouse\u002Ftouch input, object selection. Use when handling user input, implementing click detection, adding camera controls, or creating interactive 3D experiences.\nrisk: unknown\nsource: community\n---\n\n# Three.js Interaction\n\n## When to Use\n\n- You need user interaction inside a Three.js scene.\n- The task involves raycasting, object picking, pointer handling, touch input, or camera controls.\n- You are building an interactive 3D experience rather than a passive render.\n\n## Quick Start\n\n```javascript\nimport * as THREE from \"three\";\nimport { OrbitControls } from \"three\u002Faddons\u002Fcontrols\u002FOrbitControls.js\";\n\n\u002F\u002F Camera controls\nconst controls = new OrbitControls(camera, renderer.domElement);\ncontrols.enableDamping = true;\n\n\u002F\u002F Raycasting for click detection\nconst raycaster = new THREE.Raycaster();\nconst mouse = new THREE.Vector2();\n\nfunction onClick(event) {\n  mouse.x = (event.clientX \u002F window.innerWidth) * 2 - 1;\n  mouse.y = -(event.clientY \u002F window.innerHeight) * 2 + 1;\n\n  raycaster.setFromCamera(mouse, camera);\n  const intersects = raycaster.intersectObjects(scene.children);\n\n  if (intersects.length > 0) {\n    console.log(\"Clicked:\", intersects[0].object);\n  }\n}\n\nwindow.addEventListener(\"click\", onClick);\n```\n\n## Raycaster\n\n### Basic Raycasting\n\n```javascript\nconst raycaster = new THREE.Raycaster();\n\n\u002F\u002F From camera (mouse picking)\nraycaster.setFromCamera(mousePosition, camera);\n\n\u002F\u002F From any origin and direction\nraycaster.set(origin, direction); \u002F\u002F origin: Vector3, direction: normalized Vector3\n\n\u002F\u002F Get intersections\nconst intersects = raycaster.intersectObjects(objects, recursive);\n\n\u002F\u002F intersects array contains:\n\u002F\u002F {\n\u002F\u002F   distance: number,          \u002F\u002F Distance from ray origin\n\u002F\u002F   point: Vector3,            \u002F\u002F Intersection point in world coords\n\u002F\u002F   face: Face3,               \u002F\u002F Intersected face\n\u002F\u002F   faceIndex: number,         \u002F\u002F Face index\n\u002F\u002F   object: Object3D,          \u002F\u002F Intersected object\n\u002F\u002F   uv: Vector2,               \u002F\u002F UV coordinates at intersection\n\u002F\u002F   uv1: Vector2,              \u002F\u002F Second UV channel\n\u002F\u002F   normal: Vector3,           \u002F\u002F Interpolated face normal\n\u002F\u002F   instanceId: number         \u002F\u002F For InstancedMesh\n\u002F\u002F }\n```\n\n### Mouse Position Conversion\n\n```javascript\nconst mouse = new THREE.Vector2();\n\nfunction updateMouse(event) {\n  \u002F\u002F For full window\n  mouse.x = (event.clientX \u002F window.innerWidth) * 2 - 1;\n  mouse.y = -(event.clientY \u002F window.innerHeight) * 2 + 1;\n}\n\n\u002F\u002F For specific canvas element\nfunction updateMouseCanvas(event, canvas) {\n  const rect = canvas.getBoundingClientRect();\n  mouse.x = ((event.clientX - rect.left) \u002F rect.width) * 2 - 1;\n  mouse.y = -((event.clientY - rect.top) \u002F rect.height) * 2 + 1;\n}\n```\n\n### Touch Support\n\n```javascript\nfunction onTouchStart(event) {\n  event.preventDefault();\n\n  if (event.touches.length === 1) {\n    const touch = event.touches[0];\n    mouse.x = (touch.clientX \u002F window.innerWidth) * 2 - 1;\n    mouse.y = -(touch.clientY \u002F window.innerHeight) * 2 + 1;\n\n    raycaster.setFromCamera(mouse, camera);\n    const intersects = raycaster.intersectObjects(clickableObjects);\n\n    if (intersects.length > 0) {\n      handleSelection(intersects[0]);\n    }\n  }\n}\n\nrenderer.domElement.addEventListener(\"touchstart\", onTouchStart);\n```\n\n### Raycaster Options\n\n```javascript\nconst raycaster = new THREE.Raycaster();\n\n\u002F\u002F Near\u002Ffar clipping (default: 0, Infinity)\nraycaster.near = 0;\nraycaster.far = 100;\n\n\u002F\u002F Line\u002FPoints precision\nraycaster.params.Line.threshold = 0.1;\nraycaster.params.Points.threshold = 0.1;\n\n\u002F\u002F Layers (only intersect objects on specific layers)\nraycaster.layers.set(1);\n```\n\n### Efficient Raycasting\n\n```javascript\n\u002F\u002F Only check specific objects\nconst clickables = [mesh1, mesh2, mesh3];\nconst intersects = raycaster.intersectObjects(clickables, false);\n\n\u002F\u002F Use layers for filtering\nmesh1.layers.set(1); \u002F\u002F Clickable layer\nraycaster.layers.set(1);\n\n\u002F\u002F Throttle raycast for hover effects\nlet lastRaycast = 0;\nfunction onMouseMove(event) {\n  const now = Date.now();\n  if (now - lastRaycast \u003C 50) return; \u002F\u002F 20fps max\n  lastRaycast = now;\n\n  \u002F\u002F Raycast here\n}\n```\n\n## Camera Controls\n\n### OrbitControls\n\n```javascript\nimport { OrbitControls } from \"three\u002Faddons\u002Fcontrols\u002FOrbitControls.js\";\n\nconst controls = new OrbitControls(camera, renderer.domElement);\n\n\u002F\u002F Damping (smooth movement)\ncontrols.enableDamping = true;\ncontrols.dampingFactor = 0.05;\n\n\u002F\u002F Rotation limits\ncontrols.minPolarAngle = 0; \u002F\u002F Top\ncontrols.maxPolarAngle = Math.PI \u002F 2; \u002F\u002F Horizon\ncontrols.minAzimuthAngle = -Math.PI \u002F 4; \u002F\u002F Left\ncontrols.maxAzimuthAngle = Math.PI \u002F 4; \u002F\u002F Right\n\n\u002F\u002F Zoom limits\ncontrols.minDistance = 2;\ncontrols.maxDistance = 50;\n\n\u002F\u002F Enable\u002Fdisable features\ncontrols.enableRotate = true;\ncontrols.enableZoom = true;\ncontrols.enablePan = true;\n\n\u002F\u002F Auto-rotate\ncontrols.autoRotate = true;\ncontrols.autoRotateSpeed = 2.0;\n\n\u002F\u002F Target (orbit point)\ncontrols.target.set(0, 1, 0);\n\n\u002F\u002F Update in animation loop\nfunction animate() {\n  controls.update(); \u002F\u002F Required for damping and auto-rotate\n  renderer.render(scene, camera);\n}\n```\n\n#### OrbitControls Programmatic Methods (r183)\n\n```javascript\n\u002F\u002F Programmatic camera movement\ncontrols.dolly(1.5); \u002F\u002F Dolly in\u002Fout (zoom for perspective cameras)\ncontrols.pan(deltaX, deltaY); \u002F\u002F Pan the camera\ncontrols.rotate(deltaAzimuth, deltaPolar); \u002F\u002F Rotate around target\n\n\u002F\u002F Cursor style (r183)\ncontrols.cursorStyle = { orbit: \"grab\", pan: \"move\", dolly: \"zoom-in\" };\n```\n\n### FlyControls\n\n```javascript\nimport { FlyControls } from \"three\u002Faddons\u002Fcontrols\u002FFlyControls.js\";\n\nconst controls = new FlyControls(camera, renderer.domElement);\ncontrols.movementSpeed = 10;\ncontrols.rollSpeed = Math.PI \u002F 24;\ncontrols.dragToLook = true;\n\n\u002F\u002F Update with delta\nfunction animate() {\n  controls.update(clock.getDelta());\n  renderer.render(scene, camera);\n}\n```\n\n### FirstPersonControls\n\n```javascript\nimport { FirstPersonControls } from \"three\u002Faddons\u002Fcontrols\u002FFirstPersonControls.js\";\n\nconst controls = new FirstPersonControls(camera, renderer.domElement);\ncontrols.movementSpeed = 10;\ncontrols.lookSpeed = 0.1;\ncontrols.lookVertical = true;\ncontrols.constrainVertical = true;\ncontrols.verticalMin = Math.PI \u002F 4;\ncontrols.verticalMax = (Math.PI * 3) \u002F 4;\n\nfunction animate() {\n  controls.update(clock.getDelta());\n}\n```\n\n### PointerLockControls\n\n```javascript\nimport { PointerLockControls } from \"three\u002Faddons\u002Fcontrols\u002FPointerLockControls.js\";\n\nconst controls = new PointerLockControls(camera, document.body);\n\n\u002F\u002F Lock pointer on click\ndocument.addEventListener(\"click\", () => {\n  controls.lock();\n});\n\ncontrols.addEventListener(\"lock\", () => {\n  console.log(\"Pointer locked\");\n});\n\ncontrols.addEventListener(\"unlock\", () => {\n  console.log(\"Pointer unlocked\");\n});\n\n\u002F\u002F Movement\nconst velocity = new THREE.Vector3();\nconst direction = new THREE.Vector3();\nconst moveForward = false;\nconst moveBackward = false;\n\ndocument.addEventListener(\"keydown\", (event) => {\n  switch (event.code) {\n    case \"KeyW\":\n      moveForward = true;\n      break;\n    case \"KeyS\":\n      moveBackward = true;\n      break;\n  }\n});\n\nfunction animate() {\n  if (controls.isLocked) {\n    direction.z = Number(moveForward) - Number(moveBackward);\n    direction.normalize();\n\n    velocity.z -= direction.z * 0.1;\n    velocity.z *= 0.9; \u002F\u002F Friction\n\n    controls.moveForward(-velocity.z);\n  }\n}\n```\n\n### TrackballControls\n\n```javascript\nimport { TrackballControls } from \"three\u002Faddons\u002Fcontrols\u002FTrackballControls.js\";\n\nconst controls = new TrackballControls(camera, renderer.domElement);\ncontrols.rotateSpeed = 2.0;\ncontrols.zoomSpeed = 1.2;\ncontrols.panSpeed = 0.8;\ncontrols.staticMoving = true;\n\nfunction animate() {\n  controls.update();\n}\n```\n\n### MapControls\n\n```javascript\nimport { MapControls } from \"three\u002Faddons\u002Fcontrols\u002FMapControls.js\";\n\nconst controls = new MapControls(camera, renderer.domElement);\ncontrols.enableDamping = true;\ncontrols.dampingFactor = 0.05;\ncontrols.screenSpacePanning = false;\ncontrols.maxPolarAngle = Math.PI \u002F 2;\n```\n\n## TransformControls\n\nGizmo for moving\u002Frotating\u002Fscaling objects.\n\n```javascript\nimport { TransformControls } from \"three\u002Faddons\u002Fcontrols\u002FTransformControls.js\";\n\nconst transformControls = new TransformControls(camera, renderer.domElement);\nscene.add(transformControls);\n\n\u002F\u002F Attach to object\ntransformControls.attach(selectedMesh);\n\n\u002F\u002F Switch modes\ntransformControls.setMode(\"translate\"); \u002F\u002F 'translate', 'rotate', 'scale'\n\n\u002F\u002F Change space\ntransformControls.setSpace(\"local\"); \u002F\u002F 'local', 'world'\n\n\u002F\u002F Size\ntransformControls.setSize(1);\n\n\u002F\u002F Events\ntransformControls.addEventListener(\"dragging-changed\", (event) => {\n  \u002F\u002F Disable orbit controls while dragging\n  orbitControls.enabled = !event.value;\n});\n\ntransformControls.addEventListener(\"change\", () => {\n  renderer.render(scene, camera);\n});\n\n\u002F\u002F Keyboard shortcuts\nwindow.addEventListener(\"keydown\", (event) => {\n  switch (event.key) {\n    case \"g\":\n      transformControls.setMode(\"translate\");\n      break;\n    case \"r\":\n      transformControls.setMode(\"rotate\");\n      break;\n    case \"s\":\n      transformControls.setMode(\"scale\");\n      break;\n    case \"Escape\":\n      transformControls.detach();\n      break;\n  }\n});\n```\n\n## DragControls\n\nDrag objects directly.\n\n```javascript\nimport { DragControls } from \"three\u002Faddons\u002Fcontrols\u002FDragControls.js\";\n\nconst draggableObjects = [mesh1, mesh2, mesh3];\nconst dragControls = new DragControls(\n  draggableObjects,\n  camera,\n  renderer.domElement,\n);\n\ndragControls.addEventListener(\"dragstart\", (event) => {\n  orbitControls.enabled = false;\n  event.object.material.emissive.set(0xaaaaaa);\n});\n\ndragControls.addEventListener(\"drag\", (event) => {\n  \u002F\u002F Constrain to ground plane\n  event.object.position.y = 0;\n});\n\ndragControls.addEventListener(\"dragend\", (event) => {\n  orbitControls.enabled = true;\n  event.object.material.emissive.set(0x000000);\n});\n```\n\n## Selection System\n\n### Click to Select\n\n```javascript\nconst raycaster = new THREE.Raycaster();\nconst mouse = new THREE.Vector2();\nlet selectedObject = null;\n\nfunction onMouseDown(event) {\n  mouse.x = (event.clientX \u002F window.innerWidth) * 2 - 1;\n  mouse.y = -(event.clientY \u002F window.innerHeight) * 2 + 1;\n\n  raycaster.setFromCamera(mouse, camera);\n  const intersects = raycaster.intersectObjects(selectableObjects);\n\n  \u002F\u002F Deselect previous\n  if (selectedObject) {\n    selectedObject.material.emissive.set(0x000000);\n  }\n\n  \u002F\u002F Select new\n  if (intersects.length > 0) {\n    selectedObject = intersects[0].object;\n    selectedObject.material.emissive.set(0x444444);\n  } else {\n    selectedObject = null;\n  }\n}\n```\n\n### Box Selection\n\n```javascript\nimport { SelectionBox } from \"three\u002Faddons\u002Finteractive\u002FSelectionBox.js\";\nimport { SelectionHelper } from \"three\u002Faddons\u002Finteractive\u002FSelectionHelper.js\";\n\nconst selectionBox = new SelectionBox(camera, scene);\nconst selectionHelper = new SelectionHelper(renderer, \"selectBox\"); \u002F\u002F CSS class\n\ndocument.addEventListener(\"pointerdown\", (event) => {\n  selectionBox.startPoint.set(\n    (event.clientX \u002F window.innerWidth) * 2 - 1,\n    -(event.clientY \u002F window.innerHeight) * 2 + 1,\n    0.5,\n  );\n});\n\ndocument.addEventListener(\"pointermove\", (event) => {\n  if (selectionHelper.isDown) {\n    selectionBox.endPoint.set(\n      (event.clientX \u002F window.innerWidth) * 2 - 1,\n      -(event.clientY \u002F window.innerHeight) * 2 + 1,\n      0.5,\n    );\n  }\n});\n\ndocument.addEventListener(\"pointerup\", (event) => {\n  selectionBox.endPoint.set(\n    (event.clientX \u002F window.innerWidth) * 2 - 1,\n    -(event.clientY \u002F window.innerHeight) * 2 + 1,\n    0.5,\n  );\n\n  const selected = selectionBox.select();\n  console.log(\"Selected objects:\", selected);\n});\n```\n\n### Hover Effects\n\n```javascript\nconst raycaster = new THREE.Raycaster();\nconst mouse = new THREE.Vector2();\nlet hoveredObject = null;\n\nfunction onMouseMove(event) {\n  mouse.x = (event.clientX \u002F window.innerWidth) * 2 - 1;\n  mouse.y = -(event.clientY \u002F window.innerHeight) * 2 + 1;\n\n  raycaster.setFromCamera(mouse, camera);\n  const intersects = raycaster.intersectObjects(hoverableObjects);\n\n  \u002F\u002F Reset previous hover\n  if (hoveredObject) {\n    hoveredObject.material.color.set(hoveredObject.userData.originalColor);\n    document.body.style.cursor = \"default\";\n  }\n\n  \u002F\u002F Apply new hover\n  if (intersects.length > 0) {\n    hoveredObject = intersects[0].object;\n    if (!hoveredObject.userData.originalColor) {\n      hoveredObject.userData.originalColor =\n        hoveredObject.material.color.getHex();\n    }\n    hoveredObject.material.color.set(0xff6600);\n    document.body.style.cursor = \"pointer\";\n  } else {\n    hoveredObject = null;\n  }\n}\n\nwindow.addEventListener(\"mousemove\", onMouseMove);\n```\n\n## Keyboard Input\n\n```javascript\nconst keys = {};\n\ndocument.addEventListener(\"keydown\", (event) => {\n  keys[event.code] = true;\n});\n\ndocument.addEventListener(\"keyup\", (event) => {\n  keys[event.code] = false;\n});\n\nfunction update() {\n  const speed = 0.1;\n\n  if (keys[\"KeyW\"]) player.position.z -= speed;\n  if (keys[\"KeyS\"]) player.position.z += speed;\n  if (keys[\"KeyA\"]) player.position.x -= speed;\n  if (keys[\"KeyD\"]) player.position.x += speed;\n  if (keys[\"Space\"]) player.position.y += speed;\n  if (keys[\"ShiftLeft\"]) player.position.y -= speed;\n}\n```\n\n## World-Screen Coordinate Conversion\n\n### World to Screen\n\n```javascript\nfunction worldToScreen(position, camera) {\n  const vector = position.clone();\n  vector.project(camera);\n\n  return {\n    x: ((vector.x + 1) \u002F 2) * window.innerWidth,\n    y: (-(vector.y - 1) \u002F 2) * window.innerHeight,\n  };\n}\n\n\u002F\u002F Position HTML element over 3D object\nconst screenPos = worldToScreen(mesh.position, camera);\nelement.style.left = screenPos.x + \"px\";\nelement.style.top = screenPos.y + \"px\";\n```\n\n### Screen to World\n\n```javascript\nfunction screenToWorld(screenX, screenY, camera, targetZ = 0) {\n  const vector = new THREE.Vector3(\n    (screenX \u002F window.innerWidth) * 2 - 1,\n    -(screenY \u002F window.innerHeight) * 2 + 1,\n    0.5,\n  );\n\n  vector.unproject(camera);\n\n  const dir = vector.sub(camera.position).normalize();\n  const distance = (targetZ - camera.position.z) \u002F dir.z;\n\n  return camera.position.clone().add(dir.multiplyScalar(distance));\n}\n```\n\n### Ray-Plane Intersection\n\n```javascript\nfunction getRayPlaneIntersection(mouse, camera, plane) {\n  const raycaster = new THREE.Raycaster();\n  raycaster.setFromCamera(mouse, camera);\n\n  const intersection = new THREE.Vector3();\n  raycaster.ray.intersectPlane(plane, intersection);\n\n  return intersection;\n}\n\n\u002F\u002F Ground plane\nconst groundPlane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);\nconst worldPos = getRayPlaneIntersection(mouse, camera, groundPlane);\n```\n\n## Event Handling Best Practices\n\n```javascript\nclass InteractionManager {\n  constructor(camera, renderer, scene) {\n    this.camera = camera;\n    this.renderer = renderer;\n    this.scene = scene;\n    this.raycaster = new THREE.Raycaster();\n    this.mouse = new THREE.Vector2();\n    this.clickables = [];\n\n    this.bindEvents();\n  }\n\n  bindEvents() {\n    const canvas = this.renderer.domElement;\n\n    canvas.addEventListener(\"click\", (e) => this.onClick(e));\n    canvas.addEventListener(\"mousemove\", (e) => this.onMouseMove(e));\n    canvas.addEventListener(\"touchstart\", (e) => this.onTouchStart(e));\n  }\n\n  updateMouse(event) {\n    const rect = this.renderer.domElement.getBoundingClientRect();\n    this.mouse.x = ((event.clientX - rect.left) \u002F rect.width) * 2 - 1;\n    this.mouse.y = -((event.clientY - rect.top) \u002F rect.height) * 2 + 1;\n  }\n\n  getIntersects() {\n    this.raycaster.setFromCamera(this.mouse, this.camera);\n    return this.raycaster.intersectObjects(this.clickables, true);\n  }\n\n  onClick(event) {\n    this.updateMouse(event);\n    const intersects = this.getIntersects();\n\n    if (intersects.length > 0) {\n      const object = intersects[0].object;\n      if (object.userData.onClick) {\n        object.userData.onClick(intersects[0]);\n      }\n    }\n  }\n\n  addClickable(object, callback) {\n    this.clickables.push(object);\n    object.userData.onClick = callback;\n  }\n\n  dispose() {\n    \u002F\u002F Remove event listeners\n  }\n}\n\n\u002F\u002F Usage\nconst interaction = new InteractionManager(camera, renderer, scene);\ninteraction.addClickable(mesh, (intersect) => {\n  console.log(\"Clicked at:\", intersect.point);\n});\n```\n\n## Performance Tips\n\n1. **Limit raycasts**: Throttle mousemove handlers\n2. **Use layers**: Filter raycast targets\n3. **Simple collision meshes**: Use invisible simpler geometry for raycasting\n4. **Disable controls when not needed**: `controls.enabled = false`\n5. **Batch updates**: Group interaction checks\n\n```javascript\n\u002F\u002F Use simpler geometry for raycasting\nconst complexMesh = loadedModel;\nconst collisionMesh = new THREE.Mesh(\n  new THREE.BoxGeometry(1, 1, 1),\n  new THREE.MeshBasicMaterial({ visible: false }),\n);\ncollisionMesh.userData.target = complexMesh;\nclickables.push(collisionMesh);\n```\n\n## See Also\n\n- `threejs-fundamentals` - Camera and scene setup\n- `threejs-animation` - Animating interactions\n- `threejs-shaders` - Visual feedback effects\n","# Three.js Interaction\n\n## When to Use\n\n- You need user interaction inside a Three.js scene.\n- The task involves raycasting, object picking, pointer handling, touch input, or camera controls.\n- You are building an interactive 3D experience rather than a passive render.\n\n## Quick Start\n\n```javascript\nimport * as THREE from \"three\";\nimport { OrbitControls } from \"three\u002Faddons\u002Fcontrols\u002FOrbitControls.js\";\n\n\u002F\u002F Camera controls\nconst controls = new OrbitControls(camera, renderer.domElement);\ncontrols.enableDamping = true;\n\n\u002F\u002F Raycasting for click detection\nconst raycaster = new THREE.Raycaster();\nconst mouse = new THREE.Vector2();\n\nfunction onClick(event) {\n  mouse.x = (event.clientX \u002F window.innerWidth) * 2 - 1;\n  mouse.y = -(event.clientY \u002F window.innerHeight) * 2 + 1;\n\n  raycaster.setFromCamera(mouse, camera);\n  const intersects = raycaster.intersectObjects(scene.children);\n\n  if (intersects.length > 0) {\n    console.log(\"Clicked:\", intersects[0].object);\n  }\n}\n\nwindow.addEventListener(\"click\", onClick);\n```\n\n## Raycaster\n\n### Basic Raycasting\n\n```javascript\nconst raycaster = new THREE.Raycaster();\n\n\u002F\u002F From camera (mouse picking)\nraycaster.setFromCamera(mousePosition, camera);\n\n\u002F\u002F From any origin and direction\nraycaster.set(origin, direction); \u002F\u002F origin: Vector3, direction: normalized Vector3\n\n\u002F\u002F Get intersections\nconst intersects = raycaster.intersectObjects(objects, recursive);\n\n\u002F\u002F intersects array contains:\n\u002F\u002F {\n\u002F\u002F   distance: number,          \u002F\u002F Distance from ray origin\n\u002F\u002F   point: Vector3,            \u002F\u002F Intersection point in world coords\n\u002F\u002F   face: Face3,               \u002F\u002F Intersected face\n\u002F\u002F   faceIndex: number,         \u002F\u002F Face index\n\u002F\u002F   object: Object3D,          \u002F\u002F Intersected object\n\u002F\u002F   uv: Vector2,               \u002F\u002F UV coordinates at intersection\n\u002F\u002F   uv1: Vector2,              \u002F\u002F Second UV channel\n\u002F\u002F   normal: Vector3,           \u002F\u002F Interpolated face normal\n\u002F\u002F   instanceId: number         \u002F\u002F For InstancedMesh\n\u002F\u002F }\n```\n\n### Mouse Position Conversion\n\n```javascript\nconst mouse = new THREE.Vector2();\n\nfunction updateMouse(event) {\n  \u002F\u002F For full window\n  mouse.x = (event.clientX \u002F window.innerWidth) * 2 - 1;\n  mouse.y = -(event.clientY \u002F window.innerHeight) * 2 + 1;\n}\n\n\u002F\u002F For specific canvas element\nfunction updateMouseCanvas(event, canvas) {\n  const rect = canvas.getBoundingClientRect();\n  mouse.x = ((event.clientX - rect.left) \u002F rect.width) * 2 - 1;\n  mouse.y = -((event.clientY - rect.top) \u002F rect.height) * 2 + 1;\n}\n```\n\n### Touch Support\n\n```javascript\nfunction onTouchStart(event) {\n  event.preventDefault();\n\n  if (event.touches.length === 1) {\n    const touch = event.touches[0];\n    mouse.x = (touch.clientX \u002F window.innerWidth) * 2 - 1;\n    mouse.y = -(touch.clientY \u002F window.innerHeight) * 2 + 1;\n\n    raycaster.setFromCamera(mouse, camera);\n    const intersects = raycaster.intersectObjects(clickableObjects);\n\n    if (intersects.length > 0) {\n      handleSelection(intersects[0]);\n    }\n  }\n}\n\nrenderer.domElement.addEventListener(\"touchstart\", onTouchStart);\n```\n\n### Raycaster Options\n\n```javascript\nconst raycaster = new THREE.Raycaster();\n\n\u002F\u002F Near\u002Ffar clipping (default: 0, Infinity)\nraycaster.near = 0;\nraycaster.far = 100;\n\n\u002F\u002F Line\u002FPoints precision\nraycaster.params.Line.threshold = 0.1;\nraycaster.params.Points.threshold = 0.1;\n\n\u002F\u002F Layers (only intersect objects on specific layers)\nraycaster.layers.set(1);\n```\n\n### Efficient Raycasting\n\n```javascript\n\u002F\u002F Only check specific objects\nconst clickables = [mesh1, mesh2, mesh3];\nconst intersects = raycaster.intersectObjects(clickables, false);\n\n\u002F\u002F Use layers for filtering\nmesh1.layers.set(1); \u002F\u002F Clickable layer\nraycaster.layers.set(1);\n\n\u002F\u002F Throttle raycast for hover effects\nlet lastRaycast = 0;\nfunction onMouseMove(event) {\n  const now = Date.now();\n  if (now - lastRaycast \u003C 50) return; \u002F\u002F 20fps max\n  lastRaycast = now;\n\n  \u002F\u002F Raycast here\n}\n```\n\n## Camera Controls\n\n### OrbitControls\n\n```javascript\nimport { OrbitControls } from \"three\u002Faddons\u002Fcontrols\u002FOrbitControls.js\";\n\nconst controls = new OrbitControls(camera, renderer.domElement);\n\n\u002F\u002F Damping (smooth movement)\ncontrols.enableDamping = true;\ncontrols.dampingFactor = 0.05;\n\n\u002F\u002F Rotation limits\ncontrols.minPolarAngle = 0; \u002F\u002F Top\ncontrols.maxPolarAngle = Math.PI \u002F 2; \u002F\u002F Horizon\ncontrols.minAzimuthAngle = -Math.PI \u002F 4; \u002F\u002F Left\ncontrols.maxAzimuthAngle = Math.PI \u002F 4; \u002F\u002F Right\n\n\u002F\u002F Zoom limits\ncontrols.minDistance = 2;\ncontrols.maxDistance = 50;\n\n\u002F\u002F Enable\u002Fdisable features\ncontrols.enableRotate = true;\ncontrols.enableZoom = true;\ncontrols.enablePan = true;\n\n\u002F\u002F Auto-rotate\ncontrols.autoRotate = true;\ncontrols.autoRotateSpeed = 2.0;\n\n\u002F\u002F Target (orbit point)\ncontrols.target.set(0, 1, 0);\n\n\u002F\u002F Update in animation loop\nfunction animate() {\n  controls.update(); \u002F\u002F Required for damping and auto-rotate\n  renderer.render(scene, camera);\n}\n```\n\n#### OrbitControls Programmatic Methods (r183)\n\n```javascript\n\u002F\u002F Programmatic camera movement\ncontrols.dolly(1.5); \u002F\u002F Dolly in\u002Fout (zoom for perspective cameras)\ncontrols.pan(deltaX, deltaY); \u002F\u002F Pan the camera\ncontrols.rotate(deltaAzimuth, deltaPolar); \u002F\u002F Rotate around target\n\n\u002F\u002F Cursor style (r183)\ncontrols.cursorStyle = { orbit: \"grab\", pan: \"move\", dolly: \"zoom-in\" };\n```\n\n### FlyControls\n\n```javascript\nimport { FlyControls } from \"three\u002Faddons\u002Fcontrols\u002FFlyControls.js\";\n\nconst controls = new FlyControls(camera, renderer.domElement);\ncontrols.movementSpeed = 10;\ncontrols.rollSpeed = Math.PI \u002F 24;\ncontrols.dragToLook = true;\n\n\u002F\u002F Update with delta\nfunction animate() {\n  controls.update(clock.getDelta());\n  renderer.render(scene, camera);\n}\n```\n\n### FirstPersonControls\n\n```javascript\nimport { FirstPersonControls } from \"three\u002Faddons\u002Fcontrols\u002FFirstPersonControls.js\";\n\nconst controls = new FirstPersonControls(camera, renderer.domElement);\ncontrols.movementSpeed = 10;\ncontrols.lookSpeed = 0.1;\ncontrols.lookVertical = true;\ncontrols.constrainVertical = true;\ncontrols.verticalMin = Math.PI \u002F 4;\ncontrols.verticalMax = (Math.PI * 3) \u002F 4;\n\nfunction animate() {\n  controls.update(clock.getDelta());\n}\n```\n\n### PointerLockControls\n\n```javascript\nimport { PointerLockControls } from \"three\u002Faddons\u002Fcontrols\u002FPointerLockControls.js\";\n\nconst controls = new PointerLockControls(camera, document.body);\n\n\u002F\u002F Lock pointer on click\ndocument.addEventListener(\"click\", () => {\n  controls.lock();\n});\n\ncontrols.addEventListener(\"lock\", () => {\n  console.log(\"Pointer locked\");\n});\n\ncontrols.addEventListener(\"unlock\", () => {\n  console.log(\"Pointer unlocked\");\n});\n\n\u002F\u002F Movement\nconst velocity = new THREE.Vector3();\nconst direction = new THREE.Vector3();\nconst moveForward = false;\nconst moveBackward = false;\n\ndocument.addEventListener(\"keydown\", (event) => {\n  switch (event.code) {\n    case \"KeyW\":\n      moveForward = true;\n      break;\n    case \"KeyS\":\n      moveBackward = true;\n      break;\n  }\n});\n\nfunction animate() {\n  if (controls.isLocked) {\n    direction.z = Number(moveForward) - Number(moveBackward);\n    direction.normalize();\n\n    velocity.z -= direction.z * 0.1;\n    velocity.z *= 0.9; \u002F\u002F Friction\n\n    controls.moveForward(-velocity.z);\n  }\n}\n```\n\n### TrackballControls\n\n```javascript\nimport { TrackballControls } from \"three\u002Faddons\u002Fcontrols\u002FTrackballControls.js\";\n\nconst controls = new TrackballControls(camera, renderer.domElement);\ncontrols.rotateSpeed = 2.0;\ncontrols.zoomSpeed = 1.2;\ncontrols.panSpeed = 0.8;\ncontrols.staticMoving = true;\n\nfunction animate() {\n  controls.update();\n}\n```\n\n### MapControls\n\n```javascript\nimport { MapControls } from \"three\u002Faddons\u002Fcontrols\u002FMapControls.js\";\n\nconst controls = new MapControls(camera, renderer.domElement);\ncontrols.enableDamping = true;\ncontrols.dampingFactor = 0.05;\ncontrols.screenSpacePanning = false;\ncontrols.maxPolarAngle = Math.PI \u002F 2;\n```\n\n## TransformControls\n\nGizmo for moving\u002Frotating\u002Fscaling objects.\n\n```javascript\nimport { TransformControls } from \"three\u002Faddons\u002Fcontrols\u002FTransformControls.js\";\n\nconst transformControls = new TransformControls(camera, renderer.domElement);\nscene.add(transformControls);\n\n\u002F\u002F Attach to object\ntransformControls.attach(selectedMesh);\n\n\u002F\u002F Switch modes\ntransformControls.setMode(\"translate\"); \u002F\u002F 'translate', 'rotate', 'scale'\n\n\u002F\u002F Change space\ntransformControls.setSpace(\"local\"); \u002F\u002F 'local', 'world'\n\n\u002F\u002F Size\ntransformControls.setSize(1);\n\n\u002F\u002F Events\ntransformControls.addEventListener(\"dragging-changed\", (event) => {\n  \u002F\u002F Disable orbit controls while dragging\n  orbitControls.enabled = !event.value;\n});\n\ntransformControls.addEventListener(\"change\", () => {\n  renderer.render(scene, camera);\n});\n\n\u002F\u002F Keyboard shortcuts\nwindow.addEventListener(\"keydown\", (event) => {\n  switch (event.key) {\n    case \"g\":\n      transformControls.setMode(\"translate\");\n      break;\n    case \"r\":\n      transformControls.setMode(\"rotate\");\n      break;\n    case \"s\":\n      transformControls.setMode(\"scale\");\n      break;\n    case \"Escape\":\n      transformControls.detach();\n      break;\n  }\n});\n```\n\n## DragControls\n\nDrag objects directly.\n\n```javascript\nimport { DragControls } from \"three\u002Faddons\u002Fcontrols\u002FDragControls.js\";\n\nconst draggableObjects = [mesh1, mesh2, mesh3];\nconst dragControls = new DragControls(\n  draggableObjects,\n  camera,\n  renderer.domElement,\n);\n\ndragControls.addEventListener(\"dragstart\", (event) => {\n  orbitControls.enabled = false;\n  event.object.material.emissive.set(0xaaaaaa);\n});\n\ndragControls.addEventListener(\"drag\", (event) => {\n  \u002F\u002F Constrain to ground plane\n  event.object.position.y = 0;\n});\n\ndragControls.addEventListener(\"dragend\", (event) => {\n  orbitControls.enabled = true;\n  event.object.material.emissive.set(0x000000);\n});\n```\n\n## Selection System\n\n### Click to Select\n\n```javascript\nconst raycaster = new THREE.Raycaster();\nconst mouse = new THREE.Vector2();\nlet selectedObject = null;\n\nfunction onMouseDown(event) {\n  mouse.x = (event.clientX \u002F window.innerWidth) * 2 - 1;\n  mouse.y = -(event.clientY \u002F window.innerHeight) * 2 + 1;\n\n  raycaster.setFromCamera(mouse, camera);\n  const intersects = raycaster.intersectObjects(selectableObjects);\n\n  \u002F\u002F Deselect previous\n  if (selectedObject) {\n    selectedObject.material.emissive.set(0x000000);\n  }\n\n  \u002F\u002F Select new\n  if (intersects.length > 0) {\n    selectedObject = intersects[0].object;\n    selectedObject.material.emissive.set(0x444444);\n  } else {\n    selectedObject = null;\n  }\n}\n```\n\n### Box Selection\n\n```javascript\nimport { SelectionBox } from \"three\u002Faddons\u002Finteractive\u002FSelectionBox.js\";\nimport { SelectionHelper } from \"three\u002Faddons\u002Finteractive\u002FSelectionHelper.js\";\n\nconst selectionBox = new SelectionBox(camera, scene);\nconst selectionHelper = new SelectionHelper(renderer, \"selectBox\"); \u002F\u002F CSS class\n\ndocument.addEventListener(\"pointerdown\", (event) => {\n  selectionBox.startPoint.set(\n    (event.clientX \u002F window.innerWidth) * 2 - 1,\n    -(event.clientY \u002F window.innerHeight) * 2 + 1,\n    0.5,\n  );\n});\n\ndocument.addEventListener(\"pointermove\", (event) => {\n  if (selectionHelper.isDown) {\n    selectionBox.endPoint.set(\n      (event.clientX \u002F window.innerWidth) * 2 - 1,\n      -(event.clientY \u002F window.innerHeight) * 2 + 1,\n      0.5,\n    );\n  }\n});\n\ndocument.addEventListener(\"pointerup\", (event) => {\n  selectionBox.endPoint.set(\n    (event.clientX \u002F window.innerWidth) * 2 - 1,\n    -(event.clientY \u002F window.innerHeight) * 2 + 1,\n    0.5,\n  );\n\n  const selected = selectionBox.select();\n  console.log(\"Selected objects:\", selected);\n});\n```\n\n### Hover Effects\n\n```javascript\nconst raycaster = new THREE.Raycaster();\nconst mouse = new THREE.Vector2();\nlet hoveredObject = null;\n\nfunction onMouseMove(event) {\n  mouse.x = (event.clientX \u002F window.innerWidth) * 2 - 1;\n  mouse.y = -(event.clientY \u002F window.innerHeight) * 2 + 1;\n\n  raycaster.setFromCamera(mouse, camera);\n  const intersects = raycaster.intersectObjects(hoverableObjects);\n\n  \u002F\u002F Reset previous hover\n  if (hoveredObject) {\n    hoveredObject.material.color.set(hoveredObject.userData.originalColor);\n    document.body.style.cursor = \"default\";\n  }\n\n  \u002F\u002F Apply new hover\n  if (intersects.length > 0) {\n    hoveredObject = intersects[0].object;\n    if (!hoveredObject.userData.originalColor) {\n      hoveredObject.userData.originalColor =\n        hoveredObject.material.color.getHex();\n    }\n    hoveredObject.material.color.set(0xff6600);\n    document.body.style.cursor = \"pointer\";\n  } else {\n    hoveredObject = null;\n  }\n}\n\nwindow.addEventListener(\"mousemove\", onMouseMove);\n```\n\n## Keyboard Input\n\n```javascript\nconst keys = {};\n\ndocument.addEventListener(\"keydown\", (event) => {\n  keys[event.code] = true;\n});\n\ndocument.addEventListener(\"keyup\", (event) => {\n  keys[event.code] = false;\n});\n\nfunction update() {\n  const speed = 0.1;\n\n  if (keys[\"KeyW\"]) player.position.z -= speed;\n  if (keys[\"KeyS\"]) player.position.z += speed;\n  if (keys[\"KeyA\"]) player.position.x -= speed;\n  if (keys[\"KeyD\"]) player.position.x += speed;\n  if (keys[\"Space\"]) player.position.y += speed;\n  if (keys[\"ShiftLeft\"]) player.position.y -= speed;\n}\n```\n\n## World-Screen Coordinate Conversion\n\n### World to Screen\n\n```javascript\nfunction worldToScreen(position, camera) {\n  const vector = position.clone();\n  vector.project(camera);\n\n  return {\n    x: ((vector.x + 1) \u002F 2) * window.innerWidth,\n    y: (-(vector.y - 1) \u002F 2) * window.innerHeight,\n  };\n}\n\n\u002F\u002F Position HTML element over 3D object\nconst screenPos = worldToScreen(mesh.position, camera);\nelement.style.left = screenPos.x + \"px\";\nelement.style.top = screenPos.y + \"px\";\n```\n\n### Screen to World\n\n```javascript\nfunction screenToWorld(screenX, screenY, camera, targetZ = 0) {\n  const vector = new THREE.Vector3(\n    (screenX \u002F window.innerWidth) * 2 - 1,\n    -(screenY \u002F window.innerHeight) * 2 + 1,\n    0.5,\n  );\n\n  vector.unproject(camera);\n\n  const dir = vector.sub(camera.position).normalize();\n  const distance = (targetZ - camera.position.z) \u002F dir.z;\n\n  return camera.position.clone().add(dir.multiplyScalar(distance));\n}\n```\n\n### Ray-Plane Intersection\n\n```javascript\nfunction getRayPlaneIntersection(mouse, camera, plane) {\n  const raycaster = new THREE.Raycaster();\n  raycaster.setFromCamera(mouse, camera);\n\n  const intersection = new THREE.Vector3();\n  raycaster.ray.intersectPlane(plane, intersection);\n\n  return intersection;\n}\n\n\u002F\u002F Ground plane\nconst groundPlane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);\nconst worldPos = getRayPlaneIntersection(mouse, camera, groundPlane);\n```\n\n## Event Handling Best Practices\n\n```javascript\nclass InteractionManager {\n  constructor(camera, renderer, scene) {\n    this.camera = camera;\n    this.renderer = renderer;\n    this.scene = scene;\n    this.raycaster = new THREE.Raycaster();\n    this.mouse = new THREE.Vector2();\n    this.clickables = [];\n\n    this.bindEvents();\n  }\n\n  bindEvents() {\n    const canvas = this.renderer.domElement;\n\n    canvas.addEventListener(\"click\", (e) => this.onClick(e));\n    canvas.addEventListener(\"mousemove\", (e) => this.onMouseMove(e));\n    canvas.addEventListener(\"touchstart\", (e) => this.onTouchStart(e));\n  }\n\n  updateMouse(event) {\n    const rect = this.renderer.domElement.getBoundingClientRect();\n    this.mouse.x = ((event.clientX - rect.left) \u002F rect.width) * 2 - 1;\n    this.mouse.y = -((event.clientY - rect.top) \u002F rect.height) * 2 + 1;\n  }\n\n  getIntersects() {\n    this.raycaster.setFromCamera(this.mouse, this.camera);\n    return this.raycaster.intersectObjects(this.clickables, true);\n  }\n\n  onClick(event) {\n    this.updateMouse(event);\n    const intersects = this.getIntersects();\n\n    if (intersects.length > 0) {\n      const object = intersects[0].object;\n      if (object.userData.onClick) {\n        object.userData.onClick(intersects[0]);\n      }\n    }\n  }\n\n  addClickable(object, callback) {\n    this.clickables.push(object);\n    object.userData.onClick = callback;\n  }\n\n  dispose() {\n    \u002F\u002F Remove event listeners\n  }\n}\n\n\u002F\u002F Usage\nconst interaction = new InteractionManager(camera, renderer, scene);\ninteraction.addClickable(mesh, (intersect) => {\n  console.log(\"Clicked at:\", intersect.point);\n});\n```\n\n## Performance Tips\n\n1. **Limit raycasts**: Throttle mousemove handlers\n2. **Use layers**: Filter raycast targets\n3. **Simple collision meshes**: Use invisible simpler geometry for raycasting\n4. **Disable controls when not needed**: `controls.enabled = false`\n5. **Batch updates**: Group interaction checks\n\n```javascript\n\u002F\u002F Use simpler geometry for raycasting\nconst complexMesh = loadedModel;\nconst collisionMesh = new THREE.Mesh(\n  new THREE.BoxGeometry(1, 1, 1),\n  new THREE.MeshBasicMaterial({ visible: false }),\n);\ncollisionMesh.userData.target = complexMesh;\nclickables.push(collisionMesh);\n```\n\n## See Also\n\n- `threejs-fundamentals` - Camera and scene setup\n- `threejs-animation` - Animating interactions\n- `threejs-shaders` - Visual feedback effects\n",{"name":5,"risk":41,"source":22,"description":7},"unknown","main","a50a3aa6b39fb0e1b7db88bef1bfc9c93606e126","modules\u002Fagent_skills\u002Fawesome-skills\u002Fplaybooks\u002Fthreejs-interaction",0,"https:\u002F\u002Fgithub.com\u002FSam-06060\u002Fjarvis-assistant","https:\u002F\u002Fgithub.com\u002FSam-06060","Mobile Application Developer | Kotlin | Flutter, KMP, Swfit, Android,Swift UI | Building at Saar It Resources | Creator of Jarvis (AI Assistant)","2026-06-23 05:13:38",{"source":8,"skillName":5,"commands":51,"prompt":61,"zipAvailable":62},[52,55,58],{"tool":53,"command":54},"npx","npx skills add Sam-06060\u002Fjarvis-assistant --skill threejs-interaction",{"tool":56,"command":57},"bunx","bunx skills add Sam-06060\u002Fjarvis-assistant --skill threejs-interaction",{"tool":59,"command":60},"pnpm","pnpm dlx skills add Sam-06060\u002Fjarvis-assistant --skill threejs-interaction","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FSam-06060\u002Fjarvis-assistant\u002Fblob\u002Fmain\u002Fmodules\u002Fagent_skills\u002Fawesome-skills\u002Fplaybooks\u002Fthreejs-interaction\u002FSKILL.md",true,[],[65,78,94,121,140,167],{"skillNo":66,"name":67,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":68,"categories":69,"keywords":75,"publishedAt":36},"01M6GDRVS6FXX3ESH0C9DW01C0","test_skill","https:\u002F\u002Fgithub.com\u002FSam-06060\u002Fjarvis-assistant\u002Fblob\u002Fmain\u002Fscratch\u002Ftest_skill\u002FSKILL.md",[70],{"categoryNo":71,"categoryName":72,"taxonomyType":73,"taxonomyTypeDesc":74},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",[76,77],"Test Skill","test",{"skillNo":79,"name":80,"nameZh":6,"description":81,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":82,"categories":83,"keywords":84,"publishedAt":36},"01M6GDRQ40HX22MA6XWC31RHHK","zustand-store-ts","Create Zustand stores following established patterns with proper TypeScript types and middleware.","https:\u002F\u002Fgithub.com\u002FSam-06060\u002Fjarvis-assistant\u002Fblob\u002Fmain\u002Fmodules\u002Fagent_skills\u002Fawesome-skills\u002Fplaybooks\u002Fzustand-store-ts\u002FSKILL.md",[],[85,86,87,88,89,90,91,22,92,93],"zustand store ts","zustand","store","with","types","middleware","patterns","create","typescript",{"skillNo":95,"name":96,"nameZh":6,"description":97,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":98,"categories":99,"keywords":103,"publishedAt":36},"01M6GDRKEA0WE670SPFWX5GKCN","zoom-automation","Automate Zoom meeting creation, management, recordings, webinars, and participant tracking via Rube MCP (Composio). Always search tools first for current schemas.","https:\u002F\u002Fgithub.com\u002FSam-06060\u002Fjarvis-assistant\u002Fblob\u002Fmain\u002Fmodules\u002Fagent_skills\u002Fawesome-skills\u002Fplaybooks\u002Fzoom-automation\u002FSKILL.md",[100],{"categoryNo":101,"categoryName":102,"taxonomyType":73,"taxonomyTypeDesc":74},"01JBSEEDCAT000000000000023","Skill与智能体开发",[104,105,106,107,108,109,110,111,112,113,114,115,116,117,22,118,119,120],"automation","zoom automation","zoom","first","Tools","search","MCP","via","meeting","automate","critical","creation","webinars","composio","recordings","management","tracking",{"skillNo":122,"name":123,"nameZh":6,"description":124,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":125,"categories":126,"keywords":128,"publishedAt":36},"01M6GDRFS1452PC71JQ38S24HR","zoho-crm-automation","Automate Zoho CRM tasks via Rube MCP (Composio): create\u002Fupdate records, search contacts, manage leads, and convert leads. Always search tools first for current schemas.","https:\u002F\u002Fgithub.com\u002FSam-06060\u002Fjarvis-assistant\u002Fblob\u002Fmain\u002Fmodules\u002Fagent_skills\u002Fawesome-skills\u002Fplaybooks\u002Fzoho-crm-automation\u002FSKILL.md",[127],{"categoryNo":101,"categoryName":102,"taxonomyType":73,"taxonomyTypeDesc":74},[129,104,130,131,132,133,134,22,109,135,117,136,114,113,108,137,92,138,110,139],"crm automation","zoho crm","crm","zoho crm automation","zoho","leads","contacts","records","update","tasks","manage",{"skillNo":141,"name":142,"nameZh":6,"description":143,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":144,"categories":145,"keywords":149,"publishedAt":36},"01M6GDRCKQBAVTGHX5XBH26KPZ","zod-validation-expert","Expert in Zod — TypeScript-first schema validation. Covers parsing, custom errors, refinements, type inference, and integration with React Hook Form, Next.js, and tRPC.","https:\u002F\u002Fgithub.com\u002FSam-06060\u002Fjarvis-assistant\u002Fblob\u002Fmain\u002Fmodules\u002Fagent_skills\u002Fawesome-skills\u002Fplaybooks\u002Fzod-validation-expert\u002FSKILL.md",[146],{"categoryNo":147,"categoryName":148,"taxonomyType":73,"taxonomyTypeDesc":74},"01JBSEEDCAT000000000000009","前端开发",[150,151,152,153,154,93,155,156,157,158,159,160,88,161,162,163,164,22,165,166],"expert","zod","zod validation expert","validation","react","safe","parsing","errors","schema validation","react hook form","hook","trpc","form","type","next","schema","Next.js",{"skillNo":168,"name":169,"nameZh":6,"description":170,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":171,"categories":172,"keywords":174,"publishedAt":36},"01M6GDR658B08K4MY0RWD4A6EH","zeroize-audit","Detects missing zeroization of sensitive data in source code and identifies zeroization removed by compiler optimizations, with assembly-level analysis, and control-flow verification. Use for auditing C\u002FC++\u002FRust code handling secrets, keys, passwords, or other sensitive data.","https:\u002F\u002Fgithub.com\u002FSam-06060\u002Fjarvis-assistant\u002Fblob\u002Fmain\u002Fmodules\u002Fagent_skills\u002Fawesome-skills\u002Fplaybooks\u002Fzeroize-audit\u002FSKILL.md",[173],{"categoryNo":101,"categoryName":102,"taxonomyType":73,"taxonomyTypeDesc":74},[175,176,177,178,179,180,181,182,22,183,184,185,186,187,188,189,190,191,192,110],"zeroize audit","audit","write","passwords","get","project","c++","activate","assembly","read","Bash","secrets","analysis","data","flow","verification","code","rust"]