From 8dae3578b16767bae266c95b52ebd9e3c6297686 Mon Sep 17 00:00:00 2001 From: syntaxbullet Date: Mon, 9 Feb 2026 22:50:25 +0100 Subject: [PATCH] fix(export): enable proper file downloads and fix empty PNG export --- src/pages/index.astro | 8 ++++---- src/scripts/ascii-controller.ts | 26 ++++++++++++++++++++++---- src/scripts/ascii-exporter.ts | 9 +++++++++ src/scripts/ui-bindings.ts | 8 ++++---- src/scripts/webgl-ascii.ts | 2 +- 5 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/pages/index.astro b/src/pages/index.astro index 3eace07..79e1c23 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -223,14 +223,14 @@ import Tooltip from "../components/Tooltip.astro"; diff --git a/src/scripts/ascii-controller.ts b/src/scripts/ascii-controller.ts index b948d21..59e42e6 100644 --- a/src/scripts/ascii-controller.ts +++ b/src/scripts/ascii-controller.ts @@ -417,11 +417,27 @@ export class AsciiController { // ============= Export ============= savePNG(): void { + const wasShowing = this.zoomState.showMagnifier; + + // 1. Force hide magnifier for clean export + if (wasShowing) { + this.zoomState.showMagnifier = false; + this.requestRender('uniforms'); + // Force synchronous render + this.renderFrame(); + } + const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19); AsciiExporter.downloadPNG(this.canvas, `ascii-art-${timestamp}.png`); + + // 2. Restore state + if (wasShowing) { + this.zoomState.showMagnifier = true; + this.requestRender('uniforms'); + } } - async copyText(): Promise { + saveText(): void { if (!this.cachedGrid.imgEl) return; const text = AsciiExporter.generateText( this.cachedGrid.imgEl, @@ -429,10 +445,11 @@ export class AsciiController { this.cachedGrid.widthCols, Math.floor(this.cachedGrid.heightRows) ); - await AsciiExporter.copyToClipboard(text); + const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19); + AsciiExporter.downloadText(text, `ascii-art-${timestamp}.txt`); } - async copyHTML(): Promise { + saveHTML(): void { if (!this.cachedGrid.imgEl) return; const html = AsciiExporter.generateHTML( this.cachedGrid.imgEl, @@ -440,7 +457,8 @@ export class AsciiController { this.cachedGrid.widthCols, Math.floor(this.cachedGrid.heightRows) ); - await AsciiExporter.copyToClipboard(html); + const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19); + AsciiExporter.downloadText(html, `ascii-art-${timestamp}.html`); } // ============= Utilities ============= diff --git a/src/scripts/ascii-exporter.ts b/src/scripts/ascii-exporter.ts index f3a66de..5817675 100644 --- a/src/scripts/ascii-exporter.ts +++ b/src/scripts/ascii-exporter.ts @@ -8,6 +8,15 @@ export class AsciiExporter { link.click(); } + static downloadText(content: string, filename: string) { + const blob = new Blob([content], { type: 'text/plain;charset=utf-8' }); + const link = document.createElement('a'); + link.href = URL.createObjectURL(blob); + link.download = filename; + link.click(); + URL.revokeObjectURL(link.href); + } + static async copyToClipboard(text: string): Promise { if (navigator.clipboard && navigator.clipboard.writeText) { await navigator.clipboard.writeText(text); diff --git a/src/scripts/ui-bindings.ts b/src/scripts/ui-bindings.ts index 6956c5b..cc9bee9 100644 --- a/src/scripts/ui-bindings.ts +++ b/src/scripts/ui-bindings.ts @@ -308,9 +308,9 @@ export class UIBindings { const btnCopyText = document.getElementById('btn-copy-text'); if (btnCopyText) { - const handler = async (e: Event) => { + const handler = (e: Event) => { e.stopPropagation(); - await this.controller.copyText(); + this.controller.saveText(); }; this.buttonHandlers.set('btn-copy-text', handler); btnCopyText.addEventListener('click', handler); @@ -318,9 +318,9 @@ export class UIBindings { const btnCopyHtml = document.getElementById('btn-copy-html'); if (btnCopyHtml) { - const handler = async (e: Event) => { + const handler = (e: Event) => { e.stopPropagation(); - await this.controller.copyHTML(); + this.controller.saveHTML(); }; this.buttonHandlers.set('btn-copy-html', handler); btnCopyHtml.addEventListener('click', handler); diff --git a/src/scripts/webgl-ascii.ts b/src/scripts/webgl-ascii.ts index a231139..ccaa5b0 100644 --- a/src/scripts/webgl-ascii.ts +++ b/src/scripts/webgl-ascii.ts @@ -46,7 +46,7 @@ export class WebGLAsciiRenderer { private lastImage: HTMLImageElement | null; constructor(_canvas: HTMLCanvasElement) { - const gl = _canvas.getContext('webgl', { antialias: false }); + const gl = _canvas.getContext('webgl', { antialias: false, preserveDrawingBuffer: true }); if (!gl) { throw new Error('WebGL not supported'); }