align zine to grid
Hunter
Monday, February 2nd, 2026 at 11:40 PM
40 height: 100%;
41 display: flex;
42 flex-direction: column;
- background: linear-gradient(to top, #252525, #3a3a3a);
43 + --grid-width: 33px;
44 + --grid-height: 33px;
45 + --spread-left: 0px;
46 + --spread-top: 0px;
47 + background:
48 + linear-gradient(to right, #4a7a6a 1px, transparent 1px),
49 + linear-gradient(to bottom, #4a7a6a 1px, transparent 1px),
50 + linear-gradient(to bottom, #1a4d3a, #184534);
51 + background-size: var(--grid-width) var(--grid-height), var(--grid-width) var(--grid-height), 100% 100%;
52 + background-position:
53 + calc(var(--spread-left) + var(--grid-width) / 2) var(--spread-top),
54 + calc(var(--spread-left) + var(--grid-width) / 2) var(--spread-top),
55 + 0 0;
56 }
57
58 .preview-pane.fullscreen {
31 window.saveFile();
32 } else if (event.data === 'saveFileWithViewer') {
33 window.saveFileWithViewer();
34 + } else if (event.data?.type === 'scaleChange') {
35 + // Update background grid size and position to match zine preview
36 + const previewPane = document.querySelector('.preview-pane');
37 + const preview = document.querySelector('#preview');
38 + if (previewPane && preview) {
39 + // Get iframe position relative to preview pane
40 + const iframeRect = preview.getBoundingClientRect();
41 + const paneRect = previewPane.getBoundingClientRect();
42 + const iframeOffsetX = iframeRect.left - paneRect.left;
43 + const iframeOffsetY = iframeRect.top - paneRect.top;
44 +
45 + // Spread position in pane coordinates
46 + const spreadLeft = iframeOffsetX + event.data.spreadLeft;
47 + const spreadTop = iframeOffsetY + event.data.spreadTop;
48 +
49 + previewPane.style.setProperty('--grid-width', `${event.data.gridWidth}px`);
50 + previewPane.style.setProperty('--grid-height', `${event.data.gridHeight}px`);
51 + previewPane.style.setProperty('--spread-left', `${spreadLeft}px`);
52 + previewPane.style.setProperty('--spread-top', `${spreadTop}px`);
53 + }
54 }
55 });
56
79 const translateX = translateMatch ? translateMatch[0] : '';
80
81 bookContainer.style.transform = translateX ? `scale(${scale}) ${translateX}` : `scale(${scale})`;
82 +
83 + // Notify parent of spread position and grid size for background grid
84 + if (doc.defaultView?.parent && doc.defaultView.parent !== doc.defaultView) {
85 + const rect = bookContainer.getBoundingClientRect();
86 +
87 + // Derive grid from height (always 1 page tall = 11 cells)
88 + // Cell aspect ratio: (2.75/7) / (4.25/11) = 30.25/29.75
89 + const gridHeight = rect.height / 11;
90 + const gridWidth = gridHeight * (30.25 / 29.75);
91 +
92 + // Remove translateX shift so grid always anchors to the un-shifted book position
93 + // The translateX is in inches and gets multiplied by scale
94 + const translateInchMatch = translateX.match(/translateX\(([^)]+)in\)/);
95 + const translatePx = translateInchMatch ? parseFloat(translateInchMatch[1]) * 96 * scale : 0;
96 +
97 + doc.defaultView.parent.postMessage({
98 + type: 'scaleChange',
99 + gridWidth,
100 + gridHeight,
101 + spreadLeft: rect.left - translatePx,
102 + spreadTop: rect.top
103 + }, '*');
104 + }
105 }