// https://gist.github.com/patriciogonzalezvivo/670c22f3966e662d2f83 vec3 permute(vec3 x) { return mod(((x*34.0)+1.0)*x, 289.0); } // https://gist.github.com/patriciogonzalezvivo/670c22f3966e662d2f83 float snoise(vec2 v) { const vec4 C = vec4(0.211324865405187, 0.366025403784439, -0.577350269189626, 0.024390243902439); vec2 i = floor(v + dot(v, C.yy) ); vec2 x0 = v - i + dot(i, C.xx); vec2 i1; i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0); vec4 x12 = x0.xyxy + C.xxzz; x12.xy -= i1; i = mod(i, 289.0); vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 )) + i.x + vec3(0.0, i1.x, 1.0 )); vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0); m = m*m ; m = m*m ; vec3 x = 2.0 * fract(p * C.www) - 1.0; vec3 h = abs(x) - 0.5; vec3 ox = floor(x + 0.5); vec3 a0 = x - ox; m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h ); vec3 g; g.x = a0.x * x0.x + h.x * x0.y; g.yz = a0.yz * x12.xz + h.yz * x12.yw; return 130.0 * dot(m, g); } // https://github.com/hughsk/glsl-hsv2rgb vec3 hsv2rgb(vec3 c) { vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); } vec3 hsv2rgb(float h, float s, float v) { return hsv2rgb(vec3(h / 360., s / 100., v / 100.)); } float lerp(float a, float b, float w) { return a * (1. - w) + b * w; } // Circular hue interpolation to avoid unwanted green tones float lerpHue(float a, float b, float w) { float diff = b - a; // Take the shortest path around the color wheel if (diff > 180.) { diff -= 360.; } else if (diff < -180.) { diff += 360.; } float result = a + diff * w; // Normalize to 0-360 range if (result < 0.) { result += 360.; } else if (result >= 360.) { result -= 360.; } return result; } float constrain(float v, float minValue, float maxValue) { return min(max(v, minValue), maxValue); } void main() { // Enhanced film noir color palette - blue base with red neon accents const float h0_min = 240.; // Deep blue shadows matching brick wall const float s0_min = 35.; // Increased saturation for richer blues const float v0_min = 1.; // Darker shadows for subtlety const float h0_max = 220.; // Cool blue-gray mid-tones const float s0_max = 45.; // Higher saturation for neon-like quality const float v0_max = 6.; // Reduced mid-tone brightness const float h1_min = 350.; // Red neon accent highlights (matching OPEN sign) const float s1_min = 70.; // High saturation for vibrant neon red const float v1_min = 16.; // Reduced brightness for subtlety const float h1_max = 10.; // Bright red-pink neon peaks const float s1_max = 85.; // Maximum saturation for intense neon glow const float v1_max = 28.; // Reduced highlight brightness // Secondary highlight colors (upper-right lamp area) const float h2_min = 200.; // Cool blue-cyan lamp base const float s2_min = 60.; // Moderate saturation for lamp glow const float v2_min = 14.; // Reduced lamp presence const float h2_max = 180.; // Bright cyan lamp peak const float s2_max = 75.; // High saturation for neon lamp effect const float v2_max = 24.; // Reduced lamp highlights // Slower, more atmospheric animation timing vec2 distortion = vec2( snoise(gl_FragCoord.xy / 200.0 + vec2(u_time * .15, u_time * .2)), snoise(gl_FragCoord.xy / 200.0 + vec2(3. + u_time * .2, 4. + u_time * .15)) ); vec2 distorted = gl_FragCoord.xy / 800. + distortion * 0.3; vec2 distortion_2 = vec2( snoise(distorted + vec2(u_time * -.005, u_time * -.008)), snoise(distorted + vec2(3. + u_time * -.008, 4. + u_time * -.15)) ); vec2 distorted_2 = gl_FragCoord.xy / 500. + distortion_2 * 0.25; float noiseValue = (snoise(distorted_2 + vec2(u_time * -0.02, u_time * 0.025)) + 1.) / 2.; // Primary highlight zone (center-based red neon) float d_center = constrain(1. - distance(gl_FragCoord.xy + ((distorted - vec2(1., 1.)) / 2.) * 800., u_resolution / 2.) / sqrt(u_resolution.x * u_resolution.x * 0.4 + u_resolution.y * u_resolution.y * 0.6), 0., 1.); d_center = pow(d_center, 2.5); // Secondary highlight zone (upper-right lamp area) vec2 lampPosition = vec2(u_resolution.x * 0.85, u_resolution.y * 0.75); float d_lamp = constrain(1. - distance(gl_FragCoord.xy + ((distorted - vec2(1., 1.)) / 2.) * 400., lampPosition) / (sqrt(u_resolution.x * u_resolution.x + u_resolution.y * u_resolution.y) * 0.3), 0., 1.); d_lamp = pow(d_lamp, 2.0); // Combine highlight zones - use maximum influence float d_combined = max(d_center, d_lamp); // Determine which highlight zone is dominant for color selection float lampInfluence = d_lamp / max(d_combined, 0.001); float centerInfluence = d_center / max(d_combined, 0.001); // Interpolate between shadow and highlight colors based on combined distance float h_min_base = lerpHue(h0_min, h1_min, d_combined); float s_min_base = lerp(s0_min, s1_min, d_combined); float v_min_base = lerp(v0_min, v1_min, d_combined); float h_max_base = lerpHue(h0_max, h1_max, d_combined); float s_max_base = lerp(s0_max, s1_max, d_combined); float v_max_base = lerp(v0_max, v1_max, d_combined); // Apply lamp influence to shift colors toward blue/cyan in lamp area float h_min_lamp = lerpHue(h0_min, h2_min, d_combined); float s_min_lamp = lerp(s0_min, s2_min, d_combined); float v_min_lamp = lerp(v0_min, v2_min, d_combined); float h_max_lamp = lerpHue(h0_max, h2_max, d_combined); float s_max_lamp = lerp(s0_max, s2_max, d_combined); float v_max_lamp = lerp(v0_max, v2_max, d_combined); // Blend between center (red) and lamp (blue) highlights based on influence float h_min_final = lerpHue(h_min_base, h_min_lamp, lampInfluence); float s_min_final = lerp(s_min_base, s_min_lamp, lampInfluence); float v_min_final = lerp(v_min_base, v_min_lamp, lampInfluence); float h_max_final = lerpHue(h_max_base, h_max_lamp, lampInfluence); float s_max_final = lerp(s_max_base, s_max_lamp, lampInfluence); float v_max_final = lerp(v_max_base, v_max_lamp, lampInfluence); vec3 color = hsv2rgb(lerpHue(h_min_final, h_max_final, noiseValue), lerp(s_min_final, s_max_final, noiseValue), lerp(v_min_final, v_max_final, noiseValue)); // Reduced opacity for subtle atmospheric effect while preserving readability float alpha = 0.30; gl_FragColor = vec4(color.r, color.g, color.b, alpha); }

Ehm, quindi, che si fa qui?

Qwirklabs è un'azienda di software che dà forma alla prossima generazione di prodotti digitali. Creiamo gli strumenti, poi realizziamo i prodotti.

... e cosa bolle in pentola

Qwirklabs nasce dalla convinzione che chi sta creando la prossima generazione di prodotti digitali meritino strumenti migliori delle opzioni spesso ingombranti e macchinose disponibili. Siamo un team compatto di appassionati di tecnologia che hanno sperimentato in prima persona quanto possano essere frustranti flussi di lavoro frammentati tra progettazione e sviluppo.

Ecco perché ci stiamo concentrando sull'integrazione di funzionalità sofisticate (come la progettazione di UI funzionali, l’assistenza AI e il 3D) in un unico ambiente collaborativo. Il nostro obiettivo è creare soluzioni che potenzino i creatori, riducano la complessità e, magari, rendano lo sviluppo di progetti ambiziosi un po' più scorrevole e divertente.

La soluzione che stiamo sviluppando si chiama Smoothie. Pensatela come un potente toolkit modulare progettato per riunire funzionalità e flussi di lavoro sofisticati in un’unica piattaforma accessibile, sul modello dei game engine moderni. Ma invece di imporvi un sistema monolitico, il suo design modulare vi permette di utilizzare solo i componenti che servono davvero al vostro progetto. Stiamo sviluppando questa soluzione nel nostro lab, puntando a quella potenza unificata senza le solite difficoltà di integrazione. È ancora in sviluppo, ma vogliamo rendere la creazione di progetti complessi sorprendentemente... smooth.

Curiosi di sapere cosa facciamo realmente e la tecnologia che stiamo sviluppando? C'è un pulsante che vi porta a tutti i dettagli più interessanti.

sbricia nel lab