fix: carregador do mural à prova de loop no celular
build-atlas.js gera páginas leves de 3072 px para celular (--so-mobile regera só elas) e registra o campo mobile no atlas-map.json. wall.html usa essas páginas em toque ou GPU/aparelho fraco, detecta pela marca em sessionStorage que a tentativa anterior morreu e força o modo leve, e trata falha de download, de decodificação e perda de contexto WebGL com aviso e botão, sem recarregar sozinho. Detalhes e testes no achado 3.5.
This commit is contained in:
+31
-1
@@ -19,6 +19,7 @@
|
||||
*
|
||||
* Uso:
|
||||
* node web/build-atlas.js [--n=99999] [--out=atlas] [--thumbs=DIR]
|
||||
* node web/build-atlas.js --so-mobile (só as páginas leves, a partir do atlas pronto)
|
||||
* node web/build-atlas.js [--n=99999] [--out=atlas] [--downloads=~/Downloads]
|
||||
*/
|
||||
|
||||
@@ -48,6 +49,12 @@ const ATLAS_SIZE = 8192; // dentro do limite de textura de qualquer GPU moderna
|
||||
const TILES_PER_ROW = ATLAS_SIZE / TILE_SIZE; // 64 -> capacidade 4096 peças por atlas
|
||||
const TILES_PER_ATLAS = TILES_PER_ROW * TILES_PER_ROW;
|
||||
const CATALOGO = path.resolve(__dirname, '..', 'pipeline', 'catalogo.jsonl');
|
||||
// light pages for phones: the same layout scaled down, so every tile keeps its
|
||||
// atlas/col/row and only the page size changes. 3072² stays under maxTextureSize
|
||||
// everywhere and under the ~16.7 M-pixel image decode ceiling of iOS Safari — a
|
||||
// phone never has to decode an 8192² page, which is what killed the tab.
|
||||
const MOBILE_TILE = 48;
|
||||
const MOBILE_SIZE = TILES_PER_ROW * MOBILE_TILE; // 3072
|
||||
|
||||
// ── acha os arquivos já baixados pela Trilha B em ~/Downloads ────────────────
|
||||
// nomes: BRAS__20.500.12156.1_<id>__THUMB__thumb_2.jpg (preferido, leve)
|
||||
@@ -201,6 +208,27 @@ async function realTile(filePath) {
|
||||
.toBuffer();
|
||||
}
|
||||
|
||||
// ── light pages for phones, from the desktop pages already on disk ────────────
|
||||
|
||||
async function buildMobile(outDir) {
|
||||
const mapPath = path.join(outDir, 'atlas-map.json');
|
||||
const mapData = JSON.parse(fs.readFileSync(mapPath, 'utf8'));
|
||||
const atlases = [];
|
||||
for (let a = 0; a < mapData.atlases.length; a++) {
|
||||
const name = `atlas-m-${a}.webp`;
|
||||
await sharp(path.join(outDir, mapData.atlases[a]))
|
||||
.resize(MOBILE_SIZE, MOBILE_SIZE, { kernel: 'lanczos3' })
|
||||
.webp({ quality: 82, effort: 4 })
|
||||
.toFile(path.join(outDir, name));
|
||||
const mb = (fs.statSync(path.join(outDir, name)).size / 1024 / 1024).toFixed(2);
|
||||
console.log(`Salvo ${name} (${mb} MB, ${MOBILE_SIZE}px)`);
|
||||
atlases.push(name);
|
||||
}
|
||||
mapData.mobile = { size: MOBILE_SIZE, tile: MOBILE_TILE, atlases };
|
||||
fs.writeFileSync(mapPath, JSON.stringify(mapData));
|
||||
console.log(`atlas-map.json: variante leve registrada (${atlases.length} páginas de ${MOBILE_SIZE}px)`);
|
||||
}
|
||||
|
||||
// ── main ────────────────────────────────────────────────────────────────────
|
||||
|
||||
async function main() {
|
||||
@@ -284,6 +312,8 @@ async function main() {
|
||||
const mapPath = path.join(OUT_DIR, 'atlas-map.json');
|
||||
fs.writeFileSync(mapPath, JSON.stringify(mapData));
|
||||
console.log(`Salvo atlas-map.json (${(fs.statSync(mapPath).size / 1024).toFixed(0)} KB)`);
|
||||
await buildMobile(OUT_DIR);
|
||||
}
|
||||
|
||||
main().catch(e => { console.error(e); process.exit(1); });
|
||||
// --so-mobile: only regenerate the light pages from the desktop atlas on disk
|
||||
(args['so-mobile'] ? buildMobile(OUT_DIR) : main()).catch(e => { console.error(e); process.exit(1); });
|
||||
|
||||
Reference in New Issue
Block a user