@aura3d/engine 1.5.0 → 1.5.2
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 +111 -46
- package/dist/engine/agent-api/ApplicationKits.d.ts +307 -0
- package/dist/engine/agent-api/ApplicationKits.d.ts.map +1 -0
- package/dist/engine/agent-api/ApplicationKits.js +650 -0
- package/dist/engine/agent-api/ApplicationKits.js.map +1 -0
- package/dist/engine/agent-api/CombatFrameData.d.ts +210 -0
- package/dist/engine/agent-api/CombatFrameData.d.ts.map +1 -0
- package/dist/engine/agent-api/CombatFrameData.js +324 -0
- package/dist/engine/agent-api/CombatFrameData.js.map +1 -0
- package/dist/engine/agent-api/FocusSelection.d.ts +186 -0
- package/dist/engine/agent-api/FocusSelection.d.ts.map +1 -0
- package/dist/engine/agent-api/FocusSelection.js +436 -0
- package/dist/engine/agent-api/FocusSelection.js.map +1 -0
- package/dist/engine/agent-api/GameGenreKits.d.ts +32 -1
- package/dist/engine/agent-api/GameGenreKits.d.ts.map +1 -1
- package/dist/engine/agent-api/GameGenreKits.js +51 -7
- package/dist/engine/agent-api/GameGenreKits.js.map +1 -1
- package/dist/engine/agent-api/GameSceneGeometryBindings.d.ts +10 -0
- package/dist/engine/agent-api/GameSceneGeometryBindings.d.ts.map +1 -1
- package/dist/engine/agent-api/GameSceneGeometryBindings.js +7 -0
- package/dist/engine/agent-api/GameSceneGeometryBindings.js.map +1 -1
- package/dist/engine/agent-api/PlatformerMotion.d.ts +177 -0
- package/dist/engine/agent-api/PlatformerMotion.d.ts.map +1 -0
- package/dist/engine/agent-api/PlatformerMotion.js +207 -0
- package/dist/engine/agent-api/PlatformerMotion.js.map +1 -0
- package/dist/engine/agent-api/SceneQueries.d.ts +124 -0
- package/dist/engine/agent-api/SceneQueries.d.ts.map +1 -0
- package/dist/engine/agent-api/SceneQueries.js +221 -0
- package/dist/engine/agent-api/SceneQueries.js.map +1 -0
- package/dist/engine/agent-api/SpatialAnchoring.d.ts +279 -0
- package/dist/engine/agent-api/SpatialAnchoring.d.ts.map +1 -0
- package/dist/engine/agent-api/SpatialAnchoring.js +394 -0
- package/dist/engine/agent-api/SpatialAnchoring.js.map +1 -0
- package/dist/engine/agent-api/VehicleChassis.d.ts +192 -0
- package/dist/engine/agent-api/VehicleChassis.d.ts.map +1 -0
- package/dist/engine/agent-api/VehicleChassis.js +322 -0
- package/dist/engine/agent-api/VehicleChassis.js.map +1 -0
- package/dist/engine/agent-api/VehicleDriverAi.d.ts +123 -0
- package/dist/engine/agent-api/VehicleDriverAi.d.ts.map +1 -0
- package/dist/engine/agent-api/VehicleDriverAi.js +217 -0
- package/dist/engine/agent-api/VehicleDriverAi.js.map +1 -0
- package/dist/engine/agent-api/WorldLabelRenderer.d.ts +146 -0
- package/dist/engine/agent-api/WorldLabelRenderer.d.ts.map +1 -0
- package/dist/engine/agent-api/WorldLabelRenderer.js +331 -0
- package/dist/engine/agent-api/WorldLabelRenderer.js.map +1 -0
- package/dist/engine/agent-api/index.d.ts +64 -1
- package/dist/engine/agent-api/index.d.ts.map +1 -1
- package/dist/engine/agent-api/index.js +148 -2
- package/dist/engine/agent-api/index.js.map +1 -1
- package/dist/engine/agent-api/product-viewer-runtime.d.ts.map +1 -1
- package/dist/rendering/CameraFraming.d.ts +77 -0
- package/dist/rendering/CameraFraming.d.ts.map +1 -1
- package/dist/rendering/CameraFraming.js +176 -1
- package/dist/rendering/CameraFraming.js.map +1 -1
- package/dist/rendering/Renderer.d.ts +25 -2
- package/dist/rendering/Renderer.d.ts.map +1 -1
- package/dist/rendering/Renderer.js +11 -3
- package/dist/rendering/Renderer.js.map +1 -1
- package/dist/rendering/index.d.ts +3 -3
- package/dist/rendering/index.d.ts.map +1 -1
- package/dist/rendering/index.js +1 -1
- package/dist/rendering/index.js.map +1 -1
- package/package.json +120 -115
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reusable AI driving: racing line, look-ahead steering, curvature-based speed.
|
|
3
|
+
*
|
|
4
|
+
* ## The defect this replaces
|
|
5
|
+
*
|
|
6
|
+
* Turbo's opponent was a route-local controller that steered only to null its
|
|
7
|
+
* lateral offset from the racing line:
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* const steeringCorrection = -snapshot.signedTrackOffset * steeringGain;
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* A pure proportional term on present error has no notion of where the track goes
|
|
14
|
+
* next. Approaching a corner it steers straight until it is already off the line,
|
|
15
|
+
* then over-corrects, which is why the opponent read as moving sideways and leaving
|
|
16
|
+
* the circuit. It also had no braking model tied to the corner ahead, so it entered
|
|
17
|
+
* every turn at cruise speed and understeered out of it. And because the kit's
|
|
18
|
+
* off-track handler pulls a certified car back toward the centreline, the recovery
|
|
19
|
+
* looked like the car being dragged rather than driving.
|
|
20
|
+
*
|
|
21
|
+
* This module drives the way a driver does: it samples the route **ahead** of the
|
|
22
|
+
* car, aims at a look-ahead point on the racing line, and sets a target speed from
|
|
23
|
+
* the curvature it is about to meet. It also detects being stuck and being off
|
|
24
|
+
* track, and recovers deliberately.
|
|
25
|
+
*
|
|
26
|
+
* Pure and deterministic: given the same route and the same seed it produces the
|
|
27
|
+
* same lap, so a race is reproducible and testable.
|
|
28
|
+
*/
|
|
29
|
+
const AGGRESSION_PROFILES = {
|
|
30
|
+
cautious: { paceScale: 0.82, cornerScale: 0.82, lineVariation: 0.05, reactionScale: 1.4 },
|
|
31
|
+
balanced: { paceScale: 0.92, cornerScale: 0.94, lineVariation: 0.1, reactionScale: 1 },
|
|
32
|
+
aggressive: { paceScale: 1, cornerScale: 1.06, lineVariation: 0.16, reactionScale: 0.7 }
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Create a deterministic AI driver for a route.
|
|
36
|
+
*/
|
|
37
|
+
export function createVehicleDriverAi(route, config) {
|
|
38
|
+
/*
|
|
39
|
+
* A non-finite or non-positive route length makes every look-ahead progress NaN and
|
|
40
|
+
* the driver produces NaN steering, which reaches the renderer as an undefined
|
|
41
|
+
* position rather than as a visible error. Fail loudly at construction instead: a
|
|
42
|
+
* caller passing a route with no measurable length has a bug in its route adapter,
|
|
43
|
+
* and silently substituting 1 would hide it behind plausible-looking driving.
|
|
44
|
+
*/
|
|
45
|
+
if (!Number.isFinite(route.length) || route.length <= 0) {
|
|
46
|
+
throw new Error(`createVehicleDriverAi requires a positive, finite route length; received ${String(route.length)}. Suggested fix: measure the racing-line polyline length and pass it as DriverRoute.length.`);
|
|
47
|
+
}
|
|
48
|
+
const aggression = config.aggression ?? "balanced";
|
|
49
|
+
const profile = AGGRESSION_PROFILES[aggression];
|
|
50
|
+
const maxSpeed = Math.max(0.01, config.maxSpeed);
|
|
51
|
+
const paceFraction = clamp(config.paceFraction ?? 0.92, 0.2, 1) * profile.paceScale;
|
|
52
|
+
const lookAheadSeconds = Math.max(0.1, config.lookAheadSeconds ?? 1.1);
|
|
53
|
+
const minLookAhead = Math.max(0.1, config.minLookAhead ?? Math.max(1, route.length * 0.01));
|
|
54
|
+
const lineGain = Math.max(0, config.lineGain ?? 1.6);
|
|
55
|
+
const headingGain = Math.max(0, config.headingGain ?? 1.5);
|
|
56
|
+
const corneringAcceleration = Math.max(0.5, config.corneringAcceleration ?? 9) * profile.cornerScale;
|
|
57
|
+
const reactionSeconds = Math.max(0, (config.reactionSeconds ?? 0.14) * profile.reactionScale);
|
|
58
|
+
let elapsed = 0;
|
|
59
|
+
let sinceDecision = 0;
|
|
60
|
+
let held = { throttle: 0, brake: 0, steer: 0, drift: false };
|
|
61
|
+
let decisionCount = 0;
|
|
62
|
+
let stuckSeconds = 0;
|
|
63
|
+
let recovering = false;
|
|
64
|
+
let telemetry = {
|
|
65
|
+
controller: "aura-vehicle-driver-ai",
|
|
66
|
+
aggression,
|
|
67
|
+
targetSpeed: maxSpeed * paceFraction,
|
|
68
|
+
lookAheadDistance: minLookAhead,
|
|
69
|
+
upcomingCurvature: 0,
|
|
70
|
+
cornerSpeedLimit: maxSpeed,
|
|
71
|
+
steerFromLine: 0,
|
|
72
|
+
steerFromHeading: 0,
|
|
73
|
+
recovering: false,
|
|
74
|
+
stuckSeconds: 0,
|
|
75
|
+
decisionCount: 0,
|
|
76
|
+
input: held
|
|
77
|
+
};
|
|
78
|
+
// Deterministic line variation, so two identical races produce identical laps.
|
|
79
|
+
let random = (config.seed ?? 1) >>> 0 || 1;
|
|
80
|
+
const nextRandom = () => {
|
|
81
|
+
random ^= random << 13;
|
|
82
|
+
random ^= random >>> 17;
|
|
83
|
+
random ^= random << 5;
|
|
84
|
+
return ((random >>> 0) / 0xffffffff) * 2 - 1;
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Curvature of the racing line over the next `distance` units.
|
|
88
|
+
*
|
|
89
|
+
* Measured as heading change per unit distance across three samples, which is
|
|
90
|
+
* enough to distinguish a straight from a hairpin without differentiating a
|
|
91
|
+
* spline the route may not expose.
|
|
92
|
+
*/
|
|
93
|
+
const curvatureAhead = (progress, distance) => {
|
|
94
|
+
const span = distance / Math.max(1e-6, route.length);
|
|
95
|
+
const a = route.sample(wrap(progress));
|
|
96
|
+
const b = route.sample(wrap(progress + span * 0.5));
|
|
97
|
+
const c = route.sample(wrap(progress + span));
|
|
98
|
+
const turn = Math.abs(angleDelta(b.heading, a.heading)) + Math.abs(angleDelta(c.heading, b.heading));
|
|
99
|
+
return turn / Math.max(1e-6, distance);
|
|
100
|
+
};
|
|
101
|
+
const decide = (state) => {
|
|
102
|
+
const speed = Math.abs(state.speed);
|
|
103
|
+
// Look-ahead distance grows with speed: at pace the driver plans further out.
|
|
104
|
+
const lookAheadDistance = Math.max(minLookAhead, speed * lookAheadSeconds);
|
|
105
|
+
const lookAheadProgress = wrap(state.progress + lookAheadDistance / Math.max(1e-6, route.length));
|
|
106
|
+
const aim = route.sample(lookAheadProgress);
|
|
107
|
+
const halfWidth = Math.max(1e-6, route.halfWidth(state.progress));
|
|
108
|
+
// Steering has two terms. Heading error aims the car at the look-ahead point,
|
|
109
|
+
// which is what makes it turn into a corner. Lateral error brings it back to
|
|
110
|
+
// the line. A controller with only the second term steers straight at a corner
|
|
111
|
+
// until it has already left the road -- the defect this replaces.
|
|
112
|
+
const bearingToAim = Math.atan2(aim.y - state.position.y, aim.x - state.position.x);
|
|
113
|
+
const headingError = angleDelta(bearingToAim, state.heading);
|
|
114
|
+
const steerFromHeading = clamp(headingError * headingGain, -1, 1);
|
|
115
|
+
// Lateral error normalized by road width, so a gain tuned on a wide circuit
|
|
116
|
+
// does not under-correct on a narrow one.
|
|
117
|
+
const steerFromLine = clamp((-state.signedTrackOffset / halfWidth) * lineGain, -1, 1);
|
|
118
|
+
// Racing-line variation keeps two AI cars from tracing the same path, and is
|
|
119
|
+
// deterministic so it does not make a race unreproducible.
|
|
120
|
+
const variation = Math.sin(elapsed * 0.74) * profile.lineVariation + nextRandom() * profile.lineVariation * 0.1;
|
|
121
|
+
// Corner speed from the curvature ahead: v = sqrt(a_lat / kappa).
|
|
122
|
+
const curvature = curvatureAhead(state.progress, lookAheadDistance);
|
|
123
|
+
const cornerSpeedLimit = curvature > 1e-4
|
|
124
|
+
? Math.min(maxSpeed, Math.sqrt(corneringAcceleration / curvature))
|
|
125
|
+
: maxSpeed;
|
|
126
|
+
let targetSpeed = Math.min(maxSpeed * paceFraction, cornerSpeedLimit);
|
|
127
|
+
// Stuck and off-track recovery. A driver that has stopped moving is not
|
|
128
|
+
// "cruising slowly", it is stuck, and must be handled explicitly rather than
|
|
129
|
+
// relying on a kit to teleport it back to the centreline.
|
|
130
|
+
if (state.offTrack || stuckSeconds > 1.2) {
|
|
131
|
+
recovering = true;
|
|
132
|
+
}
|
|
133
|
+
else if (!state.offTrack && speed > maxSpeed * 0.18 && stuckSeconds === 0) {
|
|
134
|
+
recovering = false;
|
|
135
|
+
}
|
|
136
|
+
if (recovering) {
|
|
137
|
+
// Slow to a controllable speed and steer hard back toward the line.
|
|
138
|
+
targetSpeed = Math.min(targetSpeed, maxSpeed * 0.34);
|
|
139
|
+
}
|
|
140
|
+
const steer = clamp(recovering
|
|
141
|
+
? steerFromLine * 1.4 + steerFromHeading * 0.6
|
|
142
|
+
: steerFromHeading + steerFromLine * 0.55 + variation, -1, 1);
|
|
143
|
+
// Throttle and brake from the speed error. Braking is proportional to the
|
|
144
|
+
// overspeed, so entering a corner too fast produces real braking rather than a
|
|
145
|
+
// binary coast.
|
|
146
|
+
const speedError = targetSpeed - speed;
|
|
147
|
+
const throttle = speedError > 0 ? clamp(speedError / Math.max(1e-6, maxSpeed * 0.25), 0, 1) : 0;
|
|
148
|
+
const brake = speedError < 0 ? clamp(-speedError / Math.max(1e-6, maxSpeed * 0.3), 0, 1) : 0;
|
|
149
|
+
// Drift only when genuinely cornering hard at speed; a stationary car
|
|
150
|
+
// handbraking is the kind of detail that makes a demo read as fake.
|
|
151
|
+
const drift = !recovering && Math.abs(steer) > 0.55 && speed > maxSpeed * 0.45;
|
|
152
|
+
telemetry = {
|
|
153
|
+
controller: "aura-vehicle-driver-ai",
|
|
154
|
+
aggression,
|
|
155
|
+
targetSpeed: round(targetSpeed),
|
|
156
|
+
lookAheadDistance: round(lookAheadDistance),
|
|
157
|
+
upcomingCurvature: round(curvature),
|
|
158
|
+
cornerSpeedLimit: round(cornerSpeedLimit),
|
|
159
|
+
steerFromLine: round(steerFromLine),
|
|
160
|
+
steerFromHeading: round(steerFromHeading),
|
|
161
|
+
recovering,
|
|
162
|
+
stuckSeconds: round(stuckSeconds),
|
|
163
|
+
decisionCount,
|
|
164
|
+
input: { throttle: round(throttle), brake: round(brake), steer: round(steer), drift }
|
|
165
|
+
};
|
|
166
|
+
return telemetry.input;
|
|
167
|
+
};
|
|
168
|
+
return {
|
|
169
|
+
kind: "aura-vehicle-driver-ai",
|
|
170
|
+
decide(dt, state) {
|
|
171
|
+
const step = Math.max(0, Math.min(0.1, dt));
|
|
172
|
+
elapsed += step;
|
|
173
|
+
sinceDecision += step;
|
|
174
|
+
// A stopped car accumulates stuck time; moving clears it.
|
|
175
|
+
stuckSeconds = Math.abs(state.speed) < maxSpeed * 0.05 ? stuckSeconds + step : 0;
|
|
176
|
+
// Reaction delay: hold the previous decision until the driver would react.
|
|
177
|
+
if (sinceDecision < reactionSeconds && decisionCount > 0)
|
|
178
|
+
return held;
|
|
179
|
+
sinceDecision = 0;
|
|
180
|
+
decisionCount += 1;
|
|
181
|
+
held = decide(state);
|
|
182
|
+
return held;
|
|
183
|
+
},
|
|
184
|
+
telemetry() {
|
|
185
|
+
return telemetry;
|
|
186
|
+
},
|
|
187
|
+
reset() {
|
|
188
|
+
elapsed = 0;
|
|
189
|
+
sinceDecision = 0;
|
|
190
|
+
decisionCount = 0;
|
|
191
|
+
stuckSeconds = 0;
|
|
192
|
+
recovering = false;
|
|
193
|
+
held = { throttle: 0, brake: 0, steer: 0, drift: false };
|
|
194
|
+
random = (config.seed ?? 1) >>> 0 || 1;
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
/** Smallest signed angle from `b` to `a`, in -pi..pi. */
|
|
199
|
+
export function angleDelta(a, b) {
|
|
200
|
+
let delta = a - b;
|
|
201
|
+
while (delta > Math.PI)
|
|
202
|
+
delta -= Math.PI * 2;
|
|
203
|
+
while (delta < -Math.PI)
|
|
204
|
+
delta += Math.PI * 2;
|
|
205
|
+
return delta;
|
|
206
|
+
}
|
|
207
|
+
function wrap(progress) {
|
|
208
|
+
const value = progress % 1;
|
|
209
|
+
return value < 0 ? value + 1 : value;
|
|
210
|
+
}
|
|
211
|
+
function clamp(value, min, max) {
|
|
212
|
+
return Math.min(max, Math.max(min, Number.isFinite(value) ? value : min));
|
|
213
|
+
}
|
|
214
|
+
function round(value) {
|
|
215
|
+
return Math.round(value * 1e4) / 1e4;
|
|
216
|
+
}
|
|
217
|
+
//# sourceMappingURL=VehicleDriverAi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VehicleDriverAi.js","sourceRoot":"","sources":["../../../../../packages/engine/src/agent-api/VehicleDriverAi.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* World-anchored label rendering.
|
|
3
|
+
*
|
|
4
|
+
* ## The defect this fixes
|
|
5
|
+
*
|
|
6
|
+
* `labels.callout(...)` built a valid label node, the node reached the scene
|
|
7
|
+
* snapshot, and evidence counted it -- but nothing drew it. Labels were rendered
|
|
8
|
+
* only by `drawLabelNode`, which lives in the **canvas2d fallback** path. Every
|
|
9
|
+
* public route with a typed GLB takes the **production WebGL2** path, where
|
|
10
|
+
* `createProductionRuntimeRendererInput` collects model and primitive render
|
|
11
|
+
* items and ignores `kind: "label"` entirely.
|
|
12
|
+
*
|
|
13
|
+
* So the API was not partially implemented or mis-projected: it was implemented
|
|
14
|
+
* in the wrong render path. Every callout in every production route was silently
|
|
15
|
+
* dropped. The evidence collector counted label *nodes*, which is why reports
|
|
16
|
+
* showed labels present while the screen showed none.
|
|
17
|
+
*
|
|
18
|
+
* The fix is a real screen-space label layer: labels are world-anchored, projected
|
|
19
|
+
* with the scene's own view-projection matrix each frame, and drawn into a DOM
|
|
20
|
+
* overlay above the canvas. DOM is the right medium for text -- it is legible,
|
|
21
|
+
* accessible, and responsive -- but the *placement* is driven entirely by the 3D
|
|
22
|
+
* projection, so a label tracks its anchor while the camera moves. This is not a
|
|
23
|
+
* route-local DOM overlay: it is one reusable layer owned by the runtime.
|
|
24
|
+
*
|
|
25
|
+
* The projection math here is pure and unit-testable; only `mount` touches the DOM.
|
|
26
|
+
*/
|
|
27
|
+
export type LabelVec3 = readonly [number, number, number];
|
|
28
|
+
/** Policy for labels whose anchor falls outside the viewport. */
|
|
29
|
+
export type OffscreenPolicy =
|
|
30
|
+
/** Hide the label entirely. */
|
|
31
|
+
"hide"
|
|
32
|
+
/** Clamp to the nearest viewport edge, keeping the leader line pointing out. */
|
|
33
|
+
| "clamp"
|
|
34
|
+
/** Keep drawing at the projected position even when offscreen. */
|
|
35
|
+
| "draw";
|
|
36
|
+
export interface WorldLabel {
|
|
37
|
+
readonly id: string;
|
|
38
|
+
readonly text: string;
|
|
39
|
+
/** World point the label box is placed at. */
|
|
40
|
+
readonly anchor: LabelVec3;
|
|
41
|
+
/**
|
|
42
|
+
* World point a leader line points at, when it differs from the label's own
|
|
43
|
+
* position. A callout beside a part sets `anchor` to the label position and
|
|
44
|
+
* `leaderAnchor` to the part, so the line stays attached as the camera moves.
|
|
45
|
+
*/
|
|
46
|
+
readonly leaderAnchor?: LabelVec3 | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Screen-space offset from the projected anchor, in CSS pixels. Lets a callout
|
|
49
|
+
* sit beside its target without moving the anchor the leader line points to.
|
|
50
|
+
*/
|
|
51
|
+
readonly screenOffset?: readonly [number, number] | undefined;
|
|
52
|
+
readonly color?: string | undefined;
|
|
53
|
+
readonly background?: string | undefined;
|
|
54
|
+
/** Font size in CSS pixels at the default viewport. Scaled for compact viewports. */
|
|
55
|
+
readonly fontSize?: number | undefined;
|
|
56
|
+
readonly leader?: boolean | undefined;
|
|
57
|
+
readonly offscreenPolicy?: OffscreenPolicy | undefined;
|
|
58
|
+
/**
|
|
59
|
+
* Hide the label when its anchor is behind the camera. Defaults to true: a
|
|
60
|
+
* label for geometry behind the viewer is misleading.
|
|
61
|
+
*/
|
|
62
|
+
readonly hideWhenBehindCamera?: boolean | undefined;
|
|
63
|
+
/** Screen-anchored HUD labels ignore the projection entirely. */
|
|
64
|
+
readonly screenAnchor?: "top-left" | "top-right" | "bottom-left" | "bottom-right" | undefined;
|
|
65
|
+
}
|
|
66
|
+
export interface LabelViewport {
|
|
67
|
+
readonly width: number;
|
|
68
|
+
readonly height: number;
|
|
69
|
+
/**
|
|
70
|
+
* Device pixel ratio is deliberately not used: labels are placed in CSS pixel
|
|
71
|
+
* space so they stay legible without per-device sizing.
|
|
72
|
+
*/
|
|
73
|
+
readonly compact?: boolean | undefined;
|
|
74
|
+
}
|
|
75
|
+
export interface ProjectedLabel {
|
|
76
|
+
readonly id: string;
|
|
77
|
+
readonly text: string;
|
|
78
|
+
/** CSS-pixel position of the label box centre. */
|
|
79
|
+
readonly x: number;
|
|
80
|
+
readonly y: number;
|
|
81
|
+
/** CSS-pixel position of the leader-line endpoint (the projected anchor). */
|
|
82
|
+
readonly anchorX: number;
|
|
83
|
+
readonly anchorY: number;
|
|
84
|
+
readonly visible: boolean;
|
|
85
|
+
readonly clamped: boolean;
|
|
86
|
+
readonly behindCamera: boolean;
|
|
87
|
+
readonly fontSize: number;
|
|
88
|
+
readonly color: string;
|
|
89
|
+
readonly background: string;
|
|
90
|
+
readonly leader: boolean;
|
|
91
|
+
/** Normalized depth, 0 at the near plane. Used for draw ordering. */
|
|
92
|
+
readonly depth: number;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Project a world point through a column-major 4x4 view-projection matrix.
|
|
96
|
+
*
|
|
97
|
+
* Returns clip-space w alongside NDC so callers can detect points behind the
|
|
98
|
+
* camera (`w <= 0`) rather than silently drawing a mirrored label.
|
|
99
|
+
*/
|
|
100
|
+
export declare function projectWorldPoint(viewProjection: ArrayLike<number>, point: LabelVec3): {
|
|
101
|
+
readonly ndc: readonly [number, number, number];
|
|
102
|
+
readonly w: number;
|
|
103
|
+
};
|
|
104
|
+
/** Convert NDC to CSS-pixel screen coordinates for a viewport. */
|
|
105
|
+
export declare function ndcToScreen(ndc: readonly [number, number, number], viewport: LabelViewport): readonly [number, number];
|
|
106
|
+
/**
|
|
107
|
+
* Project a set of world labels into screen space.
|
|
108
|
+
*
|
|
109
|
+
* Pure: no DOM. This is the function tests assert on, so label placement is
|
|
110
|
+
* verified by arithmetic rather than by looking at a screenshot.
|
|
111
|
+
*/
|
|
112
|
+
export declare function projectWorldLabels(labels: readonly WorldLabel[], viewProjection: ArrayLike<number>, viewport: LabelViewport): readonly ProjectedLabel[];
|
|
113
|
+
/**
|
|
114
|
+
* Resolve overlapping labels by nudging later ones vertically.
|
|
115
|
+
*
|
|
116
|
+
* Collision avoidance is a documented option on the label API, so it must
|
|
117
|
+
* actually happen. Labels are sorted front-to-back so nearer labels keep their
|
|
118
|
+
* requested position and farther ones move.
|
|
119
|
+
*/
|
|
120
|
+
export declare function resolveLabelCollisions(labels: readonly ProjectedLabel[], options?: {
|
|
121
|
+
readonly minGap?: number | undefined;
|
|
122
|
+
}): readonly ProjectedLabel[];
|
|
123
|
+
export interface WorldLabelLayerHost {
|
|
124
|
+
/** Element the layer is appended to; normally the canvas's parent. */
|
|
125
|
+
readonly container: HTMLElement;
|
|
126
|
+
/** Canvas the labels are drawn over, used for CSS-pixel viewport size. */
|
|
127
|
+
readonly canvas: HTMLCanvasElement;
|
|
128
|
+
}
|
|
129
|
+
export interface WorldLabelLayer {
|
|
130
|
+
/** Replace the label set. */
|
|
131
|
+
setLabels(labels: readonly WorldLabel[]): void;
|
|
132
|
+
/** Reproject and redraw with the current view-projection matrix. */
|
|
133
|
+
update(viewProjection: ArrayLike<number>): void;
|
|
134
|
+
/** Most recent projection result, for evidence and tests. */
|
|
135
|
+
snapshot(): readonly ProjectedLabel[];
|
|
136
|
+
dispose(): void;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Mount the screen-space label layer.
|
|
140
|
+
*
|
|
141
|
+
* Uses `pointer-events: none` so labels never intercept scene interaction, and
|
|
142
|
+
* `aria-live="off"` with per-label `role="note"` so a screen reader can read the
|
|
143
|
+
* annotations without announcing every camera-driven reposition.
|
|
144
|
+
*/
|
|
145
|
+
export declare function createWorldLabelLayer(host: WorldLabelLayerHost): WorldLabelLayer;
|
|
146
|
+
//# sourceMappingURL=WorldLabelRenderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorldLabelRenderer.d.ts","sourceRoot":"","sources":["../../../../../packages/engine/src/agent-api/WorldLabelRenderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,MAAM,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAE1D,iEAAiE;AACjE,MAAM,MAAM,eAAe;AACzB,+BAA+B;AAC7B,MAAM;AACR,gFAAgF;GAC9E,OAAO;AACT,kEAAkE;GAChE,MAAM,CAAC;AAEX,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,8CAA8C;IAC9C,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAC9C;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IAC9D,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,qFAAqF;IACrF,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,eAAe,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC;IACvD;;;OAGG;IACH,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACpD,iEAAiE;IACjE,QAAQ,CAAC,YAAY,CAAC,EAAE,UAAU,GAAG,WAAW,GAAG,aAAa,GAAG,cAAc,GAAG,SAAS,CAAC;CAC/F;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACxC;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,kDAAkD;IAClD,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,qEAAqE;IACrE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,cAAc,EAAE,SAAS,CAAC,MAAM,CAAC,EACjC,KAAK,EAAE,SAAS,GACf;IAAE,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAWzE;AAED,kEAAkE;AAClE,wBAAgB,WAAW,CAAC,GAAG,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAE,aAAa,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAKtH;AAID;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,UAAU,EAAE,EAC7B,cAAc,EAAE,SAAS,CAAC,MAAM,CAAC,EACjC,QAAQ,EAAE,aAAa,GACtB,SAAS,cAAc,EAAE,CAoF3B;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,SAAS,cAAc,EAAE,EACjC,OAAO,GAAE;IAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAO,GACrD,SAAS,cAAc,EAAE,CAkC3B;AAED,MAAM,WAAW,mBAAmB;IAClC,sEAAsE;IACtE,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC;IAChC,0EAA0E;IAC1E,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;CACpC;AAED,MAAM,WAAW,eAAe;IAC9B,6BAA6B;IAC7B,SAAS,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,GAAG,IAAI,CAAC;IAC/C,oEAAoE;IACpE,MAAM,CAAC,cAAc,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IAChD,6DAA6D;IAC7D,QAAQ,IAAI,SAAS,cAAc,EAAE,CAAC;IACtC,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,mBAAmB,GAAG,eAAe,CA8HhF"}
|