center front and back pages

Hunter
Monday, February 2nd, 2026 at 6:48 PM

resources/page-flip-animation.js+42 
resources/spread-layout.js+7-1

resources/page-flip-animation.js
  2  let isAnimating = false;
  3  let currentSpreadIndex = 0;
  4  let pendingFlipQueue = [];
  5 +let bookContainer = null;
  6  
  7  // Get animation state
  8  export function getIsAnimating() {

 27  	// Create the book structure
 28  	const book = doc.createElement('div');
 29  	book.className = 'zine-book';
 30 +	bookContainer = book;
 31  
 32  	// Create all leaves (page pairs)
 33  	PAGE_LEAVES.forEach((leaf, index) => {

 67  
 68  	// Set initial state - all leaves closed, showing front cover
 69  	updateLeafStates(0, doc);
 70 +	updateBookPosition(0, false);
 71 +}
 72 +
 73 +// Update the book container horizontal position based on spread
 74 +// Spreads 0 and 4 (single pages) should be centered, others at normal position
 75 +function updateBookPosition(spreadIndex, animated = true) {
 76 +	if (!bookContainer) return;
 77 +
 78 +	// Spread 0 (front cover): single right page, shift left to center
 79 +	// Spread 4 (back cover): single left page, shift right to center
 80 +	let shiftAmount = '0in';
 81 +	if (spreadIndex === 0) {
 82 +		shiftAmount = '-1.375in'; // Shift left by half a page width
 83 +	} else if (spreadIndex === 4) {
 84 +		shiftAmount = '1.375in'; // Shift right by half a page width
 85 +	}
 86 +
 87 +	if (animated) {
 88 +		bookContainer.style.transition = 'transform 0.6s cubic-bezier(0.645, 0.045, 0.355, 1.000)';
 89 +	} else {
 90 +		bookContainer.style.transition = 'none';
 91 +	}
 92 +
 93 +	// Preserve any existing scale from scaleSpreadToFit
 94 +	const currentTransform = bookContainer.style.transform || '';
 95 +	const scaleMatch = currentTransform.match(/scale\([^)]+\)/);
 96 +	const scale = scaleMatch ? scaleMatch[0] : '';
 97 +
 98 +	bookContainer.style.transform = scale ? `translateX(${shiftAmount}) ${scale}` : `translateX(${shiftAmount})`;
 99 +
100 +	// Remove transition after animation completes
101 +	if (animated) {
102 +		setTimeout(() => {
103 +			bookContainer.style.transition = '';
104 +		}, 600);
105 +	}
106  }
107  
108  // Update which leaves are open/closed based on current spread

150  	isAnimating = true;
151  	currentSpreadIndex = toSpread;
152  
153 +	// Update book position synchronously with the flip animation
154 +	updateBookPosition(toSpread, true);
155 +
156  	const direction = toSpread > fromSpread ? 'forward' : 'backward';
157  	const leaves = doc.querySelectorAll('.zine-leaf');
158  

252  export function setSpreadImmediate(spreadIndex, doc) {
253  	currentSpreadIndex = spreadIndex;
254  	updateLeafStates(spreadIndex, doc);
255 +	updateBookPosition(spreadIndex, false);
256  }
resources/spread-layout.js
72  	const scaleX = (vw - 40) / spreadWidthPx;
73  	const scaleY = (vh - 40) / spreadHeightPx;
74  	const scale = Math.min(scaleX, scaleY);
   -	bookContainer.style.transform = `scale(${scale})`;
75 +
76 +	// Preserve any existing translateX from book positioning
77 +	const currentTransform = bookContainer.style.transform || '';
78 +	const translateMatch = currentTransform.match(/translateX\([^)]+\)/);
79 +	const translateX = translateMatch ? translateMatch[0] : '';
80 +
81 +	bookContainer.style.transform = translateX ? `${translateX} scale(${scale})` : `scale(${scale})`;
82  }