Forráskód Böngészése

fix(avatar): 可选的工作表情不再套上等待彩带

Samien 1 hónapja
szülő
commit
fd317fb

+ 2 - 1
src/client/components/common/AgentAvatar.vue

@@ -21,7 +21,8 @@ const runtimeActive = computed(() => props.state !== 'idle' && !beatEnded.value)
 const state = computed<CursorState>(() => runtimeActive.value ? states[props.state] : oneShot.value ?? identity.value.expression)
 const live = computed(() => visible.value && foreground.value && !reduced.value && props.animated !== false && (props.animated === true || props.size >= 56 || runtimeActive.value || !!oneShot.value || hover.value))
 const options = computed(() => ({ state: state.value, paused: !live.value, color: identity.value.color, gaze: gaze.value,
-  silhouette: identity.value.bodyId ? LAOA_BODIES[identity.value.bodyId] : MASCOT_SILHOUETTES[identity.value.shape === 'ellipse' ? 'oval' : identity.value.shape], fixedTime: props.fixedTime, expression: props.expressionIndex }))
+  silhouette: identity.value.bodyId ? LAOA_BODIES[identity.value.bodyId] : MASCOT_SILHOUETTES[identity.value.shape === 'ellipse' ? 'oval' : identity.value.shape], fixedTime: props.fixedTime, expression: props.expressionIndex,
+  ribbons: runtimeActive.value || state.value !== 'working' }))
 function sync() {
   if (!svg.value || hasImage.value) { renderer?.dispose();renderer=undefined;return }
   if (!renderer) renderer=mountCursorAvatar(svg.value, options.value)

+ 7 - 3
src/client/components/common/maus/cursor-engine.ts

@@ -372,6 +372,7 @@ export interface EffectFrame {
   paint: string
   showEffects: boolean
   showGlyphs: boolean
+  showTrails?: boolean
 }
 
 /** Called once per frame from the engine loop. */
@@ -381,7 +382,7 @@ export function updateEffects(frame: EffectFrame) {
   const strength = frame.strength
 
   if (frame.trails) {
-    if (spec?.trails && frame.showEffects && strength > 0) {
+    if (spec?.trails && frame.showEffects && frame.showTrails !== false && strength > 0) {
       drawTrails(frame.trails, spec.trails, frame.elapsed, strength, centre, centre)
     } else if (frame.trails.childNodes.length) {
       frame.trails.replaceChildren()
@@ -917,11 +918,13 @@ export interface CursorOptions {
   gaze?: { x?: number; y?: number }
   expression?: number
   fixedTime?: number
+  /** Live activity rings. A saved "working" face does not wear them. */
+  ribbons?: boolean
 }
 type Engine = ReturnType<typeof newEngine>
 function newEngine() {
   return { current: clone(EXPRESSIONS[0]), target: EXPRESSIONS[0], expression: 0, morph: 1, velocity: 0, blinkStart: noTimestamp(), spinStart: noTimestamp(), spinDuration: 900, last: 0, stateStart: 0, lastState: 'idle' as CursorState, lastBodyTransform: '',
-    props: {state: 'idle' as CursorState, expression: undefined as number | undefined, gaze: undefined as {x?:number;y?:number}|undefined, turn:0, spring:7, eyeScale:1, paused:true, motionStrength:0, effects:true, glyphs:true} }
+    props: {state: 'idle' as CursorState, expression: undefined as number | undefined, gaze: undefined as {x?:number;y?:number}|undefined, turn:0, spring:7, eyeScale:1, paused:true, motionStrength:0, effects:true, glyphs:true, ribbons:true} }
 }
 let nextId = 0
 export function mountCursorAvatar(svg: SVGSVGElement, initial: CursorOptions) {
@@ -1001,6 +1004,7 @@ export function mountCursorAvatar(svg: SVGSVGElement, initial: CursorOptions) {
           paint: paintRef.current,
           showEffects: p.effects !== false,
           showGlyphs: p.glyphs !== false,
+          showTrails: p.ribbons !== false,
         })
       }
 
@@ -1032,7 +1036,7 @@ export function mountCursorAvatar(svg: SVGSVGElement, initial: CursorOptions) {
     options=next
     svg.setAttribute('viewBox', next.silhouette.viewBox ?? VIEW_BOX)
     const e=engine.current, now=performance.now();paintRef.current=next.color
-    e.props={...e.props,state:next.state,expression:next.expression,gaze:next.gaze,paused:next.paused,motionStrength:next.paused?0:1}
+    e.props={...e.props,state:next.state,expression:next.expression,gaze:next.gaze,paused:next.paused,motionStrength:next.paused?0:1,ribbons:next.ribbons!==false}
     const outline=node<SVGGElement>('outline').current, clip=node<SVGClipPathElement>('clip').current, face=node<SVGGElement>('face').current
     const body=next.silhouette.body.replace(/\{\{GRADIENT\}\}/g,next.color)
     if(lastBody!==body){outline.innerHTML=body;lastBody=body}