From e373a1b1e19d20e5b2c881fe1da07d3c9d95a44c Mon Sep 17 00:00:00 2001 From: Edom <463882408@qq.com> Date: Mon, 24 Aug 2026 21:31:04 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E8=87=AA=E5=8A=A8=E5=B0=8F=E5=8A=A8?= =?UTF-8?q?=E4=BD=9C=E4=BB=85=E5=9C=A8=E5=8A=A8=E7=94=BB=E5=88=86=E5=8C=BA?= =?UTF-8?q?=E5=BC=80=E5=90=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- replica/src/character.js | 16 ++++++++++++---- src/App.vue | 2 ++ src/components/AvatarStage.vue | 5 ++++- src/components/Hero.vue | 9 ++++++--- src/replica/boot.ts | 1 + src/replica/host.ts | 6 +++++- 6 files changed, 30 insertions(+), 9 deletions(-) diff --git a/replica/src/character.js b/replica/src/character.js index 9c74c93..2f94281 100644 --- a/replica/src/character.js +++ b/replica/src/character.js @@ -69,6 +69,10 @@ this.driven = !!opts.driven; this.paused = !!opts.paused; this.reduceMotion = opts.reduceMotion ?? (typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches); + // autoTricks gates the AUTOMATIC spin sources (wantPn, celebrate re-arm, + // idle trick loop, shape-change trick). State-inherent rotation + // (humming/loading ovSpin) and explicit spinOnce stay untouched. + this.autoTricks = opts.autoTricks !== false; this.badgeColor = opts.badgeColor || "var(--gb-badge, #1d9bf0)"; this.sizePx = opts.sizePx || null; this.eyeColor = opts.eyeColor || null; @@ -642,6 +646,10 @@ this.playlistHold = next; } + setAutoTricks(on) { + this.autoTricks = !!on; + } + playback() { const remain = this.playlistHold ? (this.eyeRemain || 0) @@ -893,7 +901,7 @@ } _cycleShapeTrick() { - if (this.reduceMotion || this.paused || this.driven || this.manualHold) return; + if (this.reduceMotion || this.paused || this.driven || this.manualHold || !this.autoTricks) return; this.trickCycle = (this.trickCycle + 1) % 5; this.wildWide = false; if (this.trickCycle === 0) this._pn(1); @@ -1039,7 +1047,7 @@ this.ctx.wantBlink = false; } if (!this.manualHold && this.ctx.wantPn) { - this._pn(...this.ctx.wantPn); + if (this.autoTricks) this._pn(...this.ctx.wantPn); this.ctx.wantPn = null; } if (!this.manualHold && this.ctx.wantBurst) { @@ -1059,12 +1067,12 @@ this._stepOverlay(now); } - if (!this.manualHold && this.celebrateAt > 0 && now >= this.celebrateAt && !this.trick) { + if (this.autoTricks && !this.manualHold && this.celebrateAt > 0 && now >= this.celebrateAt && !this.trick) { this.trick = TR.startTrick("spinWild", this.reduceMotion || this.paused); this.celebrateAt = now + 6200; } - if (!this.driven && !this.manualHold && now >= this.trickAt) { + if (this.autoTricks && !this.driven && !this.manualHold && now >= this.trickAt) { if ((V_T.has(this.state) || B_T.has(this.state)) && !this.spinTurn && this.hopAt < 0 && !this.trick) { const z = Math.random(); if (V_T.has(this.state)) { diff --git a/src/App.vue b/src/App.vue index 669e923..c0efeba 100644 --- a/src/App.vue +++ b/src/App.vue @@ -127,6 +127,7 @@ const cycle = computed(() => cycles.value.find((c) => c.id === activeId.value) ? const state = ref(intro.value ? 'idle' : (cycle.value.blocks[block.value]?.state ?? 'idle')) const gauche = computed(() => view.value === 'reglages' && !preview.value) +const autoTricks = computed(() => view.value === 'animations') const droite = computed(() => view.value !== 'reglages' && !preview.value && !intro.value) const plein = computed(() => preview.value || photo.value) const follow = computed(() => view.value === 'reglages' && !preview.value) @@ -740,6 +741,7 @@ onUnmounted(() => { :echelle="photo ? photoComposition.scale : 1" :playing="posePlay" :mix="poseMix" + :auto-tricks="autoTricks" @ready="onHeroReady" @update:manual="manual = $event" /> diff --git a/src/components/AvatarStage.vue b/src/components/AvatarStage.vue index 1f544f4..24f1252 100644 --- a/src/components/AvatarStage.vue +++ b/src/components/AvatarStage.vue @@ -18,6 +18,7 @@ const props = withDefaults( playing?: boolean mix?: number echelle?: number + autoTricks?: boolean }>(), { size: 440, @@ -30,7 +31,8 @@ const props = withDefaults( tools: false, playing: false, mix: 0, - echelle: 1 + echelle: 1, + autoTricks: true } ) @@ -125,6 +127,7 @@ defineExpose({ :state="state" :follow="follow && !active" :paper="paper" + :auto-tricks="autoTricks" @ready="onReady" /> (), { size: 440, @@ -18,7 +19,8 @@ const props = withDefaults( color: 'black', state: 'idle', follow: false, - paper: '#f9f9f9' + paper: '#f9f9f9', + autoTricks: true } ) @@ -37,7 +39,8 @@ function input() { color: props.color, follow: props.follow, paper: props.paper, - size: props.size + size: props.size, + autoTricks: props.autoTricks } } @@ -66,7 +69,7 @@ onBeforeUnmount(() => { }) watch( - () => [props.state, props.shape, props.color, props.follow, props.paper, props.size], + () => [props.state, props.shape, props.color, props.follow, props.paper, props.size, props.autoTricks], () => replica?.apply(input()) ) diff --git a/src/replica/boot.ts b/src/replica/boot.ts index 1321182..7b648c6 100644 --- a/src/replica/boot.ts +++ b/src/replica/boot.ts @@ -32,6 +32,7 @@ export type ReplicaBot = { setSize: (px: number) => void seekEye: (index: number, opts?: { snap?: boolean }) => void setPlaylistHold: (on: boolean) => void + setAutoTricks: (on: boolean) => void playback: () => ReplicaPlayback destroy: () => void } diff --git a/src/replica/host.ts b/src/replica/host.ts index 25a69f5..4ecb838 100644 --- a/src/replica/host.ts +++ b/src/replica/host.ts @@ -36,6 +36,7 @@ export type ReplicaInput = { paper: string size: number eye?: number + autoTricks?: boolean } const TILE_MAX = 6 @@ -118,7 +119,8 @@ export async function mountReplica( eyeColor: input.paper, paused: driven ? false : live ? false : 'hold-pose', driven, - eyeIndex: input.eye + eyeIndex: input.eye, + autoTricks: input.autoTricks ?? true }) const noop = { apply: () => {}, @@ -154,6 +156,8 @@ export async function mountReplica( if (next.follow !== last.follow) bot.setFollowPointer(next.follow) if (next.paper !== last.paper) bot.setEyeColor(next.paper) if (next.size !== last.size) bot.setSize(next.size) + if ((next.autoTricks ?? true) !== (last.autoTricks ?? true)) + bot.setAutoTricks(next.autoTricks ?? true) last = { ...next } }, spin: () => bot.spinOnce(1),