Jostar Shader

A shader inspired by a background I saw on Twitter by jostar. I hope you like it and find it super useful for your Godot projects!

This shader creates a “sharp teeth” or “jaw” closing effect over a scrolling grid background. It features independent speed controls for the top and bottom rows, as well as automatic aspect ratio correction to ensure the grid always stays perfectly square.

How to use:

  1. Create a ColorRect and set its layout to “Full Rect”.

  2. Add a new ShaderMaterial and paste the code.

  3. Use an AnimationPlayer to animate cierre_picos from 0.0 (open) to 1.0 (closed) for a smooth transition.

 

Parameter Type Range / Default Description
Colors      
color_fondo Color RGB The base background color behind the teeth.
color_linea Color RGBA The color of the grid lines (use Alpha for transparency).
color_picos Color RGB The color of the “jaw” or teeth (usually black).
Grid Settings      
tamano_cuadros Float 0.01 to 0.5 Controls the scale of the grid squares.
grosor_linea Float 0.0 to 0.1 The thickness of the lines forming the grid.
velocidad_fondo Vec2 (X, Y) Direction and speed of the scrolling background.
rotacion_cuadricula Float 0 to 360 Rotates the grid while maintaining perfect squares.
Teeth Settings      
cantidad_picos Float 1 to 50 Number of teeth visible across the screen.
vel_picos_arriba Float -10 to 10 Horizontal speed and direction for the top row.
vel_picos_abajo Float -10 to 10 Horizontal speed and direction for the bottom row.
inclinacion_punta Float 0.1 to 0.9 Peak Angle: 0.5 is a perfect triangle, others tilt the teeth.
intensidad_picos Float 0.0 to 1.2 The length/height of the teeth towards the center.
cierre_picos Float 0.0 to 1.0 Transition Control: 0.0 is open, 1.0 is fully closed.
rotacion_picos Float -180 to 180
Shader code
shader_type canvas_item;

// configuracion de colore
group_uniforms Colores;
uniform vec4 color_fondo : source_color = vec4(0.15, 0.25, 0.35, 1.0);
uniform vec4 color_linea : source_color = vec4(1.0, 1.0, 1.0, 0.15);
uniform vec4 color_picos : source_color = vec4(0.0, 0.0, 0.0, 1.0);

// opcione de cuadro
group_uniforms Cuadricula;
uniform float tamano_cuadros : hint_range(0.01, 0.5) = 0.05;
uniform float grosor_linea : hint_range(0.0, 0.1) = 0.005;
uniform vec2 velocidad_fondo = vec2(0.1, 0.05); 
uniform float rotacion_cuadricula : hint_range(0.0, 360.0) = 0.0;

// oico
group_uniforms Picos;
uniform float cantidad_picos : hint_range(1.0, 50.0) = 12.0;
uniform float vel_picos_arriba : hint_range(-10.0, 10.0) = 1.5;
uniform float vel_picos_abajo : hint_range(-10.0, 10.0) = -1.5;

uniform float inclinacion_punta : hint_range(0.1, 0.9) = 0.5; 
uniform float intensidad_picos : hint_range(0.0, 1.2) = 0.4;
uniform float cierre_picos : hint_range(0.0, 1.0) = 0.0;
uniform float rotacion_picos : hint_range(-180.0, 180.0) = 0.0;

vec2 rotate_uv(vec2 uv, float degrees, float aspect) {
    float rad = radians(degrees);
    mat2 rotation_matrix = mat2(
        vec2(cos(rad), -sin(rad)),
        vec2(sin(rad), cos(rad))
    );
    vec2 p = uv - vec2(0.5 * aspect, 0.5);
    p = rotation_matrix * p;
    return p + vec2(0.5 * aspect, 0.5);
}

void fragment() {
    float aspect = (1.0 / SCREEN_PIXEL_SIZE).x / (1.0 / SCREEN_PIXEL_SIZE).y;
    vec2 uv_screen = vec2(UV.x * aspect, UV.y);

    vec2 uv_grid = rotate_uv(uv_screen, rotacion_cuadricula, aspect);
    uv_grid += TIME * velocidad_fondo;
    
    vec2 grid_pos = abs(mod(uv_grid, tamano_cuadros) - (tamano_cuadros * 0.5));
    float grid_line = max(
        step(grid_pos.x, tamano_cuadros * grosor_linea),
        step(grid_pos.y, tamano_cuadros * grosor_linea)
    );
    
    vec4 background_layer = mix(color_fondo, color_linea, grid_line * color_linea.a);

    // no entiendo bien que hacer para que no se redondeen los picos pipi
    vec2 uv_picos = rotate_uv(uv_screen, rotacion_picos, aspect);
    float x_base = (uv_picos.x / aspect) * cantidad_picos;
    
  
    float rampa_arriba = fract(x_base + (TIME * vel_picos_arriba));
    float forma_arriba = (rampa_arriba < inclinacion_punta) ? (rampa_arriba / inclinacion_punta) : ((1.0 - rampa_arriba) / (1.0 - inclinacion_punta));
    float rampa_abajo = fract(x_base + (TIME * vel_picos_abajo));
    float forma_abajo = (rampa_abajo < inclinacion_punta) ? (rampa_abajo / inclinacion_punta) : ((1.0 - rampa_abajo) / (1.0 - inclinacion_punta));
    
    float closure_offset = cierre_picos * 0.5;
    float upper_limit = (forma_arriba * intensidad_picos * (1.0 - cierre_picos)) + closure_offset;
    float lower_limit = 1.0 - (forma_abajo * intensidad_picos * (1.0 - cierre_picos)) - closure_offset;

    // visivilidad
    float visibility_mask = step(upper_limit, uv_picos.y) * step(uv_picos.y, lower_limit);

    COLOR = mix(color_picos, background_layer, visibility_mask);
}
Live Preview
Tags
Closing, Geometry, grid, Jaw, Sharp, transition, ui
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from Gerardo LCDF

Related shaders

guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments