@@ -25,6 +25,8 @@ export class TorusRenderer {
2525 private status : GameStatus = "Paused" ;
2626 private scoreVisible = true ;
2727 private expandedScoreIndex : number | null = null ;
28+ private lastPoleHeight : number | null = null ;
29+ private poleResizeTimer : number | null = null ;
2830
2931 constructor ( private readonly dom : TorusDom ) { }
3032
@@ -53,6 +55,7 @@ export class TorusRenderer {
5355 }
5456
5557 public refreshLayout ( ) : void {
58+ this . syncSideColumnLayout ( ) ;
5659 this . syncPanelHeights ( ) ;
5760 }
5861
@@ -63,6 +66,8 @@ export class TorusRenderer {
6366 public setScoreboardVisible ( visible : boolean ) : void {
6467 this . scoreVisible = visible ;
6568 this . dom . scoreCardEl . classList . toggle ( "hidden" , ! visible ) ;
69+ this . syncSideColumnLayout ( ) ;
70+ this . syncPanelHeights ( ) ;
6671 }
6772
6873 public renderScoreboard (
@@ -269,6 +274,10 @@ export class TorusRenderer {
269274 }
270275
271276 private renderPole ( snapshot : GameSnapshot ) : void {
277+ const poleStageEl = this . getPoleStageElement ( ) ;
278+ const previousHeight = poleStageEl ?. getBoundingClientRect ( ) . height ?? 0 ;
279+ const shouldAnimateHeight = this . lastPoleHeight !== null && this . lastPoleHeight !== snapshot . poleHeight ;
280+
272281 this . dom . poleGridEl . style . gridTemplateColumns = `repeat(${ snapshot . numCols } , var(--ascii-cell-width))` ;
273282
274283 const cells : string [ ] = [ ] ;
@@ -288,6 +297,10 @@ export class TorusRenderer {
288297 }
289298
290299 this . dom . poleGridEl . innerHTML = cells . join ( "" ) ;
300+ this . lastPoleHeight = snapshot . poleHeight ;
301+ if ( shouldAnimateHeight ) {
302+ this . animatePoleStageResize ( previousHeight ) ;
303+ }
291304 }
292305
293306 private renderPoleCell ( entry : PoleEntry , difficulty : Difficulty ) : string {
@@ -302,6 +315,45 @@ export class TorusRenderer {
302315 return this . renderStaticBoxCell ( entry , difficulty ) ;
303316 }
304317
318+ private getPoleStageElement ( ) : HTMLDivElement | null {
319+ const parent = this . dom . poleGridEl . parentElement ;
320+ if ( ! ( parent instanceof HTMLDivElement ) ) {
321+ return null ;
322+ }
323+ return parent ;
324+ }
325+
326+ private animatePoleStageResize ( previousHeight : number ) : void {
327+ const poleStageEl = this . getPoleStageElement ( ) ;
328+ if ( ! poleStageEl || previousHeight <= 0 ) {
329+ return ;
330+ }
331+ if ( window . matchMedia ( "(prefers-reduced-motion: reduce)" ) . matches ) {
332+ return ;
333+ }
334+
335+ const nextHeight = poleStageEl . getBoundingClientRect ( ) . height ;
336+ if ( ! Number . isFinite ( nextHeight ) || Math . abs ( nextHeight - previousHeight ) < 1 ) {
337+ return ;
338+ }
339+
340+ if ( this . poleResizeTimer !== null ) {
341+ window . clearTimeout ( this . poleResizeTimer ) ;
342+ this . poleResizeTimer = null ;
343+ }
344+
345+ poleStageEl . style . height = `${ previousHeight } px` ;
346+ poleStageEl . style . transition = "height 280ms cubic-bezier(0.22, 1, 0.36, 1)" ;
347+ void poleStageEl . offsetWidth ;
348+ poleStageEl . style . height = `${ nextHeight } px` ;
349+
350+ this . poleResizeTimer = window . setTimeout ( ( ) => {
351+ poleStageEl . style . height = "" ;
352+ poleStageEl . style . transition = "" ;
353+ this . poleResizeTimer = null ;
354+ } , 320 ) ;
355+ }
356+
305357 private syncPanelHeights ( ) : void {
306358 const board = this . dom . boardStageCardEl ;
307359 const side = this . dom . sideColumnEl ;
@@ -324,6 +376,21 @@ export class TorusRenderer {
324376
325377 side . style . height = `${ clamped } px` ;
326378 }
379+
380+ private syncSideColumnLayout ( ) : void {
381+ const arena = this . dom . boardStageCardEl . parentElement ;
382+ if ( ! ( arena instanceof HTMLElement ) ) {
383+ return ;
384+ }
385+
386+ const scoreHidden = ! this . scoreVisible ;
387+ const keyVisible = ! this . dom . keyCardEl . classList . contains ( "hidden" ) ;
388+ const sideHidden = scoreHidden && ! keyVisible ;
389+
390+ this . dom . sideColumnEl . classList . toggle ( "score-hidden" , scoreHidden ) ;
391+ arena . classList . toggle ( "score-hidden" , scoreHidden && keyVisible ) ;
392+ arena . classList . toggle ( "side-hidden" , sideHidden ) ;
393+ }
327394}
328395
329396function renderAsciiCell (
0 commit comments