@@ -15,6 +15,8 @@ const CYCLE_MS = 17_100
1515
1616let pending : FrameRequestCallback [ ] = [ ]
1717let clock = 0
18+ let reducedMotion = false
19+ let onMotionPreference : ( ( ) => void ) | undefined
1820let root : Root | null = null
1921let host : HTMLDivElement | null = null
2022
@@ -40,15 +42,23 @@ beforeEach(() => {
4042 ; ( globalThis as { IS_REACT_ACT_ENVIRONMENT ?: boolean } ) . IS_REACT_ACT_ENVIRONMENT = true
4143 pending = [ ]
4244 clock = 0
45+ reducedMotion = false
46+ onMotionPreference = undefined
4347 const stubs = {
4448 requestAnimationFrame : ( cb : FrameRequestCallback ) => pending . push ( cb ) ,
4549 cancelAnimationFrame : ( ) => {
4650 pending = [ ]
4751 } ,
4852 matchMedia : ( ) => ( {
49- matches : false ,
50- addEventListener : ( ) => { } ,
51- removeEventListener : ( ) => { } ,
53+ get matches ( ) {
54+ return reducedMotion
55+ } ,
56+ addEventListener : ( _type : string , listener : ( ) => void ) => {
57+ onMotionPreference = listener
58+ } ,
59+ removeEventListener : ( ) => {
60+ onMotionPreference = undefined
61+ } ,
5262 } ) ,
5363 }
5464 for ( const [ name , value ] of Object . entries ( stubs ) ) {
@@ -79,7 +89,10 @@ describe('FooterWordmarkLoop', () => {
7989 expect ( html ) . toContain ( 'aria-hidden="true"' )
8090 expect ( html ) . toContain ( 'data-stage="wm" opacity="1"' )
8191 expect ( html ) . toContain ( 'data-stage="orb" opacity="0"' )
82- expect ( html ) . toContain ( 'stdDeviation="0.55"' )
92+ expect ( html ) . toContain ( 'stdDeviation="0"' )
93+ expect ( html ) . toMatch ( / f i l t e r = " u r l \( # f w l - g o o - / )
94+ expect ( html ) . toContain ( 'values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0"' )
95+ expect ( html ) . not . toContain ( '<feGaussianBlur in="goo"' )
8396 for ( const shape of SHAPES ) {
8497 expect ( html ) . toContain ( `data-stage="${ shape } " opacity="0"` )
8598 }
@@ -90,12 +103,14 @@ describe('FooterWordmarkLoop', () => {
90103
91104 it ( 'plays the master timeline: wordmark, orb, the seven shapes, orb, wordmark' , ( ) => {
92105 expect ( attr ( '[data-stage="wm"]' , 'opacity' ) ) . toBe ( '1.0000' )
93- expect ( attr ( '[data-goo]' , 'stdDeviation' ) ) . toBe ( '0.550' )
106+ expect ( attr ( '[data-goo]' , 'stdDeviation' ) ) . toBe ( '0.000' )
107+ expect ( attr ( '[data-goo-matrix]' , 'values' ) ) . toMatch ( / 1 \. 0 0 0 - ? 0 \. 0 0 0 $ / )
94108
95109 advanceTo ( 2700 )
96110 expect ( attr ( '[data-stage="wm"]' , 'opacity' ) ) . toBe ( '0.0000' )
97111 expect ( attr ( '[data-stage="orb"]' , 'opacity' ) ) . toBe ( '1.0000' )
98112 expect ( attr ( '[data-goo]' , 'stdDeviation' ) ) . toBe ( '5.000' )
113+ expect ( attr ( '[data-goo-matrix]' , 'values' ) ) . toMatch ( / 4 0 \. 0 0 0 - 1 9 \. 0 0 0 $ / )
99114
100115 advanceTo ( 3900 )
101116 expect ( attr ( '[data-stage="metaballs"]' , 'opacity' ) ) . toBe ( '1.0000' )
@@ -112,13 +127,53 @@ describe('FooterWordmarkLoop', () => {
112127 advanceTo ( 16000 )
113128 expect ( attr ( '[data-stage="wm"]' , 'opacity' ) ) . toBe ( '1.0000' )
114129 expect ( attr ( '[data-stage="thinking"]' , 'opacity' ) ) . toBe ( '0.0000' )
115- expect ( attr ( '[data-goo]' , 'stdDeviation' ) ) . toBe ( '0.550' )
130+ expect ( attr ( '[data-goo]' , 'stdDeviation' ) ) . toBe ( '0.000' )
131+ expect ( attr ( '[data-goo-matrix]' , 'values' ) ) . toMatch ( / 1 \. 0 0 0 - ? 0 \. 0 0 0 $ / )
116132
117133 advanceTo ( CYCLE_MS + 2700 )
118134 expect ( attr ( '[data-stage="orb"]' , 'opacity' ) ) . toBe ( '1.0000' )
119135 expect ( attr ( '[data-stage="wm"]' , 'opacity' ) ) . toBe ( '0.0000' )
120136 } )
121137
138+ it ( 'returns to an identity filter when reduced motion is enabled mid-morph' , ( ) => {
139+ advanceTo ( 2700 )
140+ expect ( attr ( '[data-goo-matrix]' , 'values' ) ) . toMatch ( / 4 0 \. 0 0 0 - 1 9 \. 0 0 0 $ / )
141+
142+ reducedMotion = true
143+ act ( ( ) => onMotionPreference ?.( ) )
144+
145+ expect ( pending ) . toHaveLength ( 0 )
146+ expect ( attr ( '[data-stage="wm"]' , 'opacity' ) ) . toBe ( '1.0000' )
147+ expect ( attr ( '[data-stage="orb"]' , 'opacity' ) ) . toBe ( '0.0000' )
148+ expect ( attr ( '[data-goo-matrix]' , 'values' ) ) . toMatch ( / 1 \. 0 0 0 - ? 0 \. 0 0 0 $ / )
149+ expect ( attr ( '[data-goo]' , 'stdDeviation' ) ) . toBe ( '0.000' )
150+ } )
151+
152+ it ( 'eases the same filter to identity at both wordmark boundaries' , ( ) => {
153+ advanceTo ( 1300 )
154+ expect ( attr ( '[data-goo]' , 'stdDeviation' ) ) . toBe ( '0.000' )
155+ expect ( attr ( '[data-goo-matrix]' , 'values' ) ) . toMatch ( / 1 \. 0 0 0 - ? 0 \. 0 0 0 $ / )
156+
157+ advanceTo ( 1301 )
158+ expect ( Number ( attr ( '[data-goo]' , 'stdDeviation' ) ) ) . toBeLessThan ( 0.001 )
159+ expect ( attr ( '[data-goo-matrix]' , 'values' ) ) . toMatch ( / 1 \. 0 0 0 - ? 0 \. 0 0 0 $ / )
160+
161+ advanceTo ( 1800 )
162+ expect ( attr ( '[data-goo-matrix]' , 'values' ) ) . toMatch ( / 4 0 \. 0 0 0 - 1 9 \. 0 0 0 $ / )
163+
164+ advanceTo ( 2500 )
165+ expect ( attr ( '[data-goo]' , 'stdDeviation' ) ) . toBe ( '5.000' )
166+
167+ advanceTo ( 15199 )
168+ expect ( Number ( attr ( '[data-goo]' , 'stdDeviation' ) ) ) . toBeLessThan ( 0.001 )
169+ expect ( attr ( '[data-goo-matrix]' , 'values' ) ) . toMatch ( / 1 \. 0 0 0 - ? 0 \. 0 0 0 $ / )
170+
171+ advanceTo ( 15200 )
172+ expect ( attr ( '[data-goo]' , 'stdDeviation' ) ) . toBe ( '0.000' )
173+ expect ( attr ( '[data-goo-matrix]' , 'values' ) ) . toMatch ( / 1 \. 0 0 0 - ? 0 \. 0 0 0 $ / )
174+ expect ( host ?. querySelector ( 'feComposite' ) ) . toBeNull ( )
175+ } )
176+
122177 it ( 'stops requesting frames on unmount' , ( ) => {
123178 advanceTo ( 500 )
124179 act ( ( ) => root ?. unmount ( ) )
0 commit comments