@rydr/game-sdk 8.13.0 → 8.15.0

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.
Files changed (70) hide show
  1. package/dist/protocol/identity.d.ts +39 -0
  2. package/dist/protocol/identity.d.ts.map +1 -1
  3. package/dist/protocol/version.d.ts +1 -1
  4. package/dist/protocol/version.js +1 -1
  5. package/dist/three/README.md +132 -4
  6. package/dist/three/character/riders.d.ts.map +1 -1
  7. package/dist/three/character/riders.js.map +1 -1
  8. package/dist/three/controller/index.d.ts +2 -0
  9. package/dist/three/controller/index.d.ts.map +1 -1
  10. package/dist/three/controller/index.js +2 -0
  11. package/dist/three/controller/index.js.map +1 -1
  12. package/dist/three/controller/joycon-designs.d.ts +15 -1
  13. package/dist/three/controller/joycon-designs.d.ts.map +1 -1
  14. package/dist/three/controller/joycon-designs.js +302 -60
  15. package/dist/three/controller/joycon-designs.js.map +1 -1
  16. package/dist/three/controller/joycon-object.d.ts +216 -0
  17. package/dist/three/controller/joycon-object.d.ts.map +1 -0
  18. package/dist/three/controller/joycon-object.js +578 -0
  19. package/dist/three/controller/joycon-object.js.map +1 -0
  20. package/dist/three/controller/joycon-spec.d.ts +116 -4
  21. package/dist/three/controller/joycon-spec.d.ts.map +1 -1
  22. package/dist/three/controller/joycon-spec.js +128 -22
  23. package/dist/three/controller/joycon-spec.js.map +1 -1
  24. package/dist/three/controller/press-pulse.d.ts +89 -0
  25. package/dist/three/controller/press-pulse.d.ts.map +1 -0
  26. package/dist/three/controller/press-pulse.js +309 -0
  27. package/dist/three/controller/press-pulse.js.map +1 -0
  28. package/dist/three/controller/three-pad-renderer.d.ts +11 -22
  29. package/dist/three/controller/three-pad-renderer.d.ts.map +1 -1
  30. package/dist/three/controller/three-pad-renderer.js +44 -258
  31. package/dist/three/controller/three-pad-renderer.js.map +1 -1
  32. package/dist/three/rider/three-rider-rig.d.ts +12 -0
  33. package/dist/three/rider/three-rider-rig.d.ts.map +1 -1
  34. package/dist/three/rider/three-rider-rig.js +102 -9
  35. package/dist/three/rider/three-rider-rig.js.map +1 -1
  36. package/dist/ui/README.md +133 -7
  37. package/dist/ui/choice-card.d.ts +8 -0
  38. package/dist/ui/choice-card.d.ts.map +1 -1
  39. package/dist/ui/choice-card.js +1 -1
  40. package/dist/ui/choice-card.js.map +1 -1
  41. package/dist/ui/controller/controller-pad.d.ts +105 -2
  42. package/dist/ui/controller/controller-pad.d.ts.map +1 -1
  43. package/dist/ui/controller/controller-pad.js +347 -16
  44. package/dist/ui/controller/controller-pad.js.map +1 -1
  45. package/dist/ui/controller/renderer.d.ts +13 -0
  46. package/dist/ui/controller/renderer.d.ts.map +1 -1
  47. package/dist/ui/controller/renderer.js.map +1 -1
  48. package/dist/ui/controller/styles.js +50 -1
  49. package/dist/ui/controller/styles.js.map +1 -1
  50. package/dist/ui/dialogue-card.d.ts +8 -0
  51. package/dist/ui/dialogue-card.d.ts.map +1 -1
  52. package/dist/ui/dialogue-card.js +1 -1
  53. package/dist/ui/dialogue-card.js.map +1 -1
  54. package/dist/ui/hud-placement.d.ts +81 -0
  55. package/dist/ui/hud-placement.d.ts.map +1 -0
  56. package/dist/ui/hud-placement.js +74 -0
  57. package/dist/ui/hud-placement.js.map +1 -0
  58. package/dist/ui/index.d.ts +1 -0
  59. package/dist/ui/index.d.ts.map +1 -1
  60. package/dist/ui/index.js +1 -0
  61. package/dist/ui/index.js.map +1 -1
  62. package/dist/ui/rider-rig.d.ts +108 -10
  63. package/dist/ui/rider-rig.d.ts.map +1 -1
  64. package/dist/ui/rider-rig.js +299 -48
  65. package/dist/ui/rider-rig.js.map +1 -1
  66. package/dist/ui/solo-labeled-diamond.d.ts +13 -0
  67. package/dist/ui/solo-labeled-diamond.d.ts.map +1 -1
  68. package/dist/ui/solo-labeled-diamond.js +1 -1
  69. package/dist/ui/solo-labeled-diamond.js.map +1 -1
  70. package/package.json +4 -2
@@ -0,0 +1,578 @@
1
+ /**
2
+ * THE JOY-CON AS AN OBJECT — the pad's model *and everything that makes it react*, with no camera,
3
+ * no canvas and no renderer attached (PLAT-1582).
4
+ *
5
+ * ```ts
6
+ * import { createJoyconObject } from "@rydr/game-sdk/three";
7
+ *
8
+ * const pad = createJoyconObject({ view: "triggers" });
9
+ * pad.addLights(scene); // the art direction brings its own rig
10
+ * pad.group.position.set(2, 1.4, -3);
11
+ * scene.add(pad.group);
12
+ *
13
+ * pad.driver.setPartState("rt", "hint"); // "press this"
14
+ *
15
+ * // in your own loop:
16
+ * pad.step(performance.now());
17
+ * ```
18
+ *
19
+ * ## Why this exists
20
+ *
21
+ * `JOYCON_DESIGNS[i].build()` has always handed back the geometry, and that was never enough: a raw
22
+ * `THREE.Group` is a MUTE pad. Everything that makes it say something — a key lighting, sinking,
23
+ * pulsing, a stick leaning, a letter re-inking so it stays readable on a lit face, the roll that brings
24
+ * a trigger into view — lived inside `createThreePadRenderer`'s closure, welded to a canvas the game
25
+ * doesn't want. So a game placing the pad in its OWN scene (on a table, on a wall, floating beside the
26
+ * rider) got a prop it could not drive.
27
+ *
28
+ * This module is that logic, lifted out and given a door. `createThreePadRenderer` is now a thin shell
29
+ * around it: canvas, camera, framing, the render loop and `partRect`. Both paths therefore animate
30
+ * through the SAME code, which is the point — a press could not look one way in the HUD and another way
31
+ * in the world.
32
+ *
33
+ * ## What you own when you use it directly
34
+ *
35
+ * The loop. This object has no `requestAnimationFrame` of its own, because a game already has one and a
36
+ * second one would render behind it. Call {@link JoyconObject.step} once per frame with the same
37
+ * timestamp you pass everything else; it returns `true` while anything is still moving, which is all a
38
+ * dirty-guarded renderer needs. Miss the call and the pad still *paints* (colour is immediate) but
39
+ * nothing *animates* — keys teleport and pulses never fade.
40
+ *
41
+ * You also own the yaw. The object's `group` is yours to rotate, scale and place; the tilt and the
42
+ * trigger roll live on an inner pivot so they can't fight you for `rotation.x`.
43
+ */
44
+ import * as THREE from "three";
45
+ import { FAINT_PARTS, SHELL_OWNED_PARTS, STICK_LIT_DEADZONE } from "../../ui/controller/pad-svg.js";
46
+ import { JOYCON_DESIGNS } from "./joycon-designs.js";
47
+ import { PAD_VIEWS, VIEW, W } from "./joycon-spec.js";
48
+ import { glyphTexture } from "./glyph-texture.js";
49
+ import { createPressPulses, } from "./press-pulse.js";
50
+ /**
51
+ * The four things a part can say, as colours. Same grammar and same hues as the flat pad's CSS.
52
+ *
53
+ * `off` is the FALLBACK only. A resting key is painted the colour its design built it in — see
54
+ * `restColor` — because a single hard-coded rest colour repainted every design into the same blue-grey
55
+ * pad the moment a driver touched it: the art direction survived in the showcase, which builds a model
56
+ * and never paints it, and was thrown away everywhere a view actually used one. That is also why a
57
+ * black pad with white keys came out with blue-grey keys.
58
+ */
59
+ export const PAD_STATE_COLOR = {
60
+ off: 0x8ea3bd,
61
+ hint: 0xf2f6ff,
62
+ on: 0x38bdf8,
63
+ done: 0x22c55e,
64
+ };
65
+ /** Emissive strength per state — what makes a lit button read as lit rather than merely repainted. */
66
+ const STATE_EMISSIVE = { off: 0, hint: 0.5, on: 0.85, done: 0.7 };
67
+ /** Glyph ink. A lit face goes bright, so its letter has to go dark to stay readable. */
68
+ const GLYPH_INK = {
69
+ off: "#eaf2ff",
70
+ hint: "#0b0f17",
71
+ on: "#06121a",
72
+ done: "#05210f",
73
+ };
74
+ /**
75
+ * How far a pressed key sinks, ÷ shell width. A press is real travel here, not a simulated shadow.
76
+ *
77
+ * It was 0.06, and it could not be seen. Two reasons, and the depth was the lesser one: the travel runs
78
+ * along the VIEWING axis, so the reading tilt (~21°) projects barely a third of it onto the screen —
79
+ * about a quarter of a button's radius. What makes it read is the ANIMATION below, not the depth, so
80
+ * this stays modest: pushed far enough to be felt, a key visibly buries itself in the shell instead of
81
+ * being clicked.
82
+ */
83
+ const PRESS_TRAVEL = 0.07;
84
+ /**
85
+ * The hard ceiling: a key may never sink more than this fraction of how far it stands PROUD.
86
+ *
87
+ * A key is a dome whose base sits exactly on the face, so its own height is the whole budget — travel
88
+ * past it and the key disappears INTO the shell, which is not a press but a hole. The budget is not a
89
+ * constant either: the "toy" direction gives its keys 2.4× the relief of the faithful one, and the
90
+ * system keys (`−`, `+`) are nearly flush by design. So the depth is read off each key's own geometry
91
+ * and the tuned figure above is only ever an upper bound.
92
+ *
93
+ * The SHOULDER row gets a looser one. That budget is really "how much of this key can disappear before
94
+ * the shape stops making sense", and a face key answers it with its dome height, since its base is
95
+ * already flush with the face. A shoulder key is not a dome sitting on a surface — it is a key in its
96
+ * slot on the crown, with the shell continuing underneath it, so it can travel its whole depth and
97
+ * still read as a key going down. It is also the largest key on the pad and the one seen most edge-on,
98
+ * both of which eat travel on screen.
99
+ */
100
+ const MAX_SINK_OF_RISE = 0.55;
101
+ const MAX_SINK_OF_RISE_SHOULDER = 1;
102
+ /**
103
+ * How long the key takes to go down, and to come back up, ms.
104
+ *
105
+ * The OTHER reason a press could not be seen, and the bigger one: the travel used to be a single
106
+ * assignment. The key was at rest on one frame and at the bottom on the next, so there was no motion to
107
+ * watch — only two static positions, and the eye reads motion, not position. Down is fast (a key is
108
+ * driven by a finger); up is slower and overshoots slightly (it is driven by a spring).
109
+ */
110
+ const SINK_DOWN_MS = 70;
111
+ const SINK_UP_MS = 190;
112
+ /** How far past rest the key springs on release, ÷ travel. Small — it is a dome on a rubber pad. */
113
+ const SINK_OVERSHOOT = 0.16;
114
+ /** Cap tilt at full stick deflection, radians. A stick leans; it doesn't slide. */
115
+ const STICK_TILT = 0.42;
116
+ /**
117
+ * Which way each control's working surface looks, in the model's own axes.
118
+ *
119
+ * Everything on the face looks at the viewer; the shoulder row lives on the crown and looks UP. That
120
+ * one distinction is all the press pulse needs to lie flat on the right surface — see `press-pulse.ts`.
121
+ */
122
+ const SHOULDER_PARTS = new Set(["lb", "rb", "lt", "rt"]);
123
+ const facingOf = (part) => (SHOULDER_PARTS.has(part) ? "up" : "front");
124
+ /**
125
+ * Is this state a key that is actually DOWN?
126
+ *
127
+ * Two of the four are: `on` (pressed) and `done` (pressed, and it was the right thing). Which of the
128
+ * two a view uses is the view's business — `mountComboDemo` and `mountControlSpotlight` paint the
129
+ * rider's OWN presses `done`, to separate them from the presses the demo is performing — so anything
130
+ * reacting to a press must accept both, or it silently does nothing in those views. `hint` is the
131
+ * opposite case and must be excluded: it means *do this*, a key nobody has touched yet.
132
+ *
133
+ * The sink and the press pulse both go through here so they cannot drift apart.
134
+ */
135
+ const isDown = (state) => state === "on" || state === "done";
136
+ /** Opacity for a part the rider's device doesn't have. Matches `.unavailable` on the flat pad. */
137
+ const UNAVAILABLE_OPACITY = 0.22;
138
+ /**
139
+ * Build a Joy-Con that lives in your scene and reacts like the one in the HUD.
140
+ *
141
+ * For a pad framed in its own canvas — a controls screen, a HUD corner — you want
142
+ * `createThreePadRenderer` (or `mountPadHud` from `@rydr/game-sdk/ui`) instead; both are built on this.
143
+ */
144
+ export function createJoyconObject(opts = {}) {
145
+ const design = JOYCON_DESIGNS.find((d) => d.id === (opts.design ?? "toy")) ?? JOYCON_DESIGNS[1];
146
+ const model = design.build();
147
+ // Two groups: the outer one is the CALLER's (place it, scale it, yaw it), the inner one carries the
148
+ // reading tilt and the roll. Separate so neither can clobber the other's rotation.
149
+ const preset = opts.view ? PAD_VIEWS[opts.view] : undefined;
150
+ const restTilt = opts.tilt ?? preset?.tilt ?? VIEW.pitch;
151
+ const tiltGroup = new THREE.Group();
152
+ tiltGroup.rotation.x = restTilt;
153
+ tiltGroup.add(model.group);
154
+ const group = new THREE.Group();
155
+ group.rotation.y = opts.yaw ?? preset?.yaw ?? 0;
156
+ group.add(tiltGroup);
157
+ const accent = opts.accent ? new THREE.Color(opts.accent).getHex() : PAD_STATE_COLOR.on;
158
+ const hintColor = opts.hintColor ? new THREE.Color(opts.hintColor).getHex() : PAD_STATE_COLOR.hint;
159
+ /**
160
+ * The colour a state paints in.
161
+ *
162
+ * `off` is the part's OWN build colour, which is why this takes one — a single hard-coded rest
163
+ * colour repaints every art direction into the same pad the moment a driver touches it.
164
+ */
165
+ const colorFor = (state, rest) => state === "on" ? accent : state === "hint" ? hintColor : state === "off" ? rest : PAD_STATE_COLOR[state];
166
+ /** Every part this model actually draws. */
167
+ const ALL_PARTS = [...model.controls.keys()];
168
+ const changeCbs = new Set();
169
+ const poseCbs = new Set();
170
+ /** Set whenever something changed; a dirty-guarded renderer reads it through `step`. */
171
+ let dirty = true;
172
+ function markDirty() {
173
+ dirty = true;
174
+ for (const cb of changeCbs)
175
+ cb();
176
+ }
177
+ /** Each part's as-built colour, captured once. A part at rest wears this, not a shared grey. */
178
+ const restColor = new Map();
179
+ /** Resting position per part along its own axis, captured once so a press is absolute, not cumulative. */
180
+ const restPos = new Map();
181
+ /**
182
+ * The mesh and material behind a part.
183
+ *
184
+ * `JoyconBuild` keys its controls by name and hands back plain `Object3D`s, so this resolves one to
185
+ * something paintable. A stick's entry is its cap mesh, which is what should light and sink.
186
+ */
187
+ function visualOf(part) {
188
+ const node = model.controls.get(part);
189
+ if (!node)
190
+ return undefined;
191
+ const mesh = node;
192
+ const mat = mesh.material;
193
+ if (!mat || !("color" in mat))
194
+ return undefined;
195
+ // A key sinks along its OWN normal, not along z. Everything on the face looks at the viewer, but
196
+ // the shoulder row sits on the CROWN and looks up: pushing those along z slid them backwards into
197
+ // the shell, which — once the pad rolls forward to show them — read as the key RISING.
198
+ const axis = facingOf(part) === "up" ? "y" : "z";
199
+ let rest = restPos.get(part);
200
+ if (rest === undefined) {
201
+ rest = node.position[axis];
202
+ restPos.set(part, rest);
203
+ }
204
+ // Captured on the first look, before anything has repainted it — exactly like `restPos` above, and
205
+ // for the same reason: read it later and you get whatever state the part was last painted in.
206
+ let base = restColor.get(part);
207
+ if (base === undefined) {
208
+ base = mat.color.getHex();
209
+ restColor.set(part, base);
210
+ }
211
+ return { node, material: mat, axis, rest, sink: sinkDepthOf(mesh, axis), restColor: base };
212
+ }
213
+ /** How far THIS key may travel: the tuned depth, capped by the key's own height above the face. */
214
+ function sinkDepthOf(mesh, axis) {
215
+ const geo = mesh.geometry;
216
+ if (!geo)
217
+ return travel;
218
+ if (!geo.boundingBox)
219
+ geo.computeBoundingBox();
220
+ const b = geo.boundingBox;
221
+ if (!b)
222
+ return travel;
223
+ // `axis` doubles as "is this a shoulder key": it is the only row that travels downwards.
224
+ const proud = axis === "y" ? b.max.y - b.min.y : b.max.z - b.min.z;
225
+ const budget = axis === "y" ? MAX_SINK_OF_RISE_SHOULDER : MAX_SINK_OF_RISE;
226
+ return Math.min(travel, proud * budget);
227
+ }
228
+ // ── the sink ────────────────────────────────────────────────────────────────────────────────────
229
+ //
230
+ // A key going down, ANIMATED. It used to be one assignment, which is why nobody could see it: there
231
+ // is no motion in a teleport. Each key runs its own little tween, driven by `step`.
232
+ const travel = W * (opts.pressTravel ?? PRESS_TRAVEL);
233
+ const sinks = new Map();
234
+ /** Where each key is along its travel right now, so a re-press starts from where it actually is. */
235
+ const depths = new Map();
236
+ /** Send a key down (`to` 1) or let it back up (`to` 0). */
237
+ function aimSink(part, node, axis, rest, dist, to) {
238
+ const from = depths.get(part) ?? 0;
239
+ if (from === to && !sinks.has(part))
240
+ return;
241
+ sinks.set(part, {
242
+ node,
243
+ axis,
244
+ rest,
245
+ dist,
246
+ from,
247
+ to,
248
+ start: performance.now(),
249
+ // Interrupting a tween shortens the next one in proportion, so a key tapped twice quickly does
250
+ // not feel like it is wading through syrup on the second press.
251
+ dur: (to > from ? SINK_DOWN_MS : SINK_UP_MS) * Math.max(0.35, Math.abs(to - from)),
252
+ });
253
+ }
254
+ /** Advance every key in motion. Returns true while any is still moving. */
255
+ function stepSinks(now) {
256
+ if (sinks.size === 0)
257
+ return false;
258
+ for (const [part, s] of sinks) {
259
+ const t = Math.min(1, (now - s.start) / s.dur);
260
+ let e;
261
+ if (s.to > s.from) {
262
+ // Down: ease-out. The finger has already committed; the key just catches up.
263
+ e = 1 - Math.pow(1 - t, 3);
264
+ }
265
+ else {
266
+ // Up: ease-out BACK — it springs past rest and settles. That little rebound is most of what
267
+ // sells the key as a physical thing rather than a sprite being moved.
268
+ const c = SINK_OVERSHOOT * 2.6;
269
+ e = 1 + (c + 1) * Math.pow(t - 1, 3) + c * Math.pow(t - 1, 2);
270
+ }
271
+ const depth = s.from + (s.to - s.from) * e;
272
+ depths.set(part, t >= 1 ? s.to : depth);
273
+ s.node.position[s.axis] = s.rest - depth * s.dist;
274
+ if (t >= 1) {
275
+ s.node.position[s.axis] = s.rest - s.to * s.dist;
276
+ sinks.delete(part);
277
+ }
278
+ }
279
+ dirty = true;
280
+ return sinks.size > 0;
281
+ }
282
+ /**
283
+ * The press pulse. Parented to the MODEL group, so a pulse inherits the tilt, the yaw and the roll a
284
+ * lit trigger provokes — it stays stuck to its key without a line of code following it.
285
+ */
286
+ const pulses = createPressPulses({
287
+ parent: model.group,
288
+ style: opts.pressPulse ?? "wave",
289
+ hold: opts.pressHold ?? "echo",
290
+ ms: opts.pressPulseMs ?? 500,
291
+ scale: opts.pressPulseScale ?? 1.4,
292
+ unit: W,
293
+ });
294
+ // ── state ───────────────────────────────────────────────────────────────────────────────────────
295
+ /** Dirty-guard, same intent as the flat driver's: an idle pad must do no work per frame. */
296
+ const lastVal = new Map();
297
+ const STATE_CODE = { off: 0, on: 1, hint: 2, done: 3 };
298
+ let unavailable = new Set();
299
+ let referenced = new Set();
300
+ function applyOpacity(part) {
301
+ const v = visualOf(part);
302
+ if (!v)
303
+ return;
304
+ const dim = unavailable.has(part);
305
+ // `referenced` only ever RAISES a faint part back to full, exactly as the flat pad's rule does.
306
+ const faint = FAINT_PARTS.has(part) && !referenced.has(part);
307
+ const o = dim ? UNAVAILABLE_OPACITY : faint ? 0.4 : 1;
308
+ v.material.transparent = o < 1;
309
+ v.material.opacity = o;
310
+ }
311
+ function paint(part, state) {
312
+ const v = visualOf(part);
313
+ if (!v)
314
+ return;
315
+ const color = colorFor(state, v.restColor);
316
+ v.material.color.setHex(color);
317
+ // Emissive stays the thing that separates a lit key from a resting one. It has to: a design whose
318
+ // keys are already near-white ("toy", "noir") cannot say "lit" by going white — but it can glow.
319
+ v.material.emissive.setHex(state === "off" ? 0x000000 : color);
320
+ v.material.emissiveIntensity = STATE_EMISSIVE[state];
321
+ // A press is real travel here — the flat pad had to fake it with a drop shadow. Animated, because
322
+ // an instant displacement is not something an eye can catch: see `aimSink`.
323
+ aimSink(part, v.node, v.axis, v.rest, v.sink, isDown(state) ? 1 : 0);
324
+ inkGlyph(part, state);
325
+ applyOpacity(part);
326
+ markDirty();
327
+ }
328
+ /**
329
+ * The lettering plane printed on a key, if it has one.
330
+ *
331
+ * The model parents a key's glyph TO the key (so it rides it down when pressed), which is also what
332
+ * makes it findable from here: the label is the control's only child carrying a texture.
333
+ */
334
+ function labelOf(part) {
335
+ const node = model.controls.get(part);
336
+ if (!node)
337
+ return undefined;
338
+ for (const child of node.children) {
339
+ const mesh = child;
340
+ const mat = mesh.material;
341
+ if (mat && "map" in mat && mat.map)
342
+ return mesh;
343
+ }
344
+ return undefined;
345
+ }
346
+ /**
347
+ * Each label's ink AS THE DESIGN DREW IT, captured before anything repaints it.
348
+ *
349
+ * Restoring `off` from {@link GLYPH_INK} would be wrong: the ink belongs to the art direction, and
350
+ * the "toy" design letters its near-white keys in near-BLACK. Handing every design the same resting
351
+ * ink would erase that one's lettering entirely.
352
+ */
353
+ const labelRest = new Map();
354
+ /**
355
+ * Re-ink a key's lettering for the state it is now in.
356
+ *
357
+ * A lit key goes bright — the accent blue, at emissive strength — and pale lettering on it turns to
358
+ * mush. So the letter flips to near-black for as long as the key is lit, and back to the design's own
359
+ * ink when it goes out. Textures are cached by `text|colour`, so this is a map swap, not a redraw.
360
+ */
361
+ function inkGlyph(part, state) {
362
+ const label = labelOf(part);
363
+ if (!label)
364
+ return;
365
+ const mat = label.material;
366
+ if (!labelRest.has(part))
367
+ labelRest.set(part, mat.map);
368
+ const text = glyphTexts.get(part) ?? "";
369
+ if (!text)
370
+ return;
371
+ mat.map = state === "off" ? (labelRest.get(part) ?? null) : glyphTexture(text, GLYPH_INK[state]);
372
+ mat.needsUpdate = true;
373
+ }
374
+ /** What's printed on a part — read back off the layout so it can be re-inked per state. */
375
+ const glyphTexts = new Map();
376
+ const layout = opts.layout;
377
+ if (layout) {
378
+ for (const [name, spec] of [
379
+ ["faceTop", layout.face.top],
380
+ ["faceRight", layout.face.right],
381
+ ["faceBottom", layout.face.bottom],
382
+ ["faceLeft", layout.face.left],
383
+ ["select", layout.system?.select],
384
+ ["start", layout.system?.start],
385
+ ["lb", layout.bumpers?.l],
386
+ ["rb", layout.bumpers?.r],
387
+ ["lt", layout.triggers?.l],
388
+ ["rt", layout.triggers?.r],
389
+ ]) {
390
+ if (spec?.glyph)
391
+ glyphTexts.set(name, spec.glyph);
392
+ }
393
+ }
394
+ // ── the trigger roll ────────────────────────────────────────────────────────────────────────────
395
+ /** Which triggers are currently lit. The pad rolls while this is non-empty. */
396
+ const litTriggers = new Set();
397
+ const extraTilt = opts.triggerTilt ?? 0.38;
398
+ const rollMs = opts.triggerTiltMs ?? 420;
399
+ /** 0 = at rest, 1 = fully rolled forward. */
400
+ let roll = 0;
401
+ let rollFrom = 0;
402
+ let rollTarget = 0;
403
+ let rollStart = 0;
404
+ function aimRoll() {
405
+ const want = litTriggers.size > 0 ? 1 : 0;
406
+ if (want === rollTarget)
407
+ return;
408
+ rollFrom = roll;
409
+ rollTarget = want;
410
+ rollStart = performance.now();
411
+ }
412
+ /** Advance the roll. Returns true while it is still moving. */
413
+ function stepRoll(now) {
414
+ if (roll === rollTarget)
415
+ return false;
416
+ const t = Math.min(1, (now - rollStart) / rollMs);
417
+ // Ease in-out: the pad should settle rather than snap, or the labels riding on it jitter.
418
+ const e = t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2;
419
+ roll = rollFrom + (rollTarget - rollFrom) * e;
420
+ if (t >= 1)
421
+ roll = rollTarget;
422
+ tiltGroup.rotation.x = restTilt + extraTilt * roll;
423
+ dirty = true;
424
+ // Anything positioned from a projection has to follow, so tell it every frame of the roll.
425
+ for (const cb of poseCbs)
426
+ cb();
427
+ return roll !== rollTarget;
428
+ }
429
+ // ── the driver ──────────────────────────────────────────────────────────────────────────────────
430
+ const setPartState = (part, state) => {
431
+ if (SHELL_OWNED_PARTS.has(part) && !opts.allowShellOwned)
432
+ return;
433
+ const prev = lastVal.get(part);
434
+ if (prev === STATE_CODE[state])
435
+ return;
436
+ lastVal.set(part, STATE_CODE[state]);
437
+ paint(part, state);
438
+ // Mark the press itself — but only on the EDGE into a pressed state. The guard above already
439
+ // swallows a held key's repeats, so this fires once per press, which is what makes it an event.
440
+ const down = isDown(state);
441
+ const wasDown = prev !== undefined && (prev === STATE_CODE.on || prev === STATE_CODE.done);
442
+ if (down && !wasDown) {
443
+ const node = model.controls.get(part);
444
+ if (node)
445
+ pulses.fire(part, node, facingOf(part));
446
+ }
447
+ else if (!down) {
448
+ pulses.release(part);
449
+ }
450
+ // A lit trigger rolls the pad forward so it can actually be seen — see `triggerTilt`.
451
+ if (part === "lt" || part === "rt") {
452
+ if (state === "off")
453
+ litTriggers.delete(part);
454
+ else
455
+ litTriggers.add(part);
456
+ aimRoll();
457
+ }
458
+ };
459
+ const setStick = (side, x, y, lit = "auto") => {
460
+ const pivot = model.sticks[side];
461
+ if (!pivot)
462
+ return;
463
+ const litKey = `${side}lit`;
464
+ const resolved = lit === "auto" ? (Math.hypot(x, y) > STICK_LIT_DEADZONE ? "on" : "off") : lit;
465
+ const code = resolved === "on" ? 1 : resolved === "hint" ? 2 : resolved === "done" ? 3 : 0;
466
+ if (lastVal.get(litKey) !== code) {
467
+ lastVal.set(litKey, code);
468
+ // Colour lives on the CAP, which is registered as the stick-click part.
469
+ const cap = visualOf(side === "l" ? "lstickPress" : "rstickPress");
470
+ if (cap) {
471
+ const state = resolved;
472
+ const color = colorFor(state, cap.restColor);
473
+ cap.material.color.setHex(color);
474
+ cap.material.emissive.setHex(state === "off" ? 0x000000 : color);
475
+ cap.material.emissiveIntensity = STATE_EMISSIVE[state];
476
+ }
477
+ markDirty();
478
+ }
479
+ // A real stick LEANS. `y` is up-positive in the SDK's convention, and a push "up" tips the cap away
480
+ // from the viewer — a negative rotation about x — so the sign works out without the flat
481
+ // renderer's y-negation.
482
+ const rx = -y * STICK_TILT;
483
+ const ry = x * STICK_TILT;
484
+ if (Math.abs(rx - (lastVal.get(`${side}rx`) ?? 0)) < 0.002 &&
485
+ Math.abs(ry - (lastVal.get(`${side}ry`) ?? 0)) < 0.002) {
486
+ return;
487
+ }
488
+ lastVal.set(`${side}rx`, rx);
489
+ lastVal.set(`${side}ry`, ry);
490
+ pivot.rotation.x = rx;
491
+ pivot.rotation.y = ry;
492
+ markDirty();
493
+ };
494
+ const driver = {
495
+ setPartState,
496
+ setPart: (part, on) => setPartState(part, on ? "on" : "off"),
497
+ setStick,
498
+ setMeter(side, v01) {
499
+ // The generated model draws no travel meter: in this protocol LT/RT are plain clicks (see
500
+ // `protocol/buttons.ts`), so the trigger simply lights, which `setPart` already does.
501
+ void side;
502
+ void v01;
503
+ },
504
+ setAvailable(available) {
505
+ unavailable = available == null
506
+ ? new Set()
507
+ : new Set(ALL_PARTS.filter((p) => !available.includes(p) && !SHELL_OWNED_PARTS.has(p)));
508
+ for (const part of ALL_PARTS)
509
+ applyOpacity(part);
510
+ markDirty();
511
+ },
512
+ clearAll() {
513
+ for (const part of ALL_PARTS) {
514
+ lastVal.set(part, 0);
515
+ paint(part, "off");
516
+ }
517
+ litTriggers.clear();
518
+ aimRoll();
519
+ pulses.cancelAll();
520
+ for (const side of ["l", "r"]) {
521
+ lastVal.delete(`${side}lit`);
522
+ setStick(side, 0, 0, "off");
523
+ this.setMeter(side, 0);
524
+ }
525
+ },
526
+ };
527
+ // Paint every part once so a part's material starts in a known state rather than its build colour.
528
+ for (const part of ALL_PARTS)
529
+ paint(part, "off");
530
+ return {
531
+ group,
532
+ tiltGroup,
533
+ model,
534
+ driver,
535
+ parts: ALL_PARTS,
536
+ nodeOf: (part) => model.controls.get(part),
537
+ addLights(target) {
538
+ // `JoyconDesign.light` is typed on `THREE.Scene` because that is where it has always been called;
539
+ // it only ever calls `.add`, which every `Object3D` has. Widening the parameter here lets a game
540
+ // hang the rig off its own group instead of polluting the root scene.
541
+ design.light(target);
542
+ },
543
+ step(now) {
544
+ const rolling = stepRoll(now);
545
+ // A live pulse is the one thing that has to redraw without anything having "changed". It marks
546
+ // the frame dirty only while it is actually animating, so an untouched pad still costs nothing.
547
+ if (pulses.step(now))
548
+ dirty = true;
549
+ const sinking = stepSinks(now);
550
+ const was = dirty;
551
+ dirty = false;
552
+ return was || rolling || sinking;
553
+ },
554
+ onChange(cb) {
555
+ changeCbs.add(cb);
556
+ return () => changeCbs.delete(cb);
557
+ },
558
+ onPoseChange(cb) {
559
+ poseCbs.add(cb);
560
+ return () => poseCbs.delete(cb);
561
+ },
562
+ setReferenced(parts) {
563
+ referenced = parts;
564
+ for (const part of ALL_PARTS)
565
+ applyOpacity(part);
566
+ markDirty();
567
+ },
568
+ dispose() {
569
+ pulses.dispose();
570
+ for (const d of model.disposables)
571
+ d.dispose();
572
+ group.removeFromParent();
573
+ changeCbs.clear();
574
+ poseCbs.clear();
575
+ },
576
+ };
577
+ }
578
+ //# sourceMappingURL=joycon-object.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"joycon-object.js","sourceRoot":"","sources":["../../../src/three/controller/joycon-object.ts"],"names":[],"mappings":"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"}