commit 462936e5181377f3b3adc08bdc5fa10cdee0da02
parent a1c047cc6472e8d93051c8aebe6f9cc016e583f3
Author: Hunter
Date: Mon, 2 Feb 2026 23:40:31 -0500
align zine to grid
Diffstat:
3 files changed, 56 insertions(+), 1 deletion(-)
diff --git a/resources/editor.css b/resources/editor.css
@@ -40,7 +40,19 @@ body {
height: 100%;
display: flex;
flex-direction: column;
- background: linear-gradient(to top, #252525, #3a3a3a);
+ --grid-width: 33px;
+ --grid-height: 33px;
+ --spread-left: 0px;
+ --spread-top: 0px;
+ background:
+ linear-gradient(to right, #4a7a6a 1px, transparent 1px),
+ linear-gradient(to bottom, #4a7a6a 1px, transparent 1px),
+ linear-gradient(to bottom, #1a4d3a, #184534);
+ background-size: var(--grid-width) var(--grid-height), var(--grid-width) var(--grid-height), 100% 100%;
+ background-position:
+ calc(var(--spread-left) + var(--grid-width) / 2) var(--spread-top),
+ calc(var(--spread-left) + var(--grid-width) / 2) var(--spread-top),
+ 0 0;
}
.preview-pane.fullscreen {
diff --git a/resources/editor.js b/resources/editor.js
@@ -31,6 +31,26 @@ window.addEventListener('message', function(event) {
window.saveFile();
} else if (event.data === 'saveFileWithViewer') {
window.saveFileWithViewer();
+ } else if (event.data?.type === 'scaleChange') {
+ // Update background grid size and position to match zine preview
+ const previewPane = document.querySelector('.preview-pane');
+ const preview = document.querySelector('#preview');
+ if (previewPane && preview) {
+ // Get iframe position relative to preview pane
+ const iframeRect = preview.getBoundingClientRect();
+ const paneRect = previewPane.getBoundingClientRect();
+ const iframeOffsetX = iframeRect.left - paneRect.left;
+ const iframeOffsetY = iframeRect.top - paneRect.top;
+
+ // Spread position in pane coordinates
+ const spreadLeft = iframeOffsetX + event.data.spreadLeft;
+ const spreadTop = iframeOffsetY + event.data.spreadTop;
+
+ previewPane.style.setProperty('--grid-width', `${event.data.gridWidth}px`);
+ previewPane.style.setProperty('--grid-height', `${event.data.gridHeight}px`);
+ previewPane.style.setProperty('--spread-left', `${spreadLeft}px`);
+ previewPane.style.setProperty('--spread-top', `${spreadTop}px`);
+ }
}
});
diff --git a/resources/spread-layout.js b/resources/spread-layout.js
@@ -79,4 +79,27 @@ export function scaleSpreadToFit(container, doc, bottomPadding = 0) {
const translateX = translateMatch ? translateMatch[0] : '';
bookContainer.style.transform = translateX ? `scale(${scale}) ${translateX}` : `scale(${scale})`;
+
+ // Notify parent of spread position and grid size for background grid
+ if (doc.defaultView?.parent && doc.defaultView.parent !== doc.defaultView) {
+ const rect = bookContainer.getBoundingClientRect();
+
+ // Derive grid from height (always 1 page tall = 11 cells)
+ // Cell aspect ratio: (2.75/7) / (4.25/11) = 30.25/29.75
+ const gridHeight = rect.height / 11;
+ const gridWidth = gridHeight * (30.25 / 29.75);
+
+ // Remove translateX shift so grid always anchors to the un-shifted book position
+ // The translateX is in inches and gets multiplied by scale
+ const translateInchMatch = translateX.match(/translateX\(([^)]+)in\)/);
+ const translatePx = translateInchMatch ? parseFloat(translateInchMatch[1]) * 96 * scale : 0;
+
+ doc.defaultView.parent.postMessage({
+ type: 'scaleChange',
+ gridWidth,
+ gridHeight,
+ spreadLeft: rect.left - translatePx,
+ spreadTop: rect.top
+ }, '*');
+ }
}