Selecting a Random Image at Build Time in Hugo
Sometimes, when searching for “how to do x” on the internet, you’ll come across forum posts that just say “don’t do that” or “that’s not how this is supposed to work”. It’s interesting that, in software, that would be an answer. One of the more recent things like that that I came across was for the static site generator, Hugo, which I use to build this site. I also use it to build the site for my TTRPG group where I keep track of session notes, NPCs, players, items, and world building. I’ve had to do some customization for my purposes and I have also taken it upon myself to bring some of the game into the website. I routinely use Midjourney to generate visuals and portraits to help immerse the players.
Pipes
For one NPC in particular, I want to pick a random portrait out of 8 or so. And I want to do this at build time. Technically, do this in javascript is feasible however I thought it would be interesting to do this at build time–the portrait would change but not too often. This, additionally, allows for the image, in my assets folder, to be processed and resized. As far as I’ve seen, for that to happen the image needs to be used in the build. This is where it gets interesting. The information for this is located on the Hugo Pipes page which, to be honest, is not where I expected to find it.
On this page the information of interest is regarding the resources
… class? Object? It’s the best way to access the items in your assets
folder. This is where my image files are located. using resources.Get
you can grab and resize an image file easily enough:
{{ $resource := resources.Get (.Get "path") }}
{{ $image := $resource.Fit "300x300" }}
<figure style="float: right; max-width: 25%;" >
<img style="max-width: 100%; width: auto; height: auto;" src="{{ $image.RelPermalink }}" >
<figcaption style="text-align: center">
<small>
{{ .Inner }}
</small>
</figcaption>
</figure>
This is how I get my player portraits right now–a partial template called portrait.html
. This partial takes a parameter, called path
and that parameter is passed in the shortcode like this: {{< portrait path="images/npc/fishman.png">}}
. The path here is relative to the site assets
folder so the images
folder is inside of my assets
folder already. Setting the src
attribute of the img
tag to {{ $image.RelPermalink }}
will get Hugo to drop the relative permalink for the asset in there.
Spicing It Up
Variety is the spice of life, they say. I may actually break my website building it for this post so I’m definitely trying to spice up my own life–but what about your audience? Let’s grab a random image using resources.Match
:
{{ $path := resources.Match "images/alric/*.png" }}
I realize that I reused path
, but do as I say not as I do and name it something else. You may recognize that this gives us an array of all the images in images/alric/
with the file extension png
. If we try to pass this to the image
object to resize it and then grab a relative link–we can’t.
I tried various programmerly methodologies that I believe should have worked however, the Go templating world is a little bit different and I don’t think I’ve quite got the hang of it, so I worked around it. I also very well might have the hang of it and this is how it is.
{{ $path := resources.Match "images/alric/*.png" | shuffle }}
{{ range first 1 $path }}
{{ $image := .Fit "300x300" }}
<figure style="float: right; max-width: 25%;" >
<img style="max-width: 100%; width: auto; height: auto;" src="{{ $image.RelPermalink }}" >
</figure>
{{ end }}
So here, I grab the array of images and I pass it into shuffle
to randomize it. I then iterate through exactly 1 image, the first one, and drop it into the page. I named this partial after this one NPC because this isn’t a trick that I intend to repeat but, by passing a parameter, you can use that to dynamically specify resources.Match
and reuse this partial in other places. Now that I mention this, I may end up doing it. But as it sits, this shortcode does not take any parameters or have an Inner value so it’s very barebones.
This character’s portrait has a chance to be different every time the website builds which, if anyone is paying attention, will be an interesting hint. Stay safe and be nice.
./content/posts/selecting-a-random-image-in-hugo.md 9:126 error Punctuation should be inside Microsoft.Quotes the quotes. 9:274 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 9:357 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 9:420 warning Use first person (such as Microsoft.FirstPerson 'my') sparingly. 9:440 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 9:470 error More than 3 commas! marktoso.TresComas 9:552 warning Use first person (such as Microsoft.FirstPerson 'my') sparingly. 9:567 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 9:610 warning Consider using 'some' instead Microsoft.Wordiness of 'some of the'. 9:644 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 13:80 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 13:168 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 13:278 error More than 3 commas! marktoso.TresComas 13:319 warning Use first person (such as Microsoft.FirstPerson 'my') sparingly. 13:608 error Use 'isn't' instead of 'is Microsoft.Contractions not'. 13:620 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 15:70 warning In general, don't use an Microsoft.Ellipses ellipsis. 15:166 warning Use first person (such as Microsoft.FirstPerson 'my') sparingly. 15:254 warning Consider removing 'easily'. Microsoft.Adverbs 30:12 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 30:19 warning Use first person (such as Microsoft.FirstPerson 'my') sparingly. 30:381 warning Use first person (such as Microsoft.FirstPerson 'my') sparingly. 33:40 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 33:62 warning Use first person (such as Microsoft.FirstPerson 'my') sparingly. 33:102 warning Use first person (such as Microsoft.FirstPerson 'I'm') sparingly. 33:136 warning Use first person (such as Microsoft.FirstPerson 'my') sparingly. 33:181 warning Try to avoid using Microsoft.We first-person plural like 'Let's'. 38:1 warning Use first person (such as 'I Microsoft.FirstPerson ') sparingly. 38:15 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 38:42 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 38:55 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 38:123 warning Try to avoid using Microsoft.We first-person plural like 'us'. 38:206 warning Try to avoid using Microsoft.We first-person plural like 'we'. 38:292 warning Try to avoid using Microsoft.We first-person plural like 'we'. 40:1 warning Use first person (such as 'I Microsoft.FirstPerson ') sparingly. 40:48 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 40:140 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 40:188 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 40:208 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 40:216 warning Consider removing 'very'. Microsoft.Adverbs 40:268 error Use 'it's' instead of 'it is'. Microsoft.Contractions 51:40 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 51:236 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 51:391 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 51:407 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 51:462 error Use 'doesn't' instead of 'does Microsoft.Contractions not'. 51:522 warning Consider removing 'very'. Microsoft.Adverbs 56:210 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly.✖ 6 errors, 42 warnings and 0 suggestions in 1 file.