@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,258 @@
1
+ (ns polymer.lipsync.articulation.jaw
2
+ (:require [clojure.string :as str]
3
+ [polymer.lipsync.state :as state]
4
+ [polymer.lipsync.articulation.visemes :as visemes]))
5
+
6
+ ;; The jaw planner is deliberately separate from lip/viseme curve assembly.
7
+ ;; JALI-style lip sync treats mouth shape and jaw drop as related but distinct
8
+ ;; control axes: a bilabial can close the lips without opening AU26, and a vowel
9
+ ;; nucleus can keep the jaw open while the lips travel through a diphthong.
10
+ ;;
11
+ ;; Inputs are normalized viseme timeline events. Outputs are jaw-activation
12
+ ;; keyframes; snippet assembly later routes those keyframes to the JAW bone so
13
+ ;; the CC4 Jaw_Open morph does not cover the independent viseme shapes. There are
14
+ ;; no host side effects here: no audio, DOM, scheduler, engine handle, UI state,
15
+ ;; or provider credential access.
16
+
17
+ (def intensity-eps 0.001)
18
+ (def jaw-long-gap-ms 90)
19
+ (def jaw-group-gap-ms 65)
20
+ (def jaw-transition-lead-ms 24)
21
+ (def jaw-vowel-attack-ms 42)
22
+ (def jaw-vowel-release-ms 45)
23
+ (def jaw-consonant-attack-ms 18)
24
+ (def jaw-consonant-release-ms 28)
25
+ (def jaw-bridge-ratio 0.55)
26
+
27
+ (defn finite-number? [value]
28
+ (and (number? value) (js/isFinite value)))
29
+
30
+ (defn class-name [value]
31
+ (cond
32
+ (keyword? value) (name value)
33
+ (string? value) (str/lower-case value)
34
+ (nil? value) nil
35
+ :else (str/lower-case (str value))))
36
+
37
+ (defn event-classes [event]
38
+ ;; Provider timelines can be lossy, so the event may carry both a primary
39
+ ;; phoneme class and a full class set. If either is absent, fall back to the
40
+ ;; canonical viseme slot class so planner rules still behave conservatively.
41
+ (let [from-event (into []
42
+ (keep class-name)
43
+ (concat (or (:phonemeClasses event) [])
44
+ [(:phonemeClass event)]))
45
+ fallback (into [] (keep class-name) (visemes/viseme-classes (:visemeId event)))]
46
+ (set (if (seq from-event) from-event fallback))))
47
+
48
+ (defn has-class? [event class]
49
+ (contains? (event-classes event) class))
50
+
51
+ (defn raw-target [event]
52
+ (state/clamp 0 2
53
+ (state/number-or (:jawActivation event)
54
+ (visemes/jaw-activation-for-viseme (:visemeId event)))))
55
+
56
+ (defn start-ms [event]
57
+ (state/number-or (:offsetMs event) 0))
58
+
59
+ (defn end-ms [event]
60
+ (+ (start-ms event) (max 1 (state/number-or (:durationMs event) 1))))
61
+
62
+ (defn pause-event? [event]
63
+ (or (has-class? event "pause")
64
+ (str/starts-with? (or (:phoneme event) "") "PAUSE_")))
65
+
66
+ (defn bilabial? [event]
67
+ (has-class? event "bilabial"))
68
+
69
+ (defn narrow-fricative? [event]
70
+ (or (has-class? event "sibilant")
71
+ (has-class? event "labiodental")
72
+ (has-class? event "dental")
73
+ (has-class? event "fricative")))
74
+
75
+ (defn tongue-consonant? [event]
76
+ (or (has-class? event "tongue")
77
+ (has-class? event "obstruent")
78
+ (has-class? event "nasal")
79
+ (has-class? event "liquid")))
80
+
81
+ (defn vocalic-jaw-event? [event]
82
+ ;; Diphthong expansion marks the secondary lip target with "diphthong".
83
+ ;; Azure W/UW events often arrive only as the W_OO viseme; treat those as
84
+ ;; vocalic only when their jaw target is the rounded vowel/glide amount, not
85
+ ;; when fallback text generated a low consonantal W.
86
+ (or (has-class? event "vowel")
87
+ (has-class? event "diphthong")
88
+ (and (= (:visemeId event) (:W_OO visemes/canonical-visemes))
89
+ (>= (raw-target event) 0.28))))
90
+
91
+ (defn event-kind [event]
92
+ (cond
93
+ (pause-event? event) :pause
94
+ (vocalic-jaw-event? event) :vocalic
95
+ :else :consonant))
96
+
97
+ (defn consonant-target [events]
98
+ ;; Consonants should not make the jaw flap. Closures and narrow consonants are
99
+ ;; mostly lip/tongue business, so the jaw stays low and stable across the
100
+ ;; whole consonant cluster.
101
+ (let [events (vec events)
102
+ raw-max (apply max 0 (map raw-target events))]
103
+ (cond
104
+ (every? bilabial? events) 0
105
+ (some bilabial? events) (min raw-max 0.08)
106
+ (every? narrow-fricative? events) (min raw-max 0.08)
107
+ (some narrow-fricative? events) (min raw-max 0.10)
108
+ (every? tongue-consonant? events) (min raw-max 0.14)
109
+ :else (min raw-max 0.16))))
110
+
111
+ (defn group-target [kind events]
112
+ (case kind
113
+ :pause 0
114
+ :vocalic (apply max 0 (map raw-target events))
115
+ :consonant (consonant-target events)))
116
+
117
+ (defn same-jaw-group? [current next-event]
118
+ (let [kind (event-kind current)
119
+ next-kind (event-kind next-event)
120
+ gap (- (start-ms next-event) (end-ms current))]
121
+ (and (= kind next-kind)
122
+ (<= gap jaw-group-gap-ms)
123
+ (>= gap (- jaw-group-gap-ms)))))
124
+
125
+ (defn raw-groups [events]
126
+ (let [ordered (vec (sort-by :offsetMs events))]
127
+ (loop [remaining ordered
128
+ current []
129
+ groups []]
130
+ (cond
131
+ (empty? remaining)
132
+ (if (seq current) (conj groups current) groups)
133
+
134
+ (empty? current)
135
+ (recur (rest remaining) [(first remaining)] groups)
136
+
137
+ (same-jaw-group? (last current) (first remaining))
138
+ (recur (rest remaining) (conj current (first remaining)) groups)
139
+
140
+ :else
141
+ (recur (rest remaining) [(first remaining)] (conj groups current))))))
142
+
143
+ (defn make-group [events]
144
+ (let [kind (event-kind (first events))
145
+ start (apply min (map start-ms events))
146
+ end (apply max (map end-ms events))]
147
+ {:kind kind
148
+ :startMs start
149
+ :endMs end
150
+ :durationMs (max 1 (- end start))
151
+ :target (group-target kind events)
152
+ :events (vec events)}))
153
+
154
+ (defn closure-group? [group]
155
+ (some bilabial? (:events group)))
156
+
157
+ (defn bridgeable-consonant-group? [group previous next-group]
158
+ ;; A short tongue-only consonant between two vowels should not close the jaw
159
+ ;; and reopen it as a separate visual beat. Bilabials and narrow fricatives are
160
+ ;; excluded because they need visible closure/narrowing.
161
+ (and (= :consonant (:kind group))
162
+ (= :vocalic (:kind previous))
163
+ (= :vocalic (:kind next-group))
164
+ (<= (:durationMs group) 90)
165
+ (not (closure-group? group))
166
+ (not-any? narrow-fricative? (:events group))))
167
+
168
+ (defn contextualize-group [groups index group]
169
+ (let [previous (get groups (dec index))
170
+ next-group (get groups (inc index))]
171
+ (if (bridgeable-consonant-group? group previous next-group)
172
+ (let [bridge-target (* jaw-bridge-ratio (min (:target previous) (:target next-group)))]
173
+ (update group :target #(max % bridge-target)))
174
+ group)))
175
+
176
+ (defn jaw-groups [events]
177
+ (let [groups (mapv make-group (raw-groups events))]
178
+ (mapv #(contextualize-group groups %1 %2) (range) groups)))
179
+
180
+ (defn push-frame [curve time-sec intensity]
181
+ (if (or (not (finite-number? time-sec))
182
+ (not (finite-number? intensity)))
183
+ curve
184
+ (let [frame {:time (max 0 time-sec)
185
+ :intensity (state/clamp 0 2 intensity)}
186
+ previous (last curve)]
187
+ (if (and previous (< (js/Math.abs (- (:time previous) (:time frame))) 0.001))
188
+ (assoc-in curve [(dec (count curve)) :intensity] (:intensity frame))
189
+ (conj curve frame)))))
190
+
191
+ (defn deduplicate-curve [curve]
192
+ (let [frames (vec curve)]
193
+ (if (<= (count frames) 1)
194
+ frames
195
+ (loop [remaining (rest frames)
196
+ result [(first frames)]]
197
+ (if (empty? remaining)
198
+ (vec result)
199
+ (let [curr (first remaining)
200
+ prev (last result)
201
+ intensity-changed? (> (js/Math.abs (- (:intensity curr) (:intensity prev))) intensity-eps)
202
+ time-changed? (> (js/Math.abs (- (:time curr) (:time prev))) 0.001)]
203
+ (recur (rest remaining)
204
+ (if (or intensity-changed? time-changed?)
205
+ (conj result curr)
206
+ result))))))))
207
+
208
+ (defn group-attack-sec [group]
209
+ (/ (min (if (= :vocalic (:kind group)) jaw-vowel-attack-ms jaw-consonant-attack-ms)
210
+ (max 6 (* (:durationMs group) 0.35)))
211
+ 1000))
212
+
213
+ (defn group-release-sec [group]
214
+ (/ (min (if (= :vocalic (:kind group)) jaw-vowel-release-ms jaw-consonant-release-ms)
215
+ (max 10 (* (:durationMs group)
216
+ (if (= :vocalic (:kind group)) 0.22 0.45))))
217
+ 1000))
218
+
219
+ (defn connected-to-next? [group next-group]
220
+ (and next-group
221
+ (<= (- (:startMs next-group) (:endMs group)) jaw-long-gap-ms)))
222
+
223
+ (defn build-jaw-curve [events jaw-scale]
224
+ (let [scale (state/clamp 0 2 (state/number-or jaw-scale 1))
225
+ groups (jaw-groups events)
226
+ has-jaw? (some #(> (* scale (:target %)) intensity-eps) groups)]
227
+ (if-not has-jaw?
228
+ []
229
+ (loop [index 0
230
+ curve []]
231
+ (if (>= index (count groups))
232
+ (->> curve (sort-by :time) deduplicate-curve vec)
233
+ (let [group (get groups index)
234
+ previous (get groups (dec index))
235
+ next-group (get groups (inc index))
236
+ start-sec (/ (:startMs group) 1000)
237
+ end-sec (/ (:endMs group) 1000)
238
+ target (* scale (:target group))
239
+ attack-sec (group-attack-sec group)
240
+ release-sec (group-release-sec group)
241
+ previous-end-sec (if previous (/ (:endMs previous) 1000) 0)
242
+ starts-after-gap? (or (nil? previous)
243
+ (> (- start-sec previous-end-sec) (/ jaw-long-gap-ms 1000)))
244
+ curve-a (if starts-after-gap? (push-frame curve start-sec 0) curve)
245
+ peak-time (if (> target intensity-eps)
246
+ (+ start-sec attack-sec)
247
+ start-sec)
248
+ curve-b (push-frame curve-a peak-time target)
249
+ connected? (connected-to-next? group next-group)]
250
+ (recur (inc index)
251
+ (if connected?
252
+ (let [next-start-sec (/ (:startMs next-group) 1000)
253
+ transition-time (max peak-time
254
+ (- next-start-sec (/ jaw-transition-lead-ms 1000)))]
255
+ (push-frame curve-b transition-time target))
256
+ (-> curve-b
257
+ (push-frame (max peak-time (- end-sec release-sec)) target)
258
+ (push-frame end-sec 0))))))))))