# id-picker

GPU-based object picker that reads per-pixel ids from a render target to detect mouse hover, click, and double-click on Three.js objects.

---

## `IdPicker<TargetType>`

Renders registered objects into a small off-screen render target, reads the pixel under the mouse cursor, and dispatches typed events identifying which object and which feature id was hit.

Extends Three.js `EventDispatcher`.

```typescript
new IdPicker<TargetType extends Object3D>()
```

### Methods

#### `setDomElement(elem) → void`

Attach (or detach) the picker to a DOM element. Mouse events are listened on this element.

| Name | Type | Description |
|------|------|-------------|
| `elem` | `HTMLElement \| null` | Element to listen on; pass `null` to detach |

#### `add(target, options?) → void`

Register a renderable object for picking.

| Name | Type | Default | Description |
|------|------|---------|-------------|
| `target` | `TargetType` | — | Object to register |
| `options.idAttrName` | `string` | `'id'` | Vertex attribute name carrying per-vertex feature ids |
| `options.vertexSource` | `string` | auto | Custom GLSL vertex source; use `PICKER_ID_OUTPUT` as the output variable |
| `options.uniforms` | `Record<string, IUniform>` | — | Additional uniforms for the pick shader |
| `options.withObject` | `boolean` | `true` | If `false`, object is rendered without occupying an object-id slot (useful for background geometry) |

#### `remove(target) → void`

Unregister an object and free its id slot.

#### `update(renderer, camera) → void`

Re-render the pick buffer and dispatch events. Call once per frame after the main render.

| Name | Type | Description |
|------|------|-------------|
| `renderer` | `WebGLRenderer` | Active renderer |
| `camera` | `Camera` | Camera used for the main scene |

#### `triggerEvent(type, e) → void`

Manually fire a mouse event (useful for testing or custom event routing).

#### `dispose() → void`

Release GPU resources and detach DOM listeners. Throws if called twice.

### Events

| Event | Payload | When |
|-------|---------|------|
| `mouseover` | `PickerEvent` | Emitted every frame the cursor is over a feature |
| `mouseenter` | `PickerEvent` | Emitted once when the cursor enters a new feature |
| `mouseleave` | `PickerEvent` | Emitted once when the cursor leaves a feature |
| `click` | `PickerEvent` | Emitted on click |
| `dblclick` | `PickerEvent` | Emitted on double-click |

### Example

```typescript
import { IdPicker } from '@yaoc1996/js-tools/three-utils'
import { Mesh } from 'three'

const picker = new IdPicker<Mesh>()
picker.setDomElement(renderer.domElement)
picker.add(mesh, { idAttrName: 'featureId' })

picker.addEventListener('click', ({ id, object }) => {
    console.log('clicked feature', id, 'on', object)
})

// in animation loop:
picker.update(renderer, camera)
```

### Notes

- Supports up to 15 objects registered with `withObject: true` at a time.
- The `id` in events is the raw 28-bit per-vertex feature id encoded in the render target. The `object` is the registered `TargetType` instance.

---

## Types

```typescript
type PickerEvent<TargetType> = {
    id: number
    object: TargetType | null
}
```
