diff --git a/scripts/smoke-cljs-blink.mjs b/scripts/smoke-cljs-blink.mjs index a826104..592f09c 100644 --- a/scripts/smoke-cljs-blink.mjs +++ b/scripts/smoke-cljs-blink.mjs @@ -394,7 +394,7 @@ const prosodicFadePlans = []; const prosodicStates = []; const prosodic = createProsodicAgency( - { fadeSteps: 3, fadeStepInterval: 40, defaultIntensity: 0.6 }, + { fadeSteps: 3, fadeStepInterval: 40, defaultIntensity: 0.6, pulsePriority: 7 }, { scheduleSnippet(snippet, opts) { prosodicScheduled.push({ snippet, opts }); @@ -456,6 +456,18 @@ if (!prosodicRemoved.includes('brow_small') || !prosodicRemoved.includes('head_s throw new Error(`Expected odd prosodic pulse to restart brow and head, removed ${prosodicRemoved.join(', ')}`); } +const oddPulseScheduled = prosodicScheduled.slice(2, 4); +if (oddPulseScheduled.length !== 2 || !oddPulseScheduled.every((entry) => entry.snippet.snippetPriority === 7)) { + throw new Error(`Expected odd prosodic pulse to use pulse priority, received ${JSON.stringify(oddPulseScheduled)}`); +} + +prosodic.pulse(2); +const browRestartCount = prosodicRemoved.filter((name) => name === 'brow_small').length; +const headRestartCount = prosodicRemoved.filter((name) => name === 'head_small').length; +if (browRestartCount !== 2 || headRestartCount !== 1 || prosodicScheduled.at(-1)?.snippet.name !== 'brow_small') { + throw new Error(`Expected even prosodic pulse to restart brow only, scheduled=${JSON.stringify(prosodicScheduled.at(-1))}, removed=${prosodicRemoved.join(', ')}`); +} + prosodic.stopTalking(); prosodicState = prosodic.getState(); if (prosodicState.browStatus !== 'stopping' || prosodicState.headStatus !== 'stopping') { @@ -471,7 +483,8 @@ if (prosodic.getState().isLooping !== false) { throw new Error('Expected prosodic stop to clear looping state'); } -if (!prosodicEvents.some((event) => event.type === 'PULSE' && event.wordIndex === 1)) { +if (!prosodicEvents.some((event) => event.type === 'PULSE' && event.wordIndex === 1 && event.channel === 'both') || + !prosodicEvents.some((event) => event.type === 'PULSE' && event.wordIndex === 2 && event.channel === 'brow')) { throw new Error(`Expected prosodic pulse event, received ${JSON.stringify(prosodicEvents)}`); } diff --git a/src-cljs/latticework/prosodic.cljs b/src-cljs/latticework/prosodic.cljs index 09b7cc7..94cf7e5 100644 --- a/src-cljs/latticework/prosodic.cljs +++ b/src-cljs/latticework/prosodic.cljs @@ -148,6 +148,18 @@ (defn- schedule-output [snippet] (protocol/emit-schedule-snippet agency-name (animation-snippet snippet) {:autoPlay true})) +(defn- pulse-schedule-output [state snippet] + (let [pulse-priority (number-or (get-in @state [:config :pulsePriority]) (:priority snippet))] + (schedule-output (assoc snippet :priority pulse-priority)))) + +(defn- pulse-channel [channels] + (let [channels (set channels)] + (cond + (= channels #{"brow" "head"}) "both" + (contains? channels "brow") "brow" + (contains? channels "head") "head" + :else "none"))) + (defn- update-state! [state update-fn] (swap! state (fn [current] @@ -201,7 +213,10 @@ head (:headSnippet current) brow-name (get-in current [:scheduledNames :brow]) head-name (get-in current [:scheduledNames :head]) - pulse-head? (odd? word-index)] + pulse-head? (odd? word-index) + channels (cond-> [] + (and brow brow-name) (conj "brow") + (and head head-name pulse-head?) (conj "head"))] (update-state! state #(-> % @@ -215,12 +230,16 @@ (cond-> [] (and brow brow-name) (conj (protocol/emit-remove-snippet agency-name brow-name) - (schedule-output (get-in @state [:browSnippet]))) + (pulse-schedule-output state (get-in @state [:browSnippet]))) (and head head-name pulse-head?) (conj (protocol/emit-remove-snippet agency-name head-name) - (schedule-output (get-in @state [:headSnippet])))) - [(event-output {:type "PULSE" :wordIndex word-index :channel "both"}) + (pulse-schedule-output state (get-in @state [:headSnippet])))) + [(event-output {:type "PULSE" + :wordIndex word-index + :channel (pulse-channel channels) + :channels channels + :priority (number-or (get-in @state [:config :pulsePriority]) (:pulsePriority default-config))}) (state-output state)])))) (defn stop-talking! [state] diff --git a/types/cljs.d.ts b/types/cljs.d.ts index 02f8960..3409cd0 100644 --- a/types/cljs.d.ts +++ b/types/cljs.d.ts @@ -401,6 +401,8 @@ export interface ProsodicEvent { snippetName?: string; wordIndex?: number; channel?: 'brow' | 'head' | 'both'; + channels?: Array<'brow' | 'head'>; + priority?: number; [key: string]: unknown; }