shader_type canvas_item; // An organic membrane rather than terrain: broad folds move below branching // cyan veins. It follows SurfaceBackground's shared camera-uniform contract. uniform vec2 camera_cell = vec2(0.0, 0.0); uniform vec2 camera_frac = vec2(0.0, 0.0); uniform float camera_zoom = 1.0; uniform vec2 viewport_size = vec2(720.0, 1280.0); uniform float cell_size = 220.0; uniform float tile_cells = 32.0; uniform vec4 base_color : source_color = vec4(0.055, 0.008, 0.05, 1.0); uniform vec4 crater_color : source_color = vec4(0.16, 0.018, 0.10, 1.0); uniform vec4 highlight_color : source_color = vec4(0.16, 0.66, 0.72, 1.0); float hash21(vec2 p) { vec3 p3 = fract(vec3(p.xyx) * 0.1031); p3 += dot(p3, p3.yzx + 33.33); return fract((p3.x + p3.y) * p3.z); } void fragment() { vec2 screen_px = UV * viewport_size; vec2 centered = screen_px - viewport_size * 0.5; vec2 rel = camera_frac + centered * (camera_zoom / cell_size); vec2 cell_rel = floor(rel); vec2 local = rel - cell_rel; vec2 wrapped = mod(camera_cell + cell_rel, tile_cells); vec2 p = (wrapped + local) / tile_cells * 6.28318530718; float fold_a = sin(p.x * 3.0 + sin(p.y * 2.0 - TIME * 0.16) * 1.1); // Integer frequencies on both axes keep the 32-cell wrapped field // seamless where p crosses from 2*PI back to zero. float fold_b = sin(p.y * 4.0 - p.x * 2.0 + TIME * 0.11); float tissue = 0.5 + 0.25 * fold_a + 0.25 * fold_b; vec3 color = mix(base_color.rgb, crater_color.rgb, smoothstep(0.18, 0.85, tissue)); float vein_a = abs(sin(p.x * 5.0 + sin(p.y * 3.0 + TIME * 0.22))); float vein_b = abs(sin(p.y * 6.0 - p.x * 2.0 - TIME * 0.18)); // Veins are environmental texture, not attack telegraphs. Keep them thin // and subdued so the boss's bright pink laser lanes remain unambiguous. float vein = 1.0 - smoothstep(0.0, 0.028, min(vein_a, vein_b)); float pulse = 0.55 + 0.45 * sin(TIME * 1.8 + p.x + p.y); color = mix(color, highlight_color.rgb, vein * (0.10 + pulse * 0.20)); float dither = (hash21(screen_px + vec2(7.0, 13.0)) - 0.5) / 128.0; COLOR = vec4(color + vec3(dither), 1.0); }