From 2b708f50c6e61478f88519002061cacb9594a7a9 Mon Sep 17 00:00:00 2001 From: Hiren Kangad Date: Tue, 10 Mar 2026 10:36:07 +0530 Subject: [PATCH] fix(refboard): revert image size cap, keep Assets.unload() cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove server-side Sharp resize and texture dimension cap — PixiJS handles large textures natively. Keep the proper Assets.unload() fix to prevent "TextureSource destroyed instead of unloaded" warnings. --- backend/server.js | 26 +++++--------------------- frontend/src/canvas/TextureManager.ts | 15 ++------------- 2 files changed, 7 insertions(+), 34 deletions(-) diff --git a/backend/server.js b/backend/server.js index 71d30fe..d71c538 100644 --- a/backend/server.js +++ b/backend/server.js @@ -18,35 +18,19 @@ app.get('/health', (_req, res) => { res.json({ status: 'ok', timestamp: new Date().toISOString() }); }); -// ---- Image proxy (MinIO → browser, optional resize via ?w=) ---- +// ---- Image proxy (MinIO → browser) ---- app.get('/api/images/*', async (req, res) => { try { const objectPath = req.params[0]; // everything after /api/images/ if (!objectPath) return res.status(400).json({ error: 'Missing path' }); const { minioClient, MINIO_BUCKET } = require('./minio'); const stat = await minioClient.statObject(MINIO_BUCKET, objectPath); - const contentType = stat.metaData?.['content-type'] || ''; + if (stat.metaData?.['content-type']) { + res.setHeader('Content-Type', stat.metaData['content-type']); + } res.setHeader('Cache-Control', 'public, max-age=31536000, immutable'); const stream = await minioClient.getObject(MINIO_BUCKET, objectPath); - - const maxW = parseInt(req.query.w, 10); - const isImage = contentType.startsWith('image/') && !contentType.includes('svg'); - if (maxW > 0 && isImage) { - // Resize on the fly with Sharp — cap width, preserve aspect ratio - const sharp = require('sharp'); - const transform = sharp() - .resize({ width: maxW, withoutEnlargement: true }) - .on('error', () => { - // If sharp fails (e.g. unsupported format), just pipe original - res.setHeader('Content-Type', contentType); - }); - // Sharp outputs same format by default - if (contentType) res.setHeader('Content-Type', contentType); - stream.pipe(transform).pipe(res); - } else { - if (contentType) res.setHeader('Content-Type', contentType); - stream.pipe(res); - } + stream.pipe(res); } catch (err) { if (err.code === 'NoSuchKey' || err.code === 'NotFound') { return res.status(404).json({ error: 'Image not found' }); diff --git a/frontend/src/canvas/TextureManager.ts b/frontend/src/canvas/TextureManager.ts index 7a3b928..96cb3a5 100644 --- a/frontend/src/canvas/TextureManager.ts +++ b/frontend/src/canvas/TextureManager.ts @@ -1,10 +1,5 @@ import { Texture, Assets } from "pixi.js"; -// Max texture dimension — avoids WebGL INVALID_VALUE on large images. -// Most GPUs support 4096 or 8192; we cap at 2048 for memory efficiency -// since display sizes are typically 300-600px anyway. -const MAX_TEXTURE_DIM = 2048; - interface TextureEntry { texture: Texture; url: string; // needed for Assets.unload() @@ -14,12 +9,11 @@ interface TextureEntry { /** * TextureManager — GPU texture cache with LRU eviction and memory budget. - * Caps texture dimensions at MAX_TEXTURE_DIM to prevent WebGL OOM. * Uses Assets.unload() instead of texture.destroy() for proper cleanup. */ export class TextureManager { private cache = new Map(); - private budget = 256 * 1024 * 1024; // 256 MB (conservative for 90+ items) + private budget = 512 * 1024 * 1024; // 512 MB private currentUsage = 0; /** Build the URL for a given asset. */ @@ -33,7 +27,6 @@ export class TextureManager { /** * Load a texture for the given asset. * Returns cached texture if available, otherwise fetches and caches. - * Large images are downscaled server-side via width param to stay within GPU limits. */ async load(assetKey: string): Promise { const existing = this.cache.get(assetKey); @@ -42,11 +35,7 @@ export class TextureManager { return existing.texture; } - // Request capped size from server to avoid loading huge textures into GPU - let url = this.urlForAsset(assetKey); - if (!url.includes('?')) { - url += `?w=${MAX_TEXTURE_DIM}`; - } + const url = this.urlForAsset(assetKey); let texture: Texture; try {