From b09f4656e4368e29aa8760c08c12f25620100f03 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 5 May 2026 11:26:48 +0100 Subject: [PATCH] Constrain aquarium ink emission --- apps/epiphany-gui/src/aquariumFluid.ts | 43 +++++++++++++++++--------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/apps/epiphany-gui/src/aquariumFluid.ts b/apps/epiphany-gui/src/aquariumFluid.ts index 605d0f42..4fd483dc 100644 --- a/apps/epiphany-gui/src/aquariumFluid.ts +++ b/apps/epiphany-gui/src/aquariumFluid.ts @@ -995,6 +995,7 @@ class WebglAquariumRenderer implements AquariumRenderer { private drawSource(projected: ProjectedAgent[], activeAgent: ProjectedAgent | undefined, time: number) { const ctx = this.sourceContext; + const paintAgentChrome = this.frame.variant !== "fullscreen"; ctx.clearRect(0, 0, this.simWidth, this.simHeight); this.hotOptions = []; ctx.save(); @@ -1003,33 +1004,42 @@ class WebglAquariumRenderer implements AquariumRenderer { const hot = agent.id === activeAgent?.id || agent.id === this.frame.selectedAgentId; this.drawAgentSource(ctx, agent, hot); } - if (activeAgent) { + if (activeAgent && paintAgentChrome) { this.drawThoughtSource(ctx, activeAgent); - this.drawOptionsSource(ctx, activeAgent); + } + if (activeAgent) { + this.drawOptionsSource(ctx, activeAgent, paintAgentChrome); } this.drawParameterImpulseSource(ctx, time); ctx.restore(); } private drawAgentSource(ctx: CanvasRenderingContext2D, agent: ProjectedAgent, hot: boolean) { - const size = 22 + agent.activity * 10 + agent.chirps.expression * 4 + (hot ? 4 : 0); + const fullscreen = this.frame.variant === "fullscreen"; + const size = fullscreen + ? 46 + agent.activity * 7 + agent.chirps.expression * 3 + (hot ? 2 : 0) + : 22 + agent.activity * 10 + agent.chirps.expression * 4 + (hot ? 4 : 0); const ink = this.fluidParams.sourceOpacity * agent.emissionPulse * agent.chirps.inkPulse; const distortion = agent.chirps.distortion + (hot ? 0.02 : 0); + const layers = fullscreen ? 1 : 4; ctx.save(); ctx.translate(agent.x, agent.y); ctx.rotate(Math.atan2(agent.vy, agent.vx || 0.001) * 0.12); ctx.globalCompositeOperation = "lighter"; ctx.fillStyle = agent.color; - for (let index = 0; index < 4; index += 1) { - const lag = 4 + index * 6; - const layerSize = size * (1 + index * 0.18); + for (let index = 0; index < layers; index += 1) { + const lag = fullscreen ? 0 : 4 + index * 6; + const layerSize = fullscreen ? size : size * (1 + index * 0.18); const pulse = 0.68 + agent.chirps.glowPulse * 0.14 + chirplet(this.time, agent.phase + index * 0.61, 0.28 + agent.chirps.expression * 0.24, 0.025, 6.5) * 0.24; + const alphaBase = fullscreen + ? 0.01 + agent.activity * 0.012 + (hot ? 0.003 : 0) + : 0.024 + agent.activity * 0.028 + (hot ? 0.015 : 0) - index * 0.003; ctx.save(); - ctx.translate(-agent.vx * lag - index * 1.5, -agent.vy * lag + index); - ctx.globalAlpha = clamp((0.024 + agent.activity * 0.028 + (hot ? 0.015 : 0) - index * 0.003) * ink * pulse, 0, 0.42); + ctx.translate(fullscreen ? 0 : -agent.vx * lag - index * 1.5, fullscreen ? 0 : -agent.vy * lag + index); + ctx.globalAlpha = clamp(alphaBase * ink * pulse, 0, fullscreen ? 0.09 : 0.42); drawDistortedAgentPath(ctx, agent.shape, layerSize, this.time * 0.18 + index * 0.9, agent.phase + index * 0.37, distortion + index * 0.018); ctx.fill(); ctx.restore(); @@ -1052,16 +1062,18 @@ class WebglAquariumRenderer implements AquariumRenderer { ctx.restore(); } - private drawOptionsSource(ctx: CanvasRenderingContext2D, agent: ProjectedAgent) { + private drawOptionsSource(ctx: CanvasRenderingContext2D, agent: ProjectedAgent, paint = true) { const options = agent.options ?? []; if (!options.length) return; const radius = this.simWidth < 540 ? 64 : 86; const arc = Math.min(Math.PI * 1.2, Math.max(Math.PI * 0.7, options.length * 0.34)); const start = -Math.PI / 2 - arc / 2; - ctx.save(); - ctx.font = "900 9px Inter, system-ui, sans-serif"; - ctx.textAlign = "center"; - ctx.textBaseline = "middle"; + if (paint) { + ctx.save(); + ctx.font = "900 9px Inter, system-ui, sans-serif"; + ctx.textAlign = "center"; + ctx.textBaseline = "middle"; + } for (let index = 0; index < options.length; index += 1) { const option = options[index]; const angle = start + (arc * (index + 0.5)) / options.length; @@ -1071,6 +1083,7 @@ class WebglAquariumRenderer implements AquariumRenderer { if (!option.disabled) { this.hotOptions.push({ x, y, radius: 32, key: option.key }); } + if (!paint) continue; ctx.globalAlpha = (option.disabled ? 0.008 : hot ? 0.04 : 0.018) * this.fluidParams.sourceOpacity; ctx.fillStyle = option.disabled ? agent.glow : agent.color; ctx.strokeStyle = option.disabled ? hexAlpha(agent.glow, 0.12) : hexAlpha(agent.glow, hot ? 0.62 : 0.32); @@ -1078,7 +1091,9 @@ class WebglAquariumRenderer implements AquariumRenderer { ctx.fill(); ctx.stroke(); } - ctx.restore(); + if (paint) { + ctx.restore(); + } } private drawDeckSource(ctx: CanvasRenderingContext2D) {