@forgeax/engine-picking 0.1.32 → 0.1.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -20,6 +20,23 @@ never the reverse.
20
20
  - **`viewportToWorld(world, cameraEntity, screenX, screenY, viewportWidth, viewportHeight)`**
21
21
  — exposes the same camera unprojection as a world-space `Ray` for cursor
22
22
  placement, gizmos, and custom plane/triangle queries.
23
+ - **`pickDisplay` / `computeDisplayScreenRay`** — explicit display-space
24
+ entrypoints. They consume the effective `BarrelDistortionMapping` from the
25
+ submitted frame, map the displayed physical pixel once, then use the existing
26
+ unwarped camera math. The submitted mapping is mandatory, including its
27
+ identity case; absent, retired, lost, or zero-size frame contexts return a
28
+ miss. Legacy `pick` and `viewportToWorld` remain unwarped APIs.
29
+ - **`pickVertexDisplay` / `pickVertexOnEntityDisplay`** — display-space vertex
30
+ queries. They project each candidate back through the same scene-to-display
31
+ inverse before applying the optional physical-pixel radius and sorting, so a
32
+ nonlinear warp cannot change which vertex is closest merely by correcting the
33
+ pointer.
34
+
35
+ > [!WARNING]
36
+ > An omitted `barrelDistortion` field means that no accepted submitted display
37
+ > context is available. Treat it as a miss and wait for a new frame. An
38
+ > identity query is valid only with an explicit submitted mapping whose
39
+ > `strength` is `0`.
23
40
  - **`pickTriangle`** — exact static CPU triangle query for a screen ray. It
24
41
  transforms indexed or non-indexed triangle-list vertices into world space,
25
42
  returns the nearest world point, distance, barycentric weights, entity,
@@ -84,6 +101,37 @@ and `orthographic` camera projections are supported. Reads the resolved
84
101
  `GlobalTransform.world` mat4 directly (feat-20260601 D-3), so the camera + candidates
85
102
  must have propagated transforms for the current frame.
86
103
 
104
+ ### Display-space interaction
105
+
106
+ ```ts
107
+ import { pickDisplay } from '@forgeax/engine-picking';
108
+
109
+ const hit = pickDisplay(
110
+ world,
111
+ cameraEntity,
112
+ outputPixelX,
113
+ outputPixelY,
114
+ submittedReceipt.barrelDistortion,
115
+ outputWidth,
116
+ outputHeight,
117
+ );
118
+ ```
119
+
120
+ Coordinates are continuous physical output pixels. The host first converts the
121
+ CSS pointer through the actual canvas/viewport rectangle and output extent; it
122
+ does not add a half-pixel offset. Out-of-viewport and crop misses return
123
+ `undefined` before the math layer's normal screen clamp. Reuse the same receipt
124
+ mapping for labels, crosshairs, and display-space queries so a newer ECS camera
125
+ component cannot disagree with the frame on screen. The App
126
+ `subscribeBrowserFrameSubmitted(canvas, listener)` helper forwards the
127
+ deep-frozen mapping and frame identity from the accepted browser submission;
128
+ unsubscribe it when the canvas or renderer is retired. A lost or zero-size
129
+ context must be discarded and reacquired through the existing App/Renderer
130
+ recovery path. The width and height arguments are an explicit check against
131
+ `mapping.width` and `mapping.height`; a mismatch, an undefined mapping, or an
132
+ identity guess without a submitted mapping returns a miss. Display picking
133
+ never falls back to the live World camera.
134
+
87
135
  ### Screen-to-world (`viewportToWorld`)
88
136
 
89
137
  | Function | Signature | Return |
@@ -132,10 +180,9 @@ Only `triangle-list` submeshes participate; skinned meshes report
132
180
  nearest `TriangleHit`; `miss` means every candidate was tested and no triangle
133
181
  intersects the ray; `unavailable` names intersecting entities whose CPU
134
182
  geometry, current skinned pose, or explicit instance transforms cannot be
135
- tested. For an entity carrying `Instances`, pass its renderer-owned
136
- `InstanceCollectionStore` as `options.instances`; a hit then includes the
137
- zero-based `instanceIndex`. The picker uses the store's non-consuming `peek`
138
- read, so inspection cannot consume a later render upload range. Pass
183
+ tested. For an entity carrying `Instances`, the picker reads World-owned
184
+ `Instances.transforms`; a hit includes the zero-based `instanceIndex`.
185
+ No Renderer or collection resolver is needed. Pass
139
186
  `AssetRegistry.guidOf` as `assetGuidOf` when provenance is needed. The query
140
187
  does not mutate the World or own an asset registry.
141
188
 
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=display-picking.unit.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display-picking.unit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/display-picking.unit.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=voxel-display-consumer.test-d.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voxel-display-consumer.test-d.d.ts","sourceRoot":"","sources":["../../src/__tests__/voxel-display-consumer.test-d.ts"],"names":[],"mappings":""}
@@ -0,0 +1,27 @@
1
+ import type { EntityHandle, World } from '@forgeax/engine-ecs';
2
+ import { type BarrelDistortionMapping, type DisplayPoint } from '@forgeax/engine-render';
3
+ import { type PickHit } from './pick';
4
+ import { type ScreenRay } from './pick-core';
5
+ import { type VertexHit } from './pick-vertex';
6
+ export interface DisplayVertexPickOptions {
7
+ readonly limit?: number;
8
+ /** Maximum distance in displayed physical pixels; omitted keeps all ray hits. */
9
+ readonly radius?: number;
10
+ }
11
+ /**
12
+ * Convert a displayed output pixel to the matching unwarped scene pixel.
13
+ *
14
+ * `undefined` is the fail-closed signal that no accepted submitted frame is
15
+ * available. It is not an identity mapping; callers must wait for a new
16
+ * submitted frame (including an explicit zero-strength mapping).
17
+ */
18
+ export declare function displayToScenePixel(out: DisplayPoint, mapping: BarrelDistortionMapping | undefined, displayX: number, displayY: number): boolean;
19
+ /** Build a world ray from the physical pixel currently visible on screen. */
20
+ export declare function computeDisplayScreenRay(world: World, cameraEntity: EntityHandle, displayX: number, displayY: number, mapping: BarrelDistortionMapping | undefined, viewportWidth: number, viewportHeight: number): ScreenRay | undefined;
21
+ /** Explicit display-space entity pick; legacy `pick` remains unwarped. */
22
+ export declare function pickDisplay(world: World, _cameraEntity: EntityHandle, displayX: number, displayY: number, mapping: BarrelDistortionMapping | undefined, viewportWidth: number, viewportHeight: number): PickHit | undefined;
23
+ /** Pick vertices using displayed-pixel radius and ordering under the same mapping. */
24
+ export declare function pickVertexDisplay(world: World, _cameraEntity: EntityHandle, displayX: number, displayY: number, mapping: BarrelDistortionMapping | undefined, viewportWidth: number, viewportHeight: number, options?: DisplayVertexPickOptions): VertexHit | VertexHit[] | undefined;
25
+ /** Pick vertices on one entity using displayed-pixel radius and ordering. */
26
+ export declare function pickVertexOnEntityDisplay(world: World, _cameraEntity: EntityHandle, displayX: number, displayY: number, mapping: BarrelDistortionMapping | undefined, viewportWidth: number, viewportHeight: number, entity: EntityHandle, options?: DisplayVertexPickOptions): VertexHit | VertexHit[] | undefined;
27
+ //# sourceMappingURL=display-picking.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display-picking.d.ts","sourceRoot":"","sources":["../src/display-picking.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAE/D,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,YAAY,EAGlB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,KAAK,OAAO,EAAqB,MAAM,QAAQ,CAAC;AACzD,OAAO,EAAgC,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAC3E,OAAO,EAGL,KAAK,SAAS,EACf,MAAM,eAAe,CAAC;AAEvB,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,iFAAiF;IACjF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,YAAY,EACjB,OAAO,EAAE,uBAAuB,GAAG,SAAS,EAC5C,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAGT;AA8BD,6EAA6E;AAC7E,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,KAAK,EACZ,YAAY,EAAE,YAAY,EAC1B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,uBAAuB,GAAG,SAAS,EAC5C,aAAa,EAAE,MAAM,EACrB,cAAc,EAAE,MAAM,GACrB,SAAS,GAAG,SAAS,CAoBvB;AAqBD,0EAA0E;AAC1E,wBAAgB,WAAW,CACzB,KAAK,EAAE,KAAK,EACZ,aAAa,EAAE,YAAY,EAC3B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,uBAAuB,GAAG,SAAS,EAC5C,aAAa,EAAE,MAAM,EACrB,cAAc,EAAE,MAAM,GACrB,OAAO,GAAG,SAAS,CAkBrB;AAiED,sFAAsF;AACtF,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,KAAK,EACZ,aAAa,EAAE,YAAY,EAC3B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,uBAAuB,GAAG,SAAS,EAC5C,aAAa,EAAE,MAAM,EACrB,cAAc,EAAE,MAAM,EACtB,OAAO,CAAC,EAAE,wBAAwB,GACjC,SAAS,GAAG,SAAS,EAAE,GAAG,SAAS,CAmCrC;AAED,6EAA6E;AAC7E,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,KAAK,EACZ,aAAa,EAAE,YAAY,EAC3B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,uBAAuB,GAAG,SAAS,EAC5C,aAAa,EAAE,MAAM,EACrB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,YAAY,EACpB,OAAO,CAAC,EAAE,wBAAwB,GACjC,SAAS,GAAG,SAAS,EAAE,GAAG,SAAS,CAkCrC"}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ export type { DisplayVertexPickOptions } from './display-picking';
2
+ export { computeDisplayScreenRay, displayToScenePixel, pickDisplay, pickVertexDisplay, pickVertexOnEntityDisplay, } from './display-picking';
1
3
  export type { PickHit } from './pick';
2
4
  export { pick } from './pick';
3
5
  export type { PickErrorCode } from './pick-errors';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,YAAY,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAG9B,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC7E,OAAO,EACL,YAAY,EACZ,KAAK,WAAW,EAChB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,6BAA6B,GACnC,MAAM,iBAAiB,CAAC;AAEzB,YAAY,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,YAAY,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EACL,uBAAuB,EACvB,mBAAmB,EACnB,WAAW,EACX,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,mBAAmB,CAAC;AAG3B,YAAY,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAG9B,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC7E,OAAO,EACL,YAAY,EACZ,KAAK,WAAW,EAChB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,6BAA6B,GACnC,MAAM,iBAAiB,CAAC;AAEzB,YAAY,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC"}