@lovelace_lol/polymer 0.0.1

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 (85) hide show
  1. package/README.md +226 -0
  2. package/dist/index.d.ts +2603 -0
  3. package/dist/index.js +1031 -0
  4. package/dist/test.cjs +1519 -0
  5. package/dist/worker/agency-worker.js +972 -0
  6. package/dist/worker/manifest.edn +1 -0
  7. package/package.json +57 -0
  8. package/shadow-cljs.edn +173 -0
  9. package/src/polymer/animation/agency.cljs +84 -0
  10. package/src/polymer/animation/domain.cljs +110 -0
  11. package/src/polymer/animation/planner.cljs +88 -0
  12. package/src/polymer/animation/runtime.cljs +137 -0
  13. package/src/polymer/animation/scheduler.cljs +178 -0
  14. package/src/polymer/animation/service.cljs +981 -0
  15. package/src/polymer/animation/state.cljs +112 -0
  16. package/src/polymer/blink/agency.cljs +131 -0
  17. package/src/polymer/blink/planner.cljs +115 -0
  18. package/src/polymer/blink/scheduler.cljs +90 -0
  19. package/src/polymer/blink/snippet.cljs +50 -0
  20. package/src/polymer/blink/state.cljs +102 -0
  21. package/src/polymer/camera_context/agency.cljs +132 -0
  22. package/src/polymer/camera_context/domain.cljs +186 -0
  23. package/src/polymer/camera_context/planner.cljs +50 -0
  24. package/src/polymer/camera_context/scheduler.cljs +113 -0
  25. package/src/polymer/camera_context/state.cljs +121 -0
  26. package/src/polymer/character.cljs +471 -0
  27. package/src/polymer/conversation/agency.cljs +83 -0
  28. package/src/polymer/conversation/domain.cljs +35 -0
  29. package/src/polymer/conversation/effector.cljs +130 -0
  30. package/src/polymer/conversation/planner.cljs +178 -0
  31. package/src/polymer/conversation/scheduler.cljs +202 -0
  32. package/src/polymer/conversation/service.cljs +329 -0
  33. package/src/polymer/conversation/state.cljs +186 -0
  34. package/src/polymer/core.cljs +172 -0
  35. package/src/polymer/eye_head/agency.cljs +75 -0
  36. package/src/polymer/eye_head/domain.cljs +133 -0
  37. package/src/polymer/eye_head/goap.cljs +106 -0
  38. package/src/polymer/eye_head/scheduler.cljs +176 -0
  39. package/src/polymer/eye_head/service.cljs +259 -0
  40. package/src/polymer/eye_head/snippet.cljs +92 -0
  41. package/src/polymer/eye_head/state.cljs +167 -0
  42. package/src/polymer/gaze/agency.cljs +85 -0
  43. package/src/polymer/gaze/domain.cljs +211 -0
  44. package/src/polymer/gaze/goap.cljs +208 -0
  45. package/src/polymer/gaze/scheduler.cljs +184 -0
  46. package/src/polymer/gaze/state.cljs +202 -0
  47. package/src/polymer/gesture/agency.cljs +185 -0
  48. package/src/polymer/gesture/goap.cljs +461 -0
  49. package/src/polymer/gesture/scheduler.cljs +122 -0
  50. package/src/polymer/gesture/snippet.cljs +198 -0
  51. package/src/polymer/gesture/state.cljs +273 -0
  52. package/src/polymer/lipsync/agency.cljs +593 -0
  53. package/src/polymer/lipsync/articulation/jaw.cljs +258 -0
  54. package/src/polymer/lipsync/articulation/snippet.cljs +605 -0
  55. package/src/polymer/lipsync/articulation/tongue.cljs +418 -0
  56. package/src/polymer/lipsync/articulation/visemes.cljs +429 -0
  57. package/src/polymer/lipsync/goap.cljs +132 -0
  58. package/src/polymer/lipsync/pronunciation/effector.cljs +51 -0
  59. package/src/polymer/lipsync/scheduler.cljs +302 -0
  60. package/src/polymer/lipsync/state.cljs +202 -0
  61. package/src/polymer/nlp/phonemes.cljs +164 -0
  62. package/src/polymer/prosodic/agency.cljs +196 -0
  63. package/src/polymer/prosodic/goap.cljs +122 -0
  64. package/src/polymer/prosodic/scheduler.cljs +99 -0
  65. package/src/polymer/prosodic/snippet.cljs +106 -0
  66. package/src/polymer/prosodic/state.cljs +139 -0
  67. package/src/polymer/runtime/embody.cljs +117 -0
  68. package/src/polymer/runtime/embody_wasm.cljs +177 -0
  69. package/src/polymer/runtime/rust_embody_host.cljs +645 -0
  70. package/src/polymer/society.cljs +239 -0
  71. package/src/polymer/stream.cljs +130 -0
  72. package/src/polymer/transcription/agency.cljs +69 -0
  73. package/src/polymer/transcription/domain.cljs +68 -0
  74. package/src/polymer/transcription/effector.cljs +611 -0
  75. package/src/polymer/transcription/planner.cljs +203 -0
  76. package/src/polymer/transcription/scheduler.cljs +225 -0
  77. package/src/polymer/transcription/service.cljs +209 -0
  78. package/src/polymer/transcription/state.cljs +239 -0
  79. package/src/polymer/tts/agency.cljs +503 -0
  80. package/src/polymer/tts/azure.cljs +290 -0
  81. package/src/polymer/tts/planner.cljs +178 -0
  82. package/src/polymer/tts/runtime.cljs +624 -0
  83. package/src/polymer/tts/scheduler.cljs +162 -0
  84. package/src/polymer/tts/state.cljs +191 -0
  85. package/src/polymer/worker.cljs +70 -0
@@ -0,0 +1,645 @@
1
+ (ns polymer.runtime.rust-embody-host
2
+ "Polymer-owned CLJS host for Embody's Rust/Wasm RuntimeCore.
3
+
4
+ Rust owns profile/preset intake, binding compilation, control state, and
5
+ packed frame evaluation. This namespace owns the JavaScript object exposed to
6
+ hosts and the narrow Three.js inspection/application boundary."
7
+ (:require ["@lovelace_lol/embody" :as embody]
8
+ [polymer.runtime.embody-wasm :as embody-wasm]))
9
+
10
+ (def ThreeModelInspector (aget embody "ThreeModelInspector"))
11
+ (def ThreeFrameApplier (aget embody "ThreeFrameApplier"))
12
+ (def ThreeAnimationRuntime (aget embody "ThreeAnimationRuntime"))
13
+ (def ThreeAnimationSystem (aget embody "ThreeAnimationSystem"))
14
+ (def HairPhysicsController (aget embody "HairPhysicsController"))
15
+ (def build-frame-applier-bindings (aget embody "buildFrameApplierBindings"))
16
+ (def get-mesh-names-for-au-profile (aget embody "getMeshNamesForAUProfile"))
17
+ (def get-mesh-names-for-viseme-profile (aget embody "getMeshNamesForVisemeProfile"))
18
+
19
+ (defn- js-call
20
+ [target method & args]
21
+ (let [f (when target (aget target method))]
22
+ (when-not (fn? f)
23
+ (throw (js/Error. (str "Character host is missing method: " method))))
24
+ (.apply f target (to-array args))))
25
+
26
+ (defn- js-new
27
+ [ctor & args]
28
+ (when-not ctor
29
+ (throw (js/Error. "The installed Embody package is missing a required Three.js adapter export.")))
30
+ (.construct js/Reflect ctor (to-array args)))
31
+
32
+ (defn- js-values
33
+ [value]
34
+ (if (array? value) (array-seq value) ()))
35
+
36
+ (defn- clamp01
37
+ [value]
38
+ (max 0 (min 1 (if (and (number? value) (js/isFinite value)) value 0))))
39
+
40
+ (defn- normalize-preset-id
41
+ [preset-id]
42
+ (let [normalized (when (string? preset-id) (.toLowerCase (.trim preset-id)))]
43
+ (case normalized
44
+ (nil "" "default" "human") "cc4"
45
+ normalized)))
46
+
47
+ (defn- normalize-profile-mode
48
+ [profile-mode]
49
+ (let [normalized (when (string? profile-mode)
50
+ (.toLowerCase (.trim profile-mode)))]
51
+ (case normalized
52
+ (nil "" "preset" "embedded-preset") "embedded-preset"
53
+ ("exact" "exact-profile") "exact-profile"
54
+ (throw (js/Error.
55
+ (str "Unknown Rust Embody profileMode \"" profile-mode
56
+ "\". Expected \"embedded-preset\" or \"exact-profile\"."))))))
57
+
58
+ (defn- profile-json
59
+ [profile required?]
60
+ (cond
61
+ (nil? profile)
62
+ (if required?
63
+ (throw (js/Error. "Rust Embody exact-profile mode requires a profile object."))
64
+ "")
65
+
66
+ (or (array? profile) (not= "object" (goog/typeOf profile)))
67
+ (throw (js/Error. "Rust Embody profile must be a JSON object."))
68
+
69
+ :else
70
+ (.stringify js/JSON profile)))
71
+
72
+ (defn supports-preset?
73
+ "True when the initialized Rust/Wasm registry contains the requested preset."
74
+ [preset-id]
75
+ (let [wasm (embody-wasm/get-core)]
76
+ (boolean (js-call wasm "has_preset" (normalize-preset-id preset-id)))))
77
+
78
+ (def supportsRustEmbodyPreset supports-preset?)
79
+
80
+ (defn- profile-map
81
+ [profile key]
82
+ (or (when profile (aget profile key)) #js {}))
83
+
84
+ (defn- profile-array
85
+ [profile key]
86
+ (let [value (when profile (aget profile key))]
87
+ (if (array? value) value #js [])))
88
+
89
+ (defn- resolved-meshes
90
+ [meshes mesh-by-name profile mesh-names]
91
+ (let [requested (if (and (array? mesh-names) (pos? (.-length mesh-names)))
92
+ mesh-names
93
+ (let [face (aget (profile-map profile "morphToMesh") "face")]
94
+ (if (and (array? face) (pos? (.-length face)))
95
+ face
96
+ (.map meshes (fn [mesh] (.-name mesh))))))]
97
+ (keep (fn [name] (.get mesh-by-name name)) (js-values requested))))
98
+
99
+ (defn- resolve-morph-targets
100
+ [meshes mesh-by-name profile morph-key mesh-names]
101
+ (reduce
102
+ (fn [targets mesh]
103
+ (let [dictionary (aget mesh "morphTargetDictionary")
104
+ influences (aget mesh "morphTargetInfluences")
105
+ index (cond
106
+ (number? morph-key) morph-key
107
+ dictionary (aget dictionary morph-key)
108
+ :else nil)]
109
+ (if (and influences (number? index) (<= 0 index) (< index (.-length influences)))
110
+ (conj targets #js {:infl influences :idx index})
111
+ targets)))
112
+ []
113
+ (resolved-meshes meshes mesh-by-name profile mesh-names)))
114
+
115
+ (defn- current-morph-value
116
+ [meshes mesh-by-name profile morph-key mesh-names]
117
+ (reduce
118
+ (fn [current target]
119
+ (max current (or (aget (aget target "infl") (aget target "idx")) 0)))
120
+ 0
121
+ (resolve-morph-targets meshes mesh-by-name profile morph-key mesh-names)))
122
+
123
+ (defn- mixed-au?
124
+ [profile au-id]
125
+ (let [morphs (aget (profile-map profile "auToMorphs") (str au-id))
126
+ bones (aget (profile-map profile "auToBones") (str au-id))
127
+ has-morphs (and morphs
128
+ (some #(pos? (.-length (or (aget morphs %) #js [])))
129
+ ["left" "right" "center"]))]
130
+ (boolean (and has-morphs (array? bones) (pos? (.-length bones))))))
131
+
132
+ (defn- animation-method!
133
+ [host animation-system method]
134
+ (aset host method
135
+ (fn [& args]
136
+ (apply js-call @animation-system method args))))
137
+
138
+ (def animation-methods
139
+ ["loadAnimationClips"
140
+ "getAnimationClips"
141
+ "removeAnimationClip"
142
+ "playAnimation"
143
+ "stopAnimation"
144
+ "stopAllAnimations"
145
+ "pauseAnimation"
146
+ "resumeAnimation"
147
+ "pauseAllAnimations"
148
+ "resumeAllAnimations"
149
+ "setAnimationSpeed"
150
+ "setAnimationIntensity"
151
+ "setAnimationLoopMode"
152
+ "setAnimationRepeatCount"
153
+ "setAnimationReverse"
154
+ "setAnimationBlendMode"
155
+ "seekAnimation"
156
+ "setAnimationTimeScale"
157
+ "getAnimationState"
158
+ "getPlayingAnimations"
159
+ "crossfadeTo"
160
+ "snippetToClip"
161
+ "playClip"
162
+ "playSnippet"
163
+ "typedSnippetToClip"
164
+ "playTypedSnippet"
165
+ "buildClip"
166
+ "buildTypedClip"
167
+ "updateClipParams"
168
+ "cleanupSnippet"
169
+ "supportsClipCurves"])
170
+
171
+ (defn create-rust-embody-host-unbound
172
+ "Create Polymer's synchronous CLJS host after initEmbodyCore has completed."
173
+ ([]
174
+ (create-rust-embody-host-unbound #js {}))
175
+ ([config]
176
+ (let [config (or config #js {})
177
+ wasm (embody-wasm/get-core)
178
+ profile-mode (normalize-profile-mode (aget config "profileMode"))
179
+ exact-profile? (= profile-mode "exact-profile")
180
+ preset-id (normalize-preset-id (aget config "presetType"))
181
+ _ (when (and (not exact-profile?)
182
+ (not (js-call wasm "has_preset" preset-id)))
183
+ (throw (js/Error.
184
+ (str "Rust Embody preset \"" preset-id
185
+ "\" is not embedded. Known presets: "
186
+ (.join (js-call wasm "list_presets") ", ") "."))))
187
+ profile-source-json (atom (profile-json (aget config "profile") exact-profile?))
188
+ profile (atom (if exact-profile?
189
+ (.parse js/JSON @profile-source-json)
190
+ (.parse js/JSON
191
+ (js-call wasm
192
+ "merge_embedded_preset"
193
+ preset-id
194
+ @profile-source-json))))
195
+ RuntimeCore (aget wasm "RuntimeCore")
196
+ core (js-new RuntimeCore 0)
197
+ inspector (js-new ThreeModelInspector)
198
+ applier (js-new ThreeFrameApplier)
199
+ morph-transitions (js-new ThreeAnimationRuntime)
200
+ model (atom nil)
201
+ meshes (atom #js [])
202
+ all-meshes (atom #js [])
203
+ mesh-by-name (atom (js/Map.))
204
+ bones (atom #js {})
205
+ inspection (atom nil)
206
+ animation-system (atom nil)
207
+ hair-runtime (atom nil)
208
+ viseme-values (atom #js [])
209
+ mix-weights (atom {})
210
+ running? (atom false)
211
+ raf-id (atom nil)
212
+ last-frame-ms (atom nil)
213
+ host (js-obj)]
214
+ (letfn [(apply-frame! []
215
+ (let [morph-frame (js-call core "evaluate_morph_frame_delta")
216
+ bone-frame (js-call core "evaluate_bone_frame_delta")]
217
+ (when (pos? (.-length morph-frame))
218
+ (js-call applier "applyPackedMorphFrameDelta" morph-frame))
219
+ (when (pos? (.-length bone-frame))
220
+ (js-call applier "applyPackedBoneFrameDelta" bone-frame)
221
+ (when @model
222
+ (js-call @model "updateMatrixWorld" true)))))
223
+
224
+ (bind-model! [mesh-overrides]
225
+ (when @model
226
+ (let [options (if mesh-overrides
227
+ #js {:profile @profile :meshes mesh-overrides}
228
+ #js {:profile @profile})
229
+ result (js-call inspector "inspectModel" @model options)
230
+ model-meshes (aget result "allMeshes")
231
+ runtime-meshes (let [morph-meshes (aget result "morphMeshes")]
232
+ (if (and morph-meshes (pos? (.-length morph-meshes)))
233
+ morph-meshes
234
+ model-meshes))]
235
+ (reset! inspection result)
236
+ (reset! meshes runtime-meshes)
237
+ (reset! all-meshes model-meshes)
238
+ (reset! mesh-by-name (aget result "meshByName"))
239
+ (reset! bones (aget result "bones"))
240
+ (aset host "meshes" runtime-meshes)
241
+ (aset host "meshByName" @mesh-by-name)
242
+ (aset host "bones" @bones)
243
+ (js-call applier "setBindings" (build-frame-applier-bindings result))
244
+ (js-call applier
245
+ "applyMeshMaterialConfigs"
246
+ @model
247
+ (profile-map @profile "meshes"))
248
+ (when @hair-runtime
249
+ (js-call @hair-runtime "registerHairObjects" (to-array (hair-meshes)))
250
+ (js-call @hair-runtime
251
+ "setHairPhysicsProfileConfig"
252
+ (aget @profile "hairPhysics")))
253
+ (let [descriptor-json (.stringify js/JSON (aget result "descriptor"))]
254
+ (if exact-profile?
255
+ (js-call core
256
+ "configure_exact_profile"
257
+ @profile-source-json
258
+ descriptor-json)
259
+ (js-call core
260
+ "configure_with_preset"
261
+ preset-id
262
+ @profile-source-json
263
+ descriptor-json)))
264
+ (apply-frame!))))
265
+
266
+ (set-profile! [next-profile]
267
+ (js-call core "clear")
268
+ (js-call morph-transitions "clearTransitions")
269
+ (apply-frame!)
270
+ (reset! viseme-values #js [])
271
+ (reset! mix-weights {})
272
+ (reset! profile-source-json (profile-json next-profile exact-profile?))
273
+ (reset! profile
274
+ (if exact-profile?
275
+ (.parse js/JSON @profile-source-json)
276
+ (.parse js/JSON
277
+ (js-call wasm
278
+ "merge_embedded_preset"
279
+ preset-id
280
+ @profile-source-json))))
281
+ (bind-model! @meshes))
282
+
283
+ (get-au-mix-weight [au-id]
284
+ (or (get @mix-weights au-id)
285
+ (aget (profile-map @profile "auMixDefaults") (str au-id))
286
+ 1))
287
+
288
+ (set-morph! [morph-key value mesh-names]
289
+ (let [targets (resolve-morph-targets
290
+ @meshes @mesh-by-name @profile morph-key mesh-names)
291
+ normalized (clamp01 value)]
292
+ (doseq [target targets]
293
+ (aset (aget target "infl") (aget target "idx") normalized))))
294
+
295
+ (transition-morph! [morph-key value duration-ms mesh-names]
296
+ (let [targets (resolve-morph-targets
297
+ @meshes @mesh-by-name @profile morph-key mesh-names)
298
+ from (reduce
299
+ (fn [current target]
300
+ (max current
301
+ (or (aget (aget target "infl") (aget target "idx")) 0)))
302
+ 0
303
+ targets)
304
+ target (clamp01 value)
305
+ mesh-key (if (and (array? mesh-names) (pos? (.-length mesh-names)))
306
+ (.join mesh-names ",")
307
+ "*")]
308
+ (js-call morph-transitions
309
+ "addTransition"
310
+ (str "morph:" mesh-key ":" morph-key)
311
+ from
312
+ target
313
+ (or duration-ms 120)
314
+ (fn [next-value]
315
+ (doseq [resolved targets]
316
+ (aset (aget resolved "infl")
317
+ (aget resolved "idx")
318
+ (clamp01 next-value)))))))
319
+
320
+ (update! [dt-seconds]
321
+ (let [dt (max 0 (if (and (number? dt-seconds) (js/isFinite dt-seconds))
322
+ dt-seconds
323
+ 0))]
324
+ (when (pos? dt)
325
+ (let [active-before (js-call core "active_transition_count")
326
+ active-after (js-call core "update" dt)]
327
+ (js-call morph-transitions "tick" dt)
328
+ (when (or (pos? active-before) (pos? active-after))
329
+ (apply-frame!))
330
+ (when @animation-system
331
+ (js-call @animation-system "update" dt))
332
+ (when @hair-runtime
333
+ (js-call @hair-runtime "update" dt))))))
334
+
335
+ (request-next-frame! []
336
+ (when @running?
337
+ (when-let [request-frame (aget js/globalThis "requestAnimationFrame")]
338
+ (reset! raf-id
339
+ (.call request-frame
340
+ js/globalThis
341
+ (fn [now-ms]
342
+ (let [previous @last-frame-ms
343
+ dt (if previous
344
+ (/ (max 0 (- now-ms previous)) 1000)
345
+ 0)]
346
+ (reset! last-frame-ms now-ms)
347
+ (update! dt)
348
+ (request-next-frame!))))))))
349
+
350
+ (stop! []
351
+ (reset! running? false)
352
+ (reset! last-frame-ms nil)
353
+ (when (some? @raf-id)
354
+ (when-let [cancel-frame (aget js/globalThis "cancelAnimationFrame")]
355
+ (.call cancel-frame js/globalThis @raf-id))
356
+ (reset! raf-id nil)))
357
+
358
+ (hair-meshes []
359
+ (filter
360
+ (fn [mesh]
361
+ (let [info (aget (profile-map @profile "meshes") (.-name mesh))
362
+ category (when info (aget info "category"))]
363
+ (or (= category "hair") (= category "eyebrow"))))
364
+ (js-values @all-meshes)))]
365
+ (let [animation-host
366
+ #js {:getModel (fn [] @model)
367
+ :getMeshes (fn [] @meshes)
368
+ :getMeshByName (fn [name] (.get @mesh-by-name name))
369
+ :getMeshNamesForAU
370
+ (fn [au-id] (get-mesh-names-for-au-profile @profile au-id))
371
+ :getMeshNamesForViseme
372
+ (fn [] (get-mesh-names-for-viseme-profile @profile))
373
+ :getCurrentAUValue (fn [au-id] (js-call core "get_au" au-id))
374
+ :getCurrentVisemeValue
375
+ (fn [index] (or (aget @viseme-values index) 0))
376
+ :getCurrentMorphValue
377
+ (fn [morph-key mesh-names]
378
+ (current-morph-value
379
+ @meshes @mesh-by-name @profile morph-key mesh-names))
380
+ :getCurrentMorphIndexValue
381
+ (fn [morph-index mesh-names]
382
+ (current-morph-value
383
+ @meshes @mesh-by-name @profile morph-index mesh-names))
384
+ :getCurrentBoneQuaternion
385
+ (fn [node-key]
386
+ (some-> (aget @bones node-key) (aget "obj") (aget "quaternion") (.clone)))
387
+ :getCurrentBonePositionValue
388
+ (fn [node-key axis]
389
+ (some-> (aget @bones node-key) (aget "obj") (aget "position") (aget axis)))
390
+ :getBones (fn [] @bones)
391
+ :getConfig (fn [] @profile)
392
+ :getCompositeRotations
393
+ (fn [] (profile-array @profile "compositeRotations"))
394
+ :computeSideValues
395
+ (fn [base balance]
396
+ (let [packed (embody-wasm/solve-bilateral-values base (or balance 0))]
397
+ #js {:left (aget packed 0) :right (aget packed 1)}))
398
+ :getAUMixWeight get-au-mix-weight
399
+ :isMixedAU (fn [au-id] (mixed-au? @profile au-id))
400
+ :reapplyProceduralState apply-frame!}]
401
+ (reset! animation-system (js-new ThreeAnimationSystem animation-host)))
402
+
403
+ (let [hair-host
404
+ #js {:getMeshByName (fn [name] (.get @mesh-by-name name))
405
+ :getSelectedHairMeshNames
406
+ (fn []
407
+ (to-array
408
+ (map #(aget % "name")
409
+ (filter
410
+ (fn [mesh]
411
+ (= "hair"
412
+ (some-> (aget (profile-map @profile "meshes")
413
+ (aget mesh "name"))
414
+ (aget "category"))))
415
+ (js-values @all-meshes)))))
416
+ :buildClip
417
+ (fn [clip-name curves options]
418
+ (js-call @animation-system "buildClip" clip-name curves options))
419
+ :cleanupSnippet
420
+ (fn [clip-name]
421
+ (js-call @animation-system "cleanupSnippet" clip-name))}
422
+ controller (js-new HairPhysicsController hair-host)]
423
+ (js-call controller "setCore" wasm)
424
+ (reset! hair-runtime controller))
425
+
426
+ (aset host "onReady"
427
+ (fn [options]
428
+ (reset! model (aget options "model"))
429
+ (bind-model! (aget options "meshes"))))
430
+ (aset host "bindModel" bind-model!)
431
+ (aset host "setProfile" set-profile!)
432
+ (aset host "getProfile" (fn [] @profile))
433
+ (aset host "getProfileMode" (fn [] profile-mode))
434
+ (aset host "supportsPreset" (fn [id] (supports-preset? id)))
435
+ (aset host "setAU"
436
+ (fn [id value balance]
437
+ (js-call core "set_au_signed" id value (if (number? balance) balance js/NaN))
438
+ (apply-frame!)))
439
+ (aset host "getAU" (fn [id] (js-call core "get_au" id)))
440
+ (aset host "setContinuum"
441
+ (fn [negative-au positive-au value balance]
442
+ (js-call core
443
+ "set_continuum"
444
+ negative-au
445
+ positive-au
446
+ value
447
+ (if (number? balance) balance js/NaN))
448
+ (apply-frame!)))
449
+ (aset host "getContinuum"
450
+ (fn [negative-au positive-au]
451
+ (js-call core "get_continuum" negative-au positive-au)))
452
+ (aset host "transitionAU"
453
+ (fn [id value duration-ms balance]
454
+ (js-call core
455
+ "transition_au"
456
+ id
457
+ value
458
+ (or duration-ms 200)
459
+ (if (number? balance) balance js/NaN))))
460
+ (aset host "transitionViseme"
461
+ (fn [index value duration-ms jaw-scale]
462
+ (js-call core
463
+ "transition_viseme"
464
+ index
465
+ value
466
+ (or duration-ms 80)
467
+ (or jaw-scale 1))))
468
+ (aset host "setViseme"
469
+ (fn [index value jaw-scale]
470
+ (js-call core "set_viseme" index value)
471
+ (js-call core "set_viseme_jaw_scale" index (or jaw-scale 1))
472
+ (aset @viseme-values index value)
473
+ (apply-frame!)))
474
+ (aset host "setVisemeById"
475
+ (fn [slot-id value jaw-scale]
476
+ (let [index (js-call core "viseme_slot_index" slot-id)]
477
+ (when (<= 0 index)
478
+ (js-call host "setViseme" index value (or jaw-scale 1))))))
479
+ (aset host "transitionVisemeById"
480
+ (fn [slot-id value duration-ms jaw-scale]
481
+ (let [index (js-call core "viseme_slot_index" slot-id)]
482
+ (when (<= 0 index)
483
+ (js-call host
484
+ "transitionViseme"
485
+ index
486
+ value
487
+ (or duration-ms 80)
488
+ (or jaw-scale 1))))))
489
+ (aset host "setAUMixWeight"
490
+ (fn [id weight]
491
+ (swap! mix-weights assoc id weight)
492
+ (js-call core "set_au_mix_weight" id weight)
493
+ (apply-frame!)))
494
+ (aset host "getAUMixWeight" get-au-mix-weight)
495
+ (aset host "hasLeftRightBones"
496
+ (fn [au-id]
497
+ (let [bindings (aget (profile-map @profile "auToBones") (str au-id))
498
+ sides (set (map #(aget % "side") (js-values bindings)))]
499
+ (and (contains? sides "left") (contains? sides "right")))))
500
+ (aset host "setMorph"
501
+ (fn
502
+ ([morph-key value] (set-morph! morph-key value nil))
503
+ ([morph-key value mesh-names] (set-morph! morph-key value mesh-names))))
504
+ (aset host "setMorphOnMeshes"
505
+ (fn [mesh-names morph-key value]
506
+ (set-morph! morph-key value mesh-names)))
507
+ (aset host "transitionMorph"
508
+ (fn
509
+ ([morph-key value] (transition-morph! morph-key value 120 nil))
510
+ ([morph-key value duration-ms]
511
+ (transition-morph! morph-key value duration-ms nil))
512
+ ([morph-key value duration-ms mesh-names]
513
+ (transition-morph! morph-key value duration-ms mesh-names))))
514
+ (aset host "getMorphTargets"
515
+ (fn []
516
+ (let [result (js-obj)]
517
+ (doseq [mesh (js-values @meshes)]
518
+ (when-let [dictionary (aget mesh "morphTargetDictionary")]
519
+ (aset result
520
+ (aget mesh "name")
521
+ (.sort (.keys js/Object dictionary)))))
522
+ result)))
523
+ (aset host "getMorphTargetIndices"
524
+ (fn []
525
+ (let [result (js-obj)]
526
+ (doseq [mesh (js-values @meshes)]
527
+ (when-let [dictionary (aget mesh "morphTargetDictionary")]
528
+ (let [entries (.map
529
+ (.entries js/Object dictionary)
530
+ (fn [entry]
531
+ #js {:name (aget entry 0) :index (aget entry 1)}))]
532
+ (.sort entries (fn [a b] (- (.-index a) (.-index b))))
533
+ (aset result (aget mesh "name") entries))))
534
+ result)))
535
+ (aset host "getHairMorphTargets"
536
+ (fn
537
+ ([] (js-call @hair-runtime "getHairMorphTargets"))
538
+ ([mesh-name] (js-call @hair-runtime "getHairMorphTargets" mesh-name))))
539
+ (aset host "getMeshList"
540
+ (fn []
541
+ (.map
542
+ @all-meshes
543
+ (fn [mesh]
544
+ (let [mesh-name (aget mesh "name")
545
+ info (aget (profile-map @profile "meshes") mesh-name)]
546
+ #js {:name mesh-name
547
+ :visible (aget mesh "visible")
548
+ :morphCount (.-length (or (aget mesh "morphTargetInfluences") #js []))
549
+ :category (or (when info (aget info "category")) "other")})))))
550
+ (aset host "getBones" (fn [] @bones))
551
+ (aset host "setMeshVisible"
552
+ (fn [mesh-name visible]
553
+ (when @model
554
+ (js-call applier "setMeshVisible" @model mesh-name visible))))
555
+ (aset host "highlightMesh"
556
+ (fn
557
+ ([mesh-name]
558
+ (when @model (js-call applier "highlightMesh" @model mesh-name)))
559
+ ([mesh-name color]
560
+ (when @model (js-call applier "highlightMesh" @model mesh-name color)))
561
+ ([mesh-name color intensity]
562
+ (when @model
563
+ (js-call applier "highlightMesh" @model mesh-name color intensity)))))
564
+ (aset host "getMeshMaterialConfig"
565
+ (fn [mesh-name]
566
+ (when @model
567
+ (js-call applier "getMeshMaterialConfig" @model mesh-name))))
568
+ (aset host "setMeshMaterialConfig"
569
+ (fn [mesh-name material-config]
570
+ (when @model
571
+ (js-call applier
572
+ "setMeshMaterialConfig"
573
+ @model
574
+ mesh-name
575
+ material-config))))
576
+ (doseq [method ["registerHairObjects"
577
+ "getRegisteredHairObjects"
578
+ "getHairAppearance"
579
+ "setHairColor"
580
+ "setEyebrowColor"
581
+ "setHairBaseColor"
582
+ "setEyebrowBaseColor"
583
+ "setHairGlow"
584
+ "setEyebrowGlow"
585
+ "setHairOutline"
586
+ "setHairPhysicsEnabled"
587
+ "isHairPhysicsEnabled"
588
+ "setHairPhysicsConfig"
589
+ "getHairPhysicsConfig"
590
+ "validateHairMorphTargets"
591
+ "applyHairStateToObject"]]
592
+ (aset host method
593
+ (fn [& args]
594
+ (apply js-call @hair-runtime method args))))
595
+ (aset host "updateHairPhysics"
596
+ (fn [dt-seconds]
597
+ (js-call @hair-runtime "update" dt-seconds)))
598
+ (aset host "update" update!)
599
+ (aset host "start"
600
+ (fn []
601
+ (when-not @running?
602
+ (reset! running? true)
603
+ (reset! last-frame-ms nil)
604
+ (request-next-frame!))))
605
+ (aset host "stop" stop!)
606
+ (aset host "clear"
607
+ (fn []
608
+ (js-call core "clear")
609
+ (js-call morph-transitions "clearTransitions")
610
+ (apply-frame!)))
611
+ (aset host "resetToNeutral" (aget host "clear"))
612
+ (aset host "dispose"
613
+ (fn []
614
+ (stop!)
615
+ (when @animation-system
616
+ (js-call @animation-system "dispose"))
617
+ (when @hair-runtime
618
+ (js-call @hair-runtime "clearRegisteredHairObjects"))
619
+ (when-let [free (aget core "free")]
620
+ (.call free core))
621
+ (reset! model nil)
622
+ (reset! meshes #js [])
623
+ (reset! all-meshes #js [])
624
+ (reset! mesh-by-name (js/Map.))
625
+ (reset! bones #js {})))
626
+
627
+ (doseq [method animation-methods]
628
+ (animation-method! host animation-system method))
629
+ host))))
630
+
631
+ (def createRustEmbodyHostUnbound create-rust-embody-host-unbound)
632
+
633
+ (defn create-rust-embody-host
634
+ "Create a Polymer CLJS host and bind an already-loaded Three.js model."
635
+ ([model]
636
+ (create-rust-embody-host model #js {}))
637
+ ([model config]
638
+ (-> (embody-wasm/init-core!)
639
+ (.then
640
+ (fn [_]
641
+ (let [host (create-rust-embody-host-unbound config)]
642
+ (js-call host "onReady" #js {:model model :meshes (aget config "meshes")})
643
+ host))))))
644
+
645
+ (def createRustEmbodyHost create-rust-embody-host)