Hey nostr:npub1s02jksmr6tgmcksf3hnmue7pyzlm0sxwarh7lk8tdeprw2hjg6ysp7fxtw!
Why would my domain be flagged as "unknown" by nostter?
There's nothing unknown about a domain I set myself, it's my own domain!
Isn't nostr a decentralized protocol π?
Row
row@alephia.tech
npub1u3sv...xaql
Game dev, BTC Maximalist, and learning to Sail.
"Take heed. Kindness can wear upon one's principles..."
Notes (14)
Today I feel a deep moral solitude.
As if the whole world goes directly to a sinkhole, and the only question to ask every other clueless imbecile passing by is:
βDo you like hurting other people?β
- Bitcoin? Itβs to volatile for me, I prefer an approach with less risk, or at least something that has practical use for our worldβs current challenges.
- Like what?
- Like OpenAI or NVidβ¦ AHHHHHHHH HEELP π₯π₯π₯π₯π₯OH GOD PLEASE NO π₯π₯π₯π₯π₯THE PAIN! π©π©AAHGHHHHHH πππITβS UNBEARABLE πππ₯π₯π₯
BRING DREAD PIRATE ROGERS TO NOSTR RIGHT **THE FUCK** NOW.
#rossulbricht
Ross was pardoned, I am so happy right now π₯².
Cleaning up my laptop from old projects I found this smol proggy to crate polyptychs I made back in 2017 and decided to publish it.
Back then I found an Abyss Watcher's image I loved, and wrote my 'framer' to create this for my living room.
Enjoy stupid Haskell code: https://github.com/RowDaBoat/framer


This one is all mine SDF+Raymarching+Raytracing.
[ Sorry for turning your GPU into a stove ]
You can watch this at #glostr:
https://rowdaboat.github.io/glostr/#npub1u3svk99639mcdfn43s2nawg4a2j4ejmgrq2n63l4t67wzqdmtnks2uxaql
```glsl
#version 300 es
precision mediump float;
uniform vec2 u_resolution;
uniform float u_time;
out vec4 fragColor;
#define MAXDISTANCE 180.
#define EPSILON 0.001
#define TENTH_EPSILON 0.0001
float time;
///////////////
// Structures
struct Camera {
vec3 position;
vec3 direction;
vec3 up;
vec3 left;
vec2 resolution;
};
struct Ray {
vec3 origin;
vec3 direction;
};
#define SKYBOX 0
#define GEOMETRY 1
struct Material {
vec3 color;
vec3 emissive;
float roughness;
};
struct Hit {
vec3 point;
float distance;
vec3 normal;
Material material;
};
/////////////
// Material
Material material(vec3 color, vec3 emissive, float roughness) {
Material material;
material.color = color;
material.emissive = emissive;
material.roughness = roughness;
return material;
}
/////////////
// Ray Hits
Hit noHit() {
Hit hit;
hit.distance = .0;
hit.material.emissive = vec3(0, 0, 0);
hit.material.color = vec3(1, 1, 1);
hit.material.roughness = 1.;
return hit;
}
///////////
// Random
vec4 random;
void shuffle() {
random = fract(1e4 * sin(random) + random.wxyz + 0.5);
}
void initRandom(vec2 normalizedPixel, float frame) {
random = vec4(normalizedPixel, frame, 1);
for(int i = 0; i < 16; i++)
shuffle();
}
////////////////////////
// Viewport and Camera
vec2 viewport(vec2 coordinate, vec2 resolution) {
vec2 normalized = coordinate.xy / resolution.xy;
vec2 centered = -1.0 + 2.0 * normalized;
float aspectRatio = resolution.x / resolution.y;
return vec2(centered.x * aspectRatio, centered.y);
}
Camera camera(vec3 position, vec3 target, float roll, vec2 resolution) {
Camera camera;
camera.position = position;
camera.direction = normalize(target - position);
vec3 rolling = vec3(sin(roll), cos(roll), .0);
camera.up = normalize(cross(camera.direction, rolling));
camera.left = normalize(cross(camera.up, camera.direction));
camera.resolution = resolution;
return camera;
}
Ray cameraRay(Camera camera, vec2 point) {
vec2 displacedPoint = point + random.xy / (0.5 * camera.resolution.xy);
vec3 displacement =
displacedPoint.x * camera.up +
displacedPoint.y * camera.left;
Ray ray;
ray.origin = camera.position;
ray.direction = normalize(displacement + 1.5 * camera.direction);
return ray;
}
#define SAMPLES 15
#define BOUNCES 4
#define MAX_STEPS 25
//////////////////////////
// SDF Scene
float smoothMin(float d1, float d2, float k) {
float h = max(k - abs(d1 - d2), 0.0) / k;
return min(d1, d2) - h * h * h * k * (1.0 / 6.0);
}
float box(vec3 p, vec3 b) {
vec3 q = abs(p) - b;
return length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0);
}
float cylinder(vec3 p, float h, float r) {
vec2 d = abs(vec2(length(p.xz),p.y)) - vec2(r,h);
return min(max(d.x,d.y),0.0) + length(max(d,0.0));
}
float coin(vec3 point) {
float base = cylinder(point, .1, 1.);
float coinCarve = cylinder(point + vec3(0., -.54, 0.), .5, .9);
float lbar = box(point + vec3(.125, 0., 0.), vec3(.06, .09, .75));
float rbar = box(point + vec3(-.125, 0., 0.), vec3(.06, .09, .75));
float back = box(point + vec3(.1, 0., 0.), vec3(.3, .09, .6));
float bars = min(lbar, rbar);
float tbelly = cylinder(point + vec3(-.175, 0, 0.25), .09, .35);
float bbelly = cylinder(point + vec3(-.175, 0, -.25), .09, .35);
float bellies = min(tbelly, bbelly);
float b = min(min(back, bars), bellies);
float carveTBelly = cylinder(point + vec3(-.175, 0, 0.25), 1., .175);
float carveBBelly = cylinder(point + vec3(-.175, 0, -.25), 1., .175);
float carveTBox = box(point + vec3(-.05, 0, 0.25), vec3(.1, 1, .175));
float carveBBox = box(point + vec3(-.05, 0, -.25), vec3(.1, 1, .175));
float bellyCarving = min(min(carveTBelly, carveBBelly), min(carveTBox, carveBBox));
float backCarving = box(point + vec3(.5, 0, 0), vec3(.25, 1, .45));
float carve = min(bellyCarving, backCarving);
float carvedB = max(b, -carve);
return min(max(base, -coinCarve), carvedB);
}
float moon(vec3 point) {
float time = u_time * 2.0;
return length(point - vec3(1.5, 2.5, -1.6 + .125 * sin(time))) - 1.75;
}
float orbiter(vec3 point) {
float time = u_time * .5;
vec3 position = vec3(.9 * sin(time), -0.25, .9 * cos(time));
return length(point + position) - 0.25;
}
float sdfScene(vec3 point) {
float time = u_time * 2.0;
float coin = coin(point);
float moon = moon(point);
float orbiter = orbiter(point);
return min(coin, min(moon, orbiter));
}
Material sdfTagMaterial(Ray ray, float distance, vec3 point) {
float time = u_time * 2.0;
Material result;
float coin = coin(point);
float moon = moon(point);
float orbiter = orbiter(point);
if (abs(moon) <= EPSILON) {
// Light
result = material(
vec3(.6, .6, 1),
vec3(1.2, 1.2, 1.2),
.55
);
} else if (abs(orbiter) <= EPSILON) {
// Orbiter
result = material(
vec3(.3, 0.2, 0.6),
vec3(2, 2, 2),
1.
);
} else if (abs(coin) < EPSILON) {
// Gold
result = material(
vec3(.95, .7, .45),
vec3(.0),
.2
);
} else {
// Skybox
result = material(
(.9 + .125 * sin(time * 0.5)) * 1.4 * mix(vec3(.25, .125, .125), vec3(.7, .8, 1), .5 + .5 * ray.direction.y),
vec3(1, 1, 1),
1.0
);
}
return result;
}
////////////////////////////////////////////////
// Main tracing + marching loop
// Bounces, diffuse, emission, and reflections
vec3 cosineWeightedRandomHemisphereDirection(const vec3 n) {
vec3 uu = normalize(cross(n, vec3(0.0, 1.0, 1.0)));
vec3 vv = cross(uu, n);
float ra = sqrt(random.y);
float rb = 6.2831 * random.x;
float rx = ra * cos(rb);
float ry = ra * sin(rb);
float rz = sqrt( 1.0 - random.y);
vec3 rr = vec3( rx * uu + ry * vv + rz * n );
return normalize(rr);
}
vec3 computeNormal(vec3 point) {
vec3 epsilon = vec3(EPSILON, 0.0, 0.0);
float dx = sdfScene(point + epsilon.xyy) - sdfScene(point - epsilon.xyy);
float dy = sdfScene(point + epsilon.yxy) - sdfScene(point - epsilon.yxy);
float dz = sdfScene(point + epsilon.yyx) - sdfScene(point - epsilon.yyx);
return normalize(vec3(dx, dy, dz));
}
Hit march(Ray ray) {
Hit hit = noHit();
for(int i = 0; i < MAX_STEPS; i++) {
vec3 pivot = ray.origin + ray.direction * hit.distance;
float distance = sdfScene(pivot);
hit.distance += distance;
if(hit.distance > MAXDISTANCE || distance < .1 * TENTH_EPSILON) break;
}
hit.point += ray.origin + ray.direction * hit.distance;
hit.normal = computeNormal(hit.point);
hit.material = sdfTagMaterial(ray, hit.distance, hit.point);
return hit;
}
vec3 bounces(Ray ray) {
Hit hit = noHit();
vec3 absortion[BOUNCES];
vec3 emission[BOUNCES];
int i = 0;
for(i = 0; i < BOUNCES - 1 && hit.distance < MAXDISTANCE; i++) {
shuffle();
//hit = trace(ray);
hit = march(ray);
vec3 diffuse = cosineWeightedRandomHemisphereDirection(hit.normal);
vec3 reflection = reflect(ray.direction, hit.normal);
ray.direction = mix(reflection, diffuse, hit.material.roughness);
ray.origin = hit.point + EPSILON * ray.direction;
emission[i] = hit.material.emissive;
absortion[i] = hit.material.color;
}
vec3 sampled = vec3(0);
for (; i > 0; i--) {
sampled += emission[i - 1];
sampled *= absortion[i - 1];
}
return sampled;
}
void main() {
time = u_time;
initRandom(gl_FragCoord.xy, time);
vec2 viewportPoint = viewport(gl_FragCoord.xy, u_resolution.xy);
vec2 cameraWobble = vec2(
.1 * cos(time * 1.2),
.1 * sin(time * 1.2) + 1.5
);
Camera camera = camera(
vec3(cameraWobble, 2), // position
vec3(0, 0.2, 0.), // target
0.05 * cos(time * 1.2), // roll
u_resolution.xy
);
vec3 color = vec3(0.);
for(int j = 0; j < SAMPLES; j++) {
shuffle();
Ray ray = cameraRay(camera, viewportPoint);
color += bounces(ray);
}
fragColor = vec4(color / float(SAMPLES), 1.0);
}
```
Fourth and last for now, it's late and I'm sleepy, been coding all day.
I'm happy #glostr is working π, and that I learned a bit more of how #nostr works. So powerful.
```glsl
#version 300 es
precision mediump float;
// Original shader:
// Starfield by totetematt
// www.shadertoy.com/view/lcjGWV
uniform vec2 u_resolution;
uniform float u_time;
out vec4 fragColor;
struct Grid {
vec3 id;
float d;
} gr;
#define FBI floatBitsToInt
#define FFBI(a) FBI(cos(a))^FBI(a)
float hash(vec3 uv) {
int x = FFBI(uv.x);
int y = FFBI(uv.y);
int z = FFBI(uv.z);
return float((x * x + y) * (y * y - x) * (z * z + x)) / 2.14e9;
}
void dogrid(vec3 ro, vec3 rd, float size) {
gr.id = (floor(ro + rd * 1E-3) / size + .5) * size;
vec3 src = -(ro - gr.id) / rd;
vec3 dst = abs(.5 * size) / rd;
vec3 bz = src + dst;
gr.d = min(bz.x, min(bz.y, bz.z));
}
vec3 erot(vec3 p, vec3 ax, float t) {
return mix(dot(ax, p) * ax, p, cos(t)) + cross(ax, p) * sin(t);
}
void main() {
vec2 uv = (gl_FragCoord.xy - .5 * u_resolution.xy) / u_resolution.y;
vec3 col = vec3(0.);
vec3 ro = vec3(0.2, 0.2, -5.), rt = vec3(0.);
vec3 z = normalize(rt - ro);
vec3 x = normalize(cross(z, vec3(0., -1., 0.)));
vec3 y = cross(z, x);
vec3 rd = mat3(x, y, z) * normalize(
vec3(uv, 2. + tanh(hash(uv.xyy + u_time) * .5 + 10. * sin(u_time)))
);
float i, e, g;
float gridlen = 0.;
for(i = 0., e = .01, g = 0.; i++<99.;) {
vec3 p = ro + rd * g;
vec3 oop = p;
p = erot(
p,
normalize(sin(u_time * .33 + vec3(.6, .4, .2))), u_time * .2
);
p.z += u_time;
vec3 op = p;
if (gridlen <= g) {
dogrid(p, rd, 1.);
gridlen += gr.d;
}
p -= gr.id;
float gy = dot(sin(gr.id * 2.), cos(gr.id.zxy * 5.));
float rn = hash(gr.id + floor(u_time));
p.x += sin(rn) * .25;
float h = rn > .0 ? .5 : length(p) - .01 - gy * .05 + rn * .02;
g += e = max(.001+op.z*.000002, abs(h));
col += vec3(.25, .25, 1. + abs(rn)) *
(0.025 + (.02 * exp(5. * fract(gy + u_time)))) /
exp(e * e * i);
}
col *= exp(-.08 * g);
fragColor = vec4(sqrt(col), 1.0);
}
```
MOAR #glostr
https://rowdaboat.github.io/glostr/#npub1u3svk99639mcdfn43s2nawg4a2j4ejmgrq2n63l4t67wzqdmtnks2uxaql
```glsl
#version 300 es
precision mediump float;
// Original shader:
// Cyber Fuji by kaiware007
// www.shadertoy.com/view/Wt33Wf
uniform vec2 u_resolution;
uniform float u_time;
out vec4 fragColor;
float sun(vec2 uv, float battery)
{
float val = smoothstep(0.3, 0.29, length(uv));
float bloom = smoothstep(0.7, 0.0, length(uv));
float cut = 3.0 * sin((uv.y + u_time * 0.2 * (battery + 0.02)) * 100.0)
+ clamp(uv.y * 14.0 + 1.0, -6.0, 6.0);
cut = clamp(cut, 0.0, 1.0);
return clamp(val * cut, 0.0, 1.0) + bloom * 0.6;
}
float grid(vec2 uv, float battery)
{
vec2 size = vec2(uv.y, uv.y * uv.y * 0.2) * 0.01;
uv += vec2(0.0, u_time * 4.0 * (battery + 0.05));
uv = abs(fract(uv) - 0.5);
vec2 lines = smoothstep(size, vec2(0.0), uv);
lines += smoothstep(size * 5.0, vec2(0.0), uv) * 0.4 * battery;
return clamp(lines.x + lines.y, 0.0, 3.0);
}
float dot2(in vec2 v ) { return dot(v,v); }
float sdTrapezoid( in vec2 p, in float r1, float r2, float he )
{
vec2 k1 = vec2(r2,he);
vec2 k2 = vec2(r2-r1,2.0*he);
p.x = abs(p.x);
vec2 ca = vec2(p.x-min(p.x,(p.y<0.0)?r1:r2), abs(p.y)-he);
vec2 cb = p - k1 + k2*clamp( dot(k1-p,k2)/dot2(k2), 0.0, 1.0 );
float s = (cb.x<0.0 && ca.y<0.0) ? -1.0 : 1.0;
return s*sqrt( min(dot2(ca),dot2(cb)) );
}
float sdLine( in vec2 p, in vec2 a, in vec2 b )
{
vec2 pa = p-a, ba = b-a;
float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );
return length( pa - ba*h );
}
float sdBox( in vec2 p, in vec2 b )
{
vec2 d = abs(p)-b;
return length(max(d,vec2(0))) + min(max(d.x,d.y),0.0);
}
float opSmoothUnion(float d1, float d2, float k){
float h = clamp(0.5 + 0.5 * (d2 - d1) /k,0.0,1.0);
return mix(d2, d1 , h) - k * h * ( 1.0 - h);
}
float sdCloud(in vec2 p, in vec2 a1, in vec2 b1, in vec2 a2, in vec2 b2, float w)
{
//float lineVal1 = smoothstep(w - 0.0001, w, sdLine(p, a1, b1));
float lineVal1 = sdLine(p, a1, b1);
float lineVal2 = sdLine(p, a2, b2);
vec2 ww = vec2(w*1.5, 0.0);
vec2 left = max(a1 + ww, a2 + ww);
vec2 right = min(b1 - ww, b2 - ww);
vec2 boxCenter = (left + right) * 0.5;
//float boxW = right.x - left.x;
float boxH = abs(a2.y - a1.y) * 0.5;
//float boxVal = sdBox(p - boxCenter, vec2(boxW, boxH)) + w;
float boxVal = sdBox(p - boxCenter, vec2(0.04, boxH)) + w;
float uniVal1 = opSmoothUnion(lineVal1, boxVal, 0.05);
float uniVal2 = opSmoothUnion(lineVal2, boxVal, 0.05);
return min(uniVal1, uniVal2);
}
void main()
{
vec2 uv = (2.0 * gl_FragCoord.xy - u_resolution.xy)/u_resolution.y;
float battery = 1.0;
//if (iMouse.x > 1.0 && iMouse.y > 1.0) battery = iMouse.y / u_resolution.y;
//else battery = 0.8;
//if (abs(uv.x) < (9.0 / 16.0))
{
// Grid
float fog = smoothstep(0.1, -0.02, abs(uv.y + 0.2));
vec3 col = vec3(0.0, 0.1, 0.2);
if (uv.y < -0.2)
{
uv.y = 3.0 / (abs(uv.y + 0.2) + 0.05);
uv.x *= uv.y * 1.0;
float gridVal = grid(uv, battery);
col = mix(col, vec3(1.0, 0.5, 1.0), gridVal);
}
else
{
float fujiD = min(uv.y * 4.5 - 0.5, 1.0);
uv.y -= battery * 1.1 - 0.51;
vec2 sunUV = uv;
vec2 fujiUV = uv;
// Sun
sunUV += vec2(0.75, 0.2);
//uv.y -= 1.1 - 0.51;
col = vec3(1.0, 0.2, 1.0);
float sunVal = sun(sunUV, battery);
col = mix(col, vec3(1.0, 0.4, 0.1), sunUV.y * 2.0 + 0.2);
col = mix(vec3(0.0, 0.0, 0.0), col, sunVal);
// fuji
float fujiVal = sdTrapezoid( uv + vec2(-0.75+sunUV.y * 0.0, 0.5), 1.75 + pow(uv.y * uv.y, 2.1), 0.2, 0.5);
float waveVal = uv.y + sin(uv.x * 20.0 + u_time * 2.0) * 0.05 + 0.2;
float wave_width = smoothstep(0.0,0.01,(waveVal));
// fuji color
col = mix( col, mix(vec3(0.0, 0.0, 0.25), vec3(1.0, 0.0, 0.5), fujiD), step(fujiVal, 0.0));
// fuji top snow
col = mix( col, vec3(1.0, 0.5, 1.0), wave_width * step(fujiVal, 0.0));
// fuji outline
col = mix( col, vec3(1.0, 0.5, 1.0), 1.0-smoothstep(0.0,0.01,abs(fujiVal)) );
//col = mix( col, vec3(1.0, 1.0, 1.0), 1.0-smoothstep(0.03,0.04,abs(fujiVal)) );
//col = vec3(1.0, 1.0, 1.0) *(1.0-smoothstep(0.03,0.04,abs(fujiVal)));
// horizon color
col += mix( col, mix(vec3(1.0, 0.12, 0.8), vec3(0.0, 0.0, 0.2), clamp(uv.y * 3.5 + 3.0, 0.0, 1.0)), step(0.0, fujiVal) );
// cloud
vec2 cloudUV = uv;
cloudUV.x = mod(cloudUV.x + u_time * 0.1, 4.0) - 2.0;
float cloudTime = u_time * 0.5;
float cloudY = -0.5;
float cloudVal1 = sdCloud(cloudUV,
vec2(0.1 + sin(cloudTime + 140.5)*0.1,cloudY),
vec2(1.05 + cos(cloudTime * 0.9 - 36.56) * 0.1, cloudY),
vec2(0.2 + cos(cloudTime * 0.867 + 387.165) * 0.1,0.25+cloudY),
vec2(0.5 + cos(cloudTime * 0.9675 - 15.162) * 0.09, 0.25+cloudY), 0.075);
cloudY = -0.6;
float cloudVal2 = sdCloud(cloudUV,
vec2(-0.9 + cos(cloudTime * 1.02 + 541.75) * 0.1,cloudY),
vec2(-0.5 + sin(cloudTime * 0.9 - 316.56) * 0.1, cloudY),
vec2(-1.5 + cos(cloudTime * 0.867 + 37.165) * 0.1,0.25+cloudY),
vec2(-0.6 + sin(cloudTime * 0.9675 + 665.162) * 0.09, 0.25+cloudY), 0.075);
float cloudVal = min(cloudVal1, cloudVal2);
//col = mix(col, vec3(1.0,1.0,0.0), smoothstep(0.0751, 0.075, cloudVal));
col = mix(col, vec3(0.0, 0.0, 0.2), 1.0 - smoothstep(0.075 - 0.0001, 0.075, cloudVal));
col += vec3(1.0, 1.0, 1.0)*(1.0 - smoothstep(0.0,0.01,abs(cloudVal - 0.075)));
}
col += fog * fog * fog;
col = mix(vec3(col.r, col.r, col.r) * 0.5, col, battery * 0.7);
fragColor = vec4(col,1.0);
}
//else fragColor = vec4(0.0);
}
```
Weee it's working!!
Some clients like Primal are making my url dissapear tho T___T
Watch this shader in action and play with its code at https://rowdaboat.github.io/glostr/#npub1u3svk99639mcdfn43s2nawg4a2j4ejmgrq2n63l4t67wzqdmtnks2uxaql
```glsl
#version 300 es
precision mediump float;
uniform vec2 u_resolution;
uniform float u_time;
out vec4 fragColor;
void main() {
vec2 uv = gl_FragCoord.xy / u_resolution;
fragColor = vec4(
uv.x,
uv.y * sin(u_time * 5.0),
cos(u_time * 5.0),
1.0
);
}
```
How about some glsl shaders on nostr?
Watch this post on #glostr
https://rowdaboat.github.io/glostr/#npub1u3svk99639mcdfn43s2nawg4a2j4ejmgrq2n63l4t67wzqdmtnks2uxaql
```glsl
#version 300 es
precision mediump float;
// Original shader:
// fractal pyramid by bradjamesgrant
// www.shadertoy.com/view/tsXBzS
uniform vec2 u_resolution;
uniform float u_time;
out vec4 fragColor;
vec3 palette(float d){
return mix(vec3(0.2,0.7,0.9),vec3(1.,0.,1.),d);
}
vec2 rotate(vec2 p,float a){
float c = cos(a);
float s = sin(a);
return p*mat2(c,s,-s,c);
}
float map(vec3 p){
for( int i = 0; i<8; ++i){
float t = u_time*0.2;
p.xz =rotate(p.xz,t);
p.xy =rotate(p.xy,t*1.89);
p.xz = abs(p.xz);
p.xz-=.5;
}
return dot(sign(p),p)/5.;
}
vec4 rm (vec3 ro, vec3 rd){
float t = 0.;
vec3 col = vec3(0.);
float d;
for(float i =0.; i<64.; i++){
vec3 p = ro + rd*t;
d = map(p)*.5;
if(d<0.02){
break;
}
if(d>100.){
break;
}
//col+=vec3(0.6,0.8,0.8)/(400.*(d));
col+=palette(length(p)*.1)/(400.*(d));
t+=d;
}
return vec4(col, 1.);//1./(d*100.));
}
void main()
{
vec2 uv = (gl_FragCoord.xy - (u_resolution.xy/2.)) / u_resolution.x;
vec3 ro = vec3(0.,0.,-50.);
ro.xz = rotate(ro.xz,u_time);
vec3 cf = normalize(-ro);
vec3 cs = normalize(cross(cf,vec3(0.,1.,0.)));
vec3 cu = normalize(cross(cf,cs));
vec3 uuv = ro+cf*3. + uv.x*cs + uv.y*cu;
vec3 rd = normalize(uuv-ro);
vec4 col = rm(ro,rd);
fragColor = col;
}
```
Iβm starting to get my code working with this. Iβm already in love with rx-nostr.
#hola nostr:npub1a73m8zj2u2y8ha5v83z0dga9290zhjtjhj3nkdjkgtkas6d2vw3s6dr5h4 π«‘
#hola nostr:npub17agje2sh6u9203uaeyd0h2qvth9nn2675pa34wgwtc7zkr7ugj7qv7v7xf π₯΅