perf: release GPU resources correctly and reuse render targets

Dispose scene resources before renderer allocation records are cleared and
release the bloom high-pass material. Avoid unused bloom depth buffers and
the final screen pass swap, keeping the same visual output and quality.
Batch sign-stage layout reads before applying existing masks.

Validated approved assets, types, client and SSR builds, prerendered content,
artifacts and transfer budgets. Checked 32 matching transition renders,
66 browser interactions and repeated quality-change resource cleanup.
This commit is contained in:
2026-09-05 15:50:53 +03:00
parent ef51580cf9
commit f3f2b031d0
3 changed files with 50 additions and 11 deletions

View File

@@ -14,6 +14,14 @@ export function createSignStage(resources: SceneResourceBag) {
(element): element is HTMLElement => element instanceof HTMLElement,
)
: [];
// Read the complete stage before writing masks. Interleaving each panel's
// reads and writes forces style recalculation again for the next panel.
const measurements = panels.map((panel) => ({
panel,
heading: panel.querySelector<HTMLElement>(':scope > h2'),
bounds: null as DOMRect | null,
headingOffset: '',
}));
let dirty = true;
let cutoff = 0;
let stageBottom = 176;
@@ -91,14 +99,16 @@ export function createSignStage(resources: SceneResourceBag) {
readingTop = topEdge + feather;
// Only the panel crossing the edge needs a composited mask. Masking
// the complete document would allocate a very tall intermediate layer.
for (const panel of panels) {
const bounds = panel.getBoundingClientRect();
const heading = panel.querySelector<HTMLElement>(':scope > h2');
for (const measurement of measurements) {
const bounds = measurement.panel.getBoundingClientRect();
measurement.bounds = bounds;
if (measurement.heading)
measurement.headingOffset = `${(measurement.heading.getBoundingClientRect().top - bounds.top).toFixed(2)}px`;
}
for (const { panel, bounds, heading, headingOffset } of measurements) {
if (!bounds) continue;
if (heading)
panel.style.setProperty(
'--chapter-heading-offset',
`${(heading.getBoundingClientRect().top - bounds.top).toFixed(2)}px`,
);
panel.style.setProperty('--chapter-heading-offset', headingOffset);
const top = topEdge * reveal;
const bottom = short && width < 768 ? height - 164 : Infinity;
if (