@@ -26,6 +26,13 @@ const STATIC_MS = 3000;
2626
2727type Act = 'silence' | 'event' | 'afterglow' ;
2828
29+ /**
30+ * 可变重奏演出变体(宪法第三条 §1:同一成就不重播同一演出)
31+ * star=孤星亮起(默认);trinity=三星连线(知识成网);bloom=光尘上浮(秩序开花)
32+ */
33+ type SignatureVisual = 'star' | 'trinity' | 'bloom' ;
34+ const VISUALS : SignatureVisual [ ] = [ 'star' , 'trinity' , 'bloom' ] ;
35+
2936export function SignatureMoment ( ) {
3037 const signatureSeq = useWorldEvents ( ( s ) => s . signatureSeq ) ;
3138 const signatureConcept = useWorldEvents ( ( s ) => s . signatureConcept ) ;
@@ -34,6 +41,7 @@ export function SignatureMoment() {
3441 const [ act , setAct ] = useState < Act > ( 'silence' ) ;
3542 const [ concept , setConcept ] = useState ( '' ) ;
3643 const [ variant , setVariant ] = useState < 'mastery' | 'genesis' > ( 'mastery' ) ;
44+ const [ visual , setVisual ] = useState < SignatureVisual > ( 'star' ) ;
3745 const timers = useRef < Array < ReturnType < typeof setTimeout > > > ( [ ] ) ;
3846 const reduced = useMemo (
3947 ( ) => typeof window !== 'undefined' && window . matchMedia ( '(prefers-reduced-motion: reduce)' ) . matches ,
@@ -57,6 +65,8 @@ export function SignatureMoment() {
5765 clearTimers ( ) ;
5866 setConcept ( signatureConcept ) ;
5967 setVariant ( signatureVariant ) ;
68+ // 可变重奏:每次事件随机选取演出变体(可变比率,对抗多巴胺适应)
69+ setVisual ( VISUALS [ Math . floor ( Math . random ( ) * VISUALS . length ) ] ) ;
6070 setActive ( true ) ;
6171
6272 if ( reduced ) {
@@ -88,6 +98,88 @@ export function SignatureMoment() {
8898 // eslint-disable-next-line react-hooks/exhaustive-deps
8999 } , [ active ] ) ;
90100
101+ /** 星核(三个变体共用的发光体) / Shared glowing star core */
102+ const starCore = (
103+ < div style = { {
104+ position : 'absolute' , inset : 44 , borderRadius : '50%' ,
105+ background : 'radial-gradient(circle at 40% 36%, #E0F7FF, #67E8F9 60%, #0891B2)' ,
106+ boxShadow : '0 0 34px #22D3EE, 0 0 90px rgba(34,211,238,0.4)' ,
107+ } } />
108+ ) ;
109+
110+ /** 可变重奏演出渲染(痕迹由场景层永久保留,此处是演出) */
111+ const renderVisual = ( ) => {
112+ if ( visual === 'trinity' ) {
113+ // 三星连线:知识结成网
114+ return (
115+ < motion . svg
116+ width = { 180 } height = { 140 } viewBox = "0 0 180 140"
117+ initial = { { opacity : 0 , scale : 0.9 } }
118+ animate = { { opacity : 1 , scale : 1 } }
119+ transition = { { type : 'spring' , stiffness : 180 , damping : 24 } }
120+ >
121+ { [ [ 90 , 24 ] , [ 34 , 108 ] , [ 146 , 108 ] ] . map ( ( [ x , y ] , i ) => (
122+ < motion . line
123+ key = { `l${ i } ` }
124+ x1 = { 90 } y1 = { 24 }
125+ x2 = { x } y2 = { y }
126+ stroke = "#22D3EE" strokeWidth = { 0.8 }
127+ initial = { { opacity : 0 } }
128+ animate = { { opacity : 0.55 } }
129+ transition = { { delay : 0.3 + i * 0.18 , duration : 0.5 } }
130+ />
131+ ) ) }
132+ { [ [ 90 , 24 , 9 ] , [ 34 , 108 , 6 ] , [ 146 , 108 , 6 ] ] . map ( ( [ x , y , r ] , i ) => (
133+ < motion . circle
134+ key = { `s${ i } ` }
135+ cx = { x } cy = { y } r = { r }
136+ fill = "#67E8F9"
137+ style = { { filter : 'drop-shadow(0 0 12px #22D3EE)' } }
138+ initial = { { opacity : 0 , scale : 0.2 } }
139+ animate = { { opacity : 1 , scale : 1 } }
140+ transition = { { delay : i * 0.22 , type : 'spring' , stiffness : 220 , damping : 20 } }
141+ />
142+ ) ) }
143+ </ motion . svg >
144+ ) ;
145+ }
146+ if ( visual === 'bloom' ) {
147+ // 光尘上浮:秩序开花
148+ return (
149+ < div style = { { position : 'relative' , width : 120 , height : 120 } } >
150+ { ! reduced && [ 0 , 1 , 2 , 3 , 4 , 5 ] . map ( ( i ) => (
151+ < motion . span
152+ key = { i }
153+ initial = { { opacity : 0 , y : 10 , x : ( i - 2.5 ) * 14 } }
154+ animate = { { opacity : [ 0 , 0.9 , 0 ] , y : - 70 - ( i % 3 ) * 18 } }
155+ transition = { { duration : 2.4 , delay : i * 0.3 , repeat : Infinity , ease : 'easeOut' } }
156+ style = { {
157+ position : 'absolute' , left : '50%' , bottom : 30 , width : 3 , height : 3 ,
158+ borderRadius : '50%' , background : '#A5F3FC' , boxShadow : '0 0 8px #22D3EE' ,
159+ } }
160+ />
161+ ) ) }
162+ { starCore }
163+ </ div >
164+ ) ;
165+ }
166+ // 默认:孤星亮起 + 秩序波纹
167+ return (
168+ < div style = { { position : 'relative' , width : 120 , height : 120 } } >
169+ { ! reduced && [ 0 , 0.5 , 1 ] . map ( ( d ) => (
170+ < motion . span
171+ key = { d }
172+ initial = { { scale : 0.2 , opacity : 0.8 } }
173+ animate = { { scale : 2.6 , opacity : 0 } }
174+ transition = { { duration : 2 , delay : d , ease : 'easeOut' , repeat : Infinity } }
175+ style = { { position : 'absolute' , inset : 0 , borderRadius : '50%' , border : '1px solid #22D3EE' } }
176+ />
177+ ) ) }
178+ { starCore }
179+ </ div >
180+ ) ;
181+ } ;
182+
91183 if ( ! active ) return null ;
92184
93185 return createPortal (
@@ -127,23 +219,8 @@ export function SignatureMoment() {
127219 transition = { { type : 'spring' , stiffness : 200 , damping : 26 } }
128220 style = { { display : 'flex' , flexDirection : 'column' , alignItems : 'center' , gap : 26 , textAlign : 'center' , padding : '0 32px' } }
129221 >
130- { /* 亮起的星 + 秩序波纹(痕迹由场景层永久保留,此处是演出) */ }
131- < div style = { { position : 'relative' , width : 120 , height : 120 } } >
132- { ! reduced && [ 0 , 0.5 , 1 ] . map ( ( d ) => (
133- < motion . span
134- key = { d }
135- initial = { { scale : 0.2 , opacity : 0.8 } }
136- animate = { { scale : 2.6 , opacity : 0 } }
137- transition = { { duration : 2 , delay : d , ease : 'easeOut' , repeat : Infinity } }
138- style = { { position : 'absolute' , inset : 0 , borderRadius : '50%' , border : '1px solid #22D3EE' } }
139- />
140- ) ) }
141- < div style = { {
142- position : 'absolute' , inset : 44 , borderRadius : '50%' ,
143- background : 'radial-gradient(circle at 40% 36%, #E0F7FF, #67E8F9 60%, #0891B2)' ,
144- boxShadow : '0 0 34px #22D3EE, 0 0 90px rgba(34,211,238,0.4)' ,
145- } } />
146- </ div >
222+ { /* 可变重奏演出区(star/trinity/bloom 随机) */ }
223+ { renderVisual ( ) }
147224
148225 < div >
149226 { variant === 'genesis' ? (
0 commit comments