Shader Canvas Hugo Shortcode

A Hugo shortcode to render GLSL in real time on your site

3 minute read

Do you want to add a canvas with a shader running in real time to your Hugo site? In this post I show how to create a Hugo shortcode to display a shader.

You need two ingredients for this recipe:

  1. The glslCanvas Javascript library (single file) originally written for The Book of Shaders website. Save it in your /js directory. Download it with:

    wget https://github.com/patriciogonzalezvivo/glslCanvas/raw/4d5e073bf135692178d7cb62b5cc32dac2dae19f/src/GlslCanvas.js
    

    Then, add js = ["/js/GlslCanvas.js"] to the header of the post/page.

  2. The Hugo shortcode. Paste this in a file named shader.html in /themes/[your-theme]/layouts/shortcodes/:

        <!-- 
        Embed a shader into a webpage. You need to add:
    
        js = ["/js/GlslCanvas.js"]
    
        in the header of the page for this to work.
    
        Attributes:
        - src      - path to the fragment shader
        - width    - width img attribute
        - height   - height img attribute
        - title    - description/caption
        - class    - figure class
        -->
        <figure{{ with .Get "class" }} class="{{ . }}"{{ end }}>
            <canvas class="glslCanvas" 
                  data-fragment-url="{{ .Get "src" }}"
                 {{- with .Get "width" }} width="{{ . }}"{{ end -}}
                 {{- with .Get "height" }} height="{{ . }}"{{ end -}}></canvas>
            {{- if or (or (.Get "title") (.Get "caption")) (.Get "attr") -}}
                <figcaption
                 {{- with .Get "width" }} style="margin: 0 auto; width:{{ . }};"{{ end -}}
                    >
                    {{ with (.Get "title") -}}
                        <h4>{{ . }}</h4>
                    {{- end -}}
                    {{- if or (.Get "caption") (.Get "attr") -}}<p class="fig-attribution">
                        {{- .Get "caption" | markdownify -}}
                        {{- with .Get "attrlink" }}
                            <a href="{{ . }}">
                        {{- end -}}
                        {{- .Get "attr" | markdownify -}}
                        {{- if .Get "attrlink" }}</a>{{ end }}</p>
                    {{- end }}
                </figcaption>
            {{- end }}
        </figure>
    
  3. Once that’s set up, embed your shader in your post, like so:

    {{< shader src="/shader/2024/spiked-star.glsl" 
                 class="fig-center" 
                 width="400" 
                 height="400" 
                 title="A spiked star that changes color and size." >}}
    

That’s it. Run your site and open your browser to admire your shader in all its WebGL splendor. My original implementation for the shader below is in Shadertoy. The actual code used in this website is shown below the canvas.

A spiked star that changes color and size.

Code: spiked-star.glsl
#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

#define SPIKE_WIDTH 0.01
#define CORE_SIZE 0.4

float parabola( float x, float k ){
  return pow( 4.0*x*(1.0-x), k );
}

float cubicPulse( float c, float w, float x ){
  x = abs(x - c);
  if( x>w ) return 0.0;
  x /= w;
  return 1.0 - x*x*(3.0-2.0*x);
}

vec3 starWithSpikes(vec2 uv, vec3 starColor){
  float d = 1.0 - length(uv - 0.5);

  float spikeV = cubicPulse(0.5, SPIKE_WIDTH, uv.x) * parabola(uv.y, 2.0) * 0.5;
  float spikeH = cubicPulse(0.5, SPIKE_WIDTH, uv.y) * parabola(uv.x, 2.0) * 0.5;
  float core = pow(d, 20.0) * CORE_SIZE;
  float corona = pow(d, 6.0);

  float val = spikeV + spikeH + core + corona;
  return vec3(val * (starColor + val));
}

void main() {
  // To normalized pixel coordinates [0,1].
  vec2 uv = gl_FragCoord.xy / u_resolution.x;

  vec3 starColor = vec3(abs(sin(u_time)), 0.1, abs(cos(u_time)));
  vec3 col = starWithSpikes(uv, starColor);

  gl_FragColor = vec4(col,1.0);
}
Website design by myself. See the privacy policy.
Content licensed under CC-BY-NC-SA 4.0 .