From 7abd3387f38dad1ed021cbba8cd56454fde800ad Mon Sep 17 00:00:00 2001 From: Georg Tomitsch Date: Sun, 7 Jun 2026 17:59:01 +0200 Subject: [PATCH] Correct WebGL dropcap texture layout --- public/js/book-page-format-module.js | 2 +- public/js/book-pagination-module.js | 5 ++--- public/js/loader.js | 2 +- public/js/webgl-book-lab.js | 2 +- scripts/check-webgl-book-lab.js | 3 +++ 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/public/js/book-page-format-module.js b/public/js/book-page-format-module.js index 688ef76..b976874 100644 --- a/public/js/book-page-format-module.js +++ b/public/js/book-page-format-module.js @@ -3,7 +3,7 @@ * Defines the canonical page geometry used by the WebGL book renderer. */ import { BaseModule } from './base-module.js'; -import { calculateProceduralBookThickness, snapProceduralPageCount } from './procedural-book-model.js?v=20260607-webgl-resize-prime'; +import { calculateProceduralBookThickness, snapProceduralPageCount } from './procedural-book-model.js?v=20260607-webgl-typography-a'; export const BOOK_TEXTURE_WIDTH = 3072; diff --git a/public/js/book-pagination-module.js b/public/js/book-pagination-module.js index 18abd80..4e198ae 100644 --- a/public/js/book-pagination-module.js +++ b/public/js/book-pagination-module.js @@ -264,7 +264,8 @@ class BookPaginationModule extends BaseModule { const inkRight = Number.isFinite(metrics.actualBoundingBoxRight) && metrics.actualBoundingBoxRight > 0 ? metrics.actualBoundingBoxRight : (metrics.width || 0); - return Math.max(inkRight, lineHeightPx * 1.08) + this.measureNormalTextGap(fontPx); + const advanceWidth = metrics.width || 0; + return Math.max(inkRight, advanceWidth, lineHeightPx * 1.08) + this.measureNormalTextGap(fontPx); } measureNormalTextGap(fontPx) { @@ -355,8 +356,6 @@ class BookPaginationModule extends BaseModule { fragments.push(node.value || ''); } else if (node.type === 'glue' && node.width > 0) { fragments.push(' '); - } else if (node.type === 'penalty' && node.penalty === 100) { - fragments.push('|'); } } return fragments.join('').replace(/\s+/g, ' ').trimStart(); diff --git a/public/js/loader.js b/public/js/loader.js index 181318a..2e3e371 100644 --- a/public/js/loader.js +++ b/public/js/loader.js @@ -24,7 +24,7 @@ const ModuleState = { ERROR: 'ERROR' }; -const MODULE_CACHE_BUSTER = '20260607-webgl-resize-prime'; +const MODULE_CACHE_BUSTER = '20260607-webgl-typography-a'; window.MODULE_CACHE_BUSTER = MODULE_CACHE_BUSTER; /** diff --git a/public/js/webgl-book-lab.js b/public/js/webgl-book-lab.js index 10d5d81..c7869ba 100644 --- a/public/js/webgl-book-lab.js +++ b/public/js/webgl-book-lab.js @@ -4,7 +4,7 @@ import { RenderPass } from 'https://esm.sh/three@0.165.0/examples/jsm/postproces import { SSAOPass } from 'https://esm.sh/three@0.165.0/examples/jsm/postprocessing/SSAOPass.js'; import { SMAAPass } from 'https://esm.sh/three@0.165.0/examples/jsm/postprocessing/SMAAPass.js'; import { OutputPass } from 'https://esm.sh/three@0.165.0/examples/jsm/postprocessing/OutputPass.js'; -import { PROCEDURAL_BOOK, createProceduralBookModel, snapProceduralPageCount } from './procedural-book-model.js?v=20260607-webgl-resize-prime'; +import { PROCEDURAL_BOOK, createProceduralBookModel, snapProceduralPageCount } from './procedural-book-model.js?v=20260607-webgl-typography-a'; const canvas = document.getElementById('scene'); canvas.style.cursor = 'grab'; diff --git a/scripts/check-webgl-book-lab.js b/scripts/check-webgl-book-lab.js index 4acac26..f80933b 100644 --- a/scripts/check-webgl-book-lab.js +++ b/scripts/check-webgl-book-lab.js @@ -106,6 +106,9 @@ const checks = [ ['texture renderer records prepare draw publish and start reveal timing', /markPipelineTiming\('prepareRevealBlock:start'/.test(textureRendererSource) && /markPipelineTiming\('drawSpread:start'/.test(textureRendererSource) && /markPipelineTiming\('publishSpread'/.test(textureRendererSource) && /markPipelineTiming\('startPreparedRevealAnimation'/.test(textureRendererSource)], ['texture renderer diagnostics include reveal word counts', /wordCounts/.test(textureRendererSource) && /revealWords/.test(textureRendererSource) && /wordRects/.test(textureRendererSource)], ['texture renderer does not draw immediate non-pending sides during pending reveal preparation', !/immediateSides/.test(textureRendererSource) && !/this\.drawSpread\(this\.currentSpread, immediateSides\)/.test(textureRendererSource)], + ['drop-cap remaining text does not reinsert discretionary hyphen markers', /extractRemainingLayoutText/.test(bookPaginationSource) && !bookPaginationSource.includes("fragments.push('|')")], + ['drop-cap reservation keeps a normal text gap beside the initial', /measureDropCapReservation/.test(bookPaginationSource) && /measureNormalTextGap\(fontPx\)/.test(bookPaginationSource)], + ['drop-cap reservation uses both ink bounds and font advance width', /const advanceWidth = metrics\.width \|\| 0/.test(bookPaginationSource) && /Math\.max\(inkRight, advanceWidth, lineHeightPx \* 1\.08\)/.test(bookPaginationSource)], ['webgl scene avoids duplicate initial texture publish', !/this\.triggerTextureRefresh\(\)/.test(methodBody(webglSceneSource, 'initializeScene'))], ['webgl scene does not republish 3D page textures from DOM refresh events', !/addEventListener\(document, 'story:turn-start', this\.triggerTextureRefresh\)/.test(webglSceneSource) && !/addEventListener\(document, 'story:turn-complete', this\.triggerTextureRefresh\)/.test(webglSceneSource) && !/addEventListener\(document, 'story:history-updated', this\.triggerTextureRefresh\)/.test(webglSceneSource) && !/addEventListener\(document, 'input', this\.triggerTextureRefresh/.test(webglSceneSource) && !/addEventListener\(document, 'change', this\.triggerTextureRefresh/.test(webglSceneSource)], ['webgl scene adoptPageContent does not republish 3D page textures', !/triggerTextureRefresh/.test(methodBody(webglSceneSource, 'adoptPageContent'))]