diff --git a/src/components/ControlPanel.astro b/src/components/ControlPanel.astro index 6a8424d..355b7f2 100644 --- a/src/components/ControlPanel.astro +++ b/src/components/ControlPanel.astro @@ -194,6 +194,19 @@ import { ChevronDown } from "@lucide/astro"; TINT + +
`;
const charSet = CHAR_SETS[settings.charSet] || CHAR_SETS.standard;
const charCount = charSet.length;
@@ -101,13 +101,11 @@ export class AsciiExporter {
// Adjust color for display
const adjColor = this.adjustColor(r, g, b, settings);
+ const finalColor = settings.color ? adjColor : this.hexToRgb(settings.monoColor);
// Recalculate luma from adjusted color for char selection
let finalLuma = (0.2126 * adjColor.r + 0.7152 * adjColor.g + 0.0722 * adjColor.b) / 255;
- // Adjust luma curve for char selection (gamma/contrast/exposure) explicitly?
- // Actually `adjustColor` does that.
-
if (settings.invert) finalLuma = 1.0 - finalLuma;
const charIndex = Math.floor(finalLuma * (charCount - 1) + 0.5);
@@ -116,7 +114,7 @@ export class AsciiExporter {
// Escape HTML
const safeChar = char === '<' ? '<' : char === '>' ? '>' : char === '&' ? '&' : char;
- const colorStyle = `color: rgb(${Math.round(adjColor.r)}, ${Math.round(adjColor.g)}, ${Math.round(adjColor.b)})`;
+ const colorStyle = `color: rgb(${Math.round(finalColor.r)}, ${Math.round(finalColor.g)}, ${Math.round(finalColor.b)})`;
output += `${safeChar}`;
}
output += "
";
@@ -177,4 +175,11 @@ export class AsciiExporter {
b: Math.max(0, Math.min(255, bNorm * 255))
};
}
+
+ private static hexToRgb(hex: string): { r: number, g: number, b: number } {
+ const r = parseInt(hex.slice(1, 3), 16);
+ const g = parseInt(hex.slice(3, 5), 16);
+ const b = parseInt(hex.slice(5, 7), 16);
+ return { r, g, b };
+ }
}
diff --git a/src/scripts/ascii-shared.ts b/src/scripts/ascii-shared.ts
index c8451b8..ab77e8e 100644
--- a/src/scripts/ascii-shared.ts
+++ b/src/scripts/ascii-shared.ts
@@ -30,6 +30,7 @@ export interface AsciiOptions {
scanlines?: number;
vignette?: number;
monoColor?: string;
+ backgroundColor?: string;
}
export interface AsciiResult {
@@ -69,6 +70,7 @@ export interface AsciiSettings {
scanlines: number;
vignette: number;
monoColor: string;
+ backgroundColor: string;
}
// ============= Constants =============
diff --git a/src/scripts/ui-bindings.ts b/src/scripts/ui-bindings.ts
index 04ebd39..6bd5d2d 100644
--- a/src/scripts/ui-bindings.ts
+++ b/src/scripts/ui-bindings.ts
@@ -243,6 +243,19 @@ export class UIBindings {
}
});
}
+
+ const bgColorInput = document.getElementById('input-bg-color') as HTMLInputElement;
+ const bgColorSwatch = document.getElementById('bg-color-swatch-display');
+
+ if (bgColorInput) {
+ bgColorInput.addEventListener('input', () => {
+ if (this.isUpdatingUI) return;
+ this.controller.setSetting('backgroundColor', bgColorInput.value);
+ if (bgColorSwatch) {
+ bgColorSwatch.style.backgroundColor = bgColorInput.value;
+ }
+ });
+ }
}
// ============= Segments =============
@@ -552,6 +565,18 @@ export class UIBindings {
}
}
+ const bgColorInput = document.getElementById('input-bg-color') as HTMLInputElement;
+ const bgColorSwatch = document.getElementById('bg-color-swatch-display');
+
+ if (bgColorInput && settings.backgroundColor) {
+ if (bgColorInput.value !== settings.backgroundColor) {
+ bgColorInput.value = settings.backgroundColor;
+ }
+ if (bgColorSwatch) {
+ bgColorSwatch.style.backgroundColor = settings.backgroundColor;
+ }
+ }
+
this.updateQueueDisplay();
this.isUpdatingUI = false;
diff --git a/src/scripts/webgl-ascii.ts b/src/scripts/webgl-ascii.ts
index 8702820..afd91f3 100644
--- a/src/scripts/webgl-ascii.ts
+++ b/src/scripts/webgl-ascii.ts
@@ -21,6 +21,7 @@ export interface RenderOptions {
scanlines?: number;
vignette?: number;
monoColor?: string;
+ backgroundColor?: string;
zoom?: number;
zoomCenter?: { x: number; y: number };
mousePos?: { x: number; y: number };
@@ -120,6 +121,7 @@ export class WebGLAsciiRenderer {
uniform float u_scanlines;
uniform float u_vignette;
uniform vec3 u_monoColor;
+ uniform vec3 u_backgroundColor;
uniform float u_zoom;
uniform vec2 u_zoomCenter;
@@ -323,7 +325,7 @@ export class WebGLAsciiRenderer {
finalColor = u_monoColor;
}
- gl_FragColor = vec4(finalColor * charAlpha, charAlpha);
+ gl_FragColor = vec4(mix(u_backgroundColor, finalColor, charAlpha), 1.0);
}
`;
@@ -358,7 +360,7 @@ export class WebGLAsciiRenderer {
'u_invert', 'u_color', 'u_overlayStrength', 'u_edgeMode',
'u_dither', 'u_denoise',
'u_sharpen', 'u_edgeThreshold', 'u_shadows', 'u_highlights',
- 'u_scanlines', 'u_vignette', 'u_monoColor',
+ 'u_scanlines', 'u_vignette', 'u_monoColor', 'u_backgroundColor',
'u_zoom', 'u_zoomCenter', 'u_mousePos',
'u_magnifierRadius', 'u_magnifierZoom', 'u_showMagnifier', 'u_aspect'
];
@@ -515,6 +517,12 @@ export class WebGLAsciiRenderer {
const b = parseInt(hex.slice(5, 7), 16) / 255.0;
gl.uniform3f(u['u_monoColor'], r, g, b);
+ const bgHex = options.backgroundColor || '#000000';
+ const br = parseInt(bgHex.slice(1, 3), 16) / 255.0;
+ const bg = parseInt(bgHex.slice(3, 5), 16) / 255.0;
+ const bb = parseInt(bgHex.slice(5, 7), 16) / 255.0;
+ gl.uniform3f(u['u_backgroundColor'], br, bg, bb);
+
gl.uniform1f(u['u_zoom'], options.zoom || 1.0);
gl.uniform2f(u['u_zoomCenter'], options.zoomCenter?.x ?? 0.5, options.zoomCenter?.y ?? 0.5);
gl.uniform2f(u['u_mousePos'], options.mousePos?.x ?? -1.0, options.mousePos?.y ?? -1.0);