Fix WebGL page readiness gating
This commit is contained in:
@@ -32,6 +32,7 @@ class BookPlaybackTimelineModule extends BaseModule {
|
||||
'startRevealForSegment',
|
||||
'assertSegmentReady',
|
||||
'collectRequiredPageMetas',
|
||||
'collectTexturePlanPageMetas',
|
||||
'requiresSpreadTransition',
|
||||
'requiresRightPageFlipAfterReveal',
|
||||
'getBlockRevealSides',
|
||||
@@ -375,7 +376,7 @@ class BookPlaybackTimelineModule extends BaseModule {
|
||||
targetSpread: options.targetSpread,
|
||||
endSpread: Math.max(0, Number(this.pagination?.spreads?.length || 1) - 1),
|
||||
getPageMetaForIndex: this.getPageMetaForIndex,
|
||||
recordMiss: true
|
||||
recordMiss: false
|
||||
});
|
||||
await this.assertSegmentReady({
|
||||
blockId: options.blockId ?? null,
|
||||
@@ -410,31 +411,44 @@ class BookPlaybackTimelineModule extends BaseModule {
|
||||
return result;
|
||||
}
|
||||
|
||||
collectRequiredPageMetas(segment = {}) {
|
||||
const spreads = new Set();
|
||||
collectRequiredPageMetas(segment = {}, phase = 'play') {
|
||||
if (phase === 'prepare') {
|
||||
return this.collectTexturePlanPageMetas(segment.preparedTexturePlan);
|
||||
}
|
||||
if (phase === 'activate' || phase === 'play') {
|
||||
return this.collectTexturePlanPageMetas(segment.activeTexturePlan || segment.preparedTexturePlan);
|
||||
}
|
||||
const currentSpread = this.getVisibleSpreadIndex();
|
||||
const targetSpread = Number.isFinite(Number(segment.targetSpreadIndex))
|
||||
? Math.max(0, Math.round(Number(segment.targetSpreadIndex)))
|
||||
: currentSpread;
|
||||
spreads.add(0);
|
||||
spreads.add(currentSpread);
|
||||
spreads.add(Math.max(0, currentSpread - 1));
|
||||
spreads.add(currentSpread + 1);
|
||||
spreads.add(targetSpread);
|
||||
if (segment.requiresRightFlip) spreads.add(targetSpread + 1);
|
||||
return Array.from(spreads)
|
||||
.filter(spread => spread >= 0)
|
||||
return Array.from(new Set([currentSpread, targetSpread]))
|
||||
.flatMap(spread => [
|
||||
this.getPageMetaForIndex(spread * 2),
|
||||
this.getPageMetaForIndex(spread * 2 + 1)
|
||||
]);
|
||||
}
|
||||
|
||||
collectTexturePlanPageMetas(texturePlan = null) {
|
||||
const pageMeta = texturePlan?.pageMeta || {};
|
||||
const records = Array.isArray(texturePlan?.records) ? texturePlan.records : [];
|
||||
const metas = records
|
||||
.map(record => record?.pageMeta || pageMeta?.[record?.side])
|
||||
.filter(meta => meta && Number.isFinite(Number(meta.pageIndex)));
|
||||
['left', 'right'].forEach((side) => {
|
||||
const meta = pageMeta?.[side];
|
||||
if (!meta || !Number.isFinite(Number(meta.pageIndex))) return;
|
||||
if (metas.some(existing => Number(existing.pageIndex) === Number(meta.pageIndex))) return;
|
||||
metas.push(meta);
|
||||
});
|
||||
return metas;
|
||||
}
|
||||
|
||||
async assertSegmentReady(segment = {}, phase = 'play') {
|
||||
if (!this.pageCache || typeof this.pageCache.ensurePageTexture !== 'function') {
|
||||
throw new Error('BookPlaybackTimeline: Page texture cache is not available');
|
||||
}
|
||||
const metas = this.collectRequiredPageMetas(segment);
|
||||
const metas = this.collectRequiredPageMetas(segment, phase);
|
||||
const missing = [];
|
||||
await Promise.all(metas.map(async (meta) => {
|
||||
const texture = await this.pageCache.ensurePageTexture(meta, {
|
||||
@@ -464,8 +478,19 @@ class BookPlaybackTimelineModule extends BaseModule {
|
||||
const spread = typeof this.pagination?.getSpread === 'function'
|
||||
? this.pagination.getSpread(spreadIndex)
|
||||
: this.pagination?.spreads?.[spreadIndex];
|
||||
const source = spread?.pageMeta?.[side] || {};
|
||||
const metrics = this.textureRenderer?.metrics || {};
|
||||
if (!spread) {
|
||||
return {
|
||||
pageIndex: index,
|
||||
width: metrics.width,
|
||||
height: metrics.height,
|
||||
kind: 'blank',
|
||||
section: index < 3 ? 'frontmatter' : 'body',
|
||||
pageNumber: null,
|
||||
omitPageNumber: true
|
||||
};
|
||||
}
|
||||
const source = spread?.pageMeta?.[side] || {};
|
||||
return {
|
||||
...source,
|
||||
pageIndex: index,
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ const ModuleState = {
|
||||
ERROR: 'ERROR'
|
||||
};
|
||||
|
||||
const MODULE_CACHE_BUSTER = '20260610-book-timeline-b';
|
||||
const MODULE_CACHE_BUSTER = '20260610-book-timeline-d';
|
||||
window.MODULE_CACHE_BUSTER = MODULE_CACHE_BUSTER;
|
||||
|
||||
/**
|
||||
|
||||
@@ -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=20260610-book-timeline-b';
|
||||
import { PROCEDURAL_BOOK, createProceduralBookModel, snapProceduralPageCount } from './procedural-book-model.js?v=20260610-book-timeline-d';
|
||||
|
||||
const canvas = document.getElementById('scene');
|
||||
canvas.style.cursor = 'grab';
|
||||
@@ -2105,7 +2105,7 @@ function handlePageTextureRecords(event) {
|
||||
source: 'book-texture-renderer'
|
||||
});
|
||||
markPageTextureTiming('handlePageTextureRecords:end');
|
||||
prewarmNavigationTextureWindow('page-texture-records').catch((error) => {
|
||||
prewarmNavigationTextureWindow('page-texture-records', { recordMiss: false }).catch((error) => {
|
||||
pageTextureStore?.recordProblem?.({
|
||||
type: 'navigation-window-prewarm-error',
|
||||
message: error?.message || String(error)
|
||||
@@ -2300,7 +2300,7 @@ async function prewarmNavigationTextureWindow(reason = 'navigation-window', opti
|
||||
targetSpread: options.targetSpread,
|
||||
endSpread,
|
||||
getPageMetaForIndex: makePageMetaForCache,
|
||||
recordMiss: options.recordMiss !== false
|
||||
recordMiss: options.recordMiss === true
|
||||
});
|
||||
markPageTextureTiming('textureStorePrewarm:end', {
|
||||
reason,
|
||||
|
||||
@@ -381,7 +381,7 @@ class WebGLPageCacheModule extends BaseModule {
|
||||
if (!Number.isFinite(pageIndex)) return null;
|
||||
const key = this.makeResidentKey(pageMeta);
|
||||
const resident = this.residentTextures.get(key);
|
||||
if (!resident || this.isOlderPageMeta(pageMeta, resident.pageMeta)) return null;
|
||||
if (!resident) return null;
|
||||
return this.getResidentTexture(pageMeta);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user