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 1:1 suggestion You averaged 1.36 complex marktoso.Kiss words per sentence 9:1 suggestion Try to keep sentences short (< Microsoft.SentenceLength 30 words). 9:126 error Punctuation should be inside Microsoft.Quotes the quotes. 9:147 suggestion 'is supposed' looks like Microsoft.Passive passive voice. 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:423 suggestion 'TTRPG' has no definition. Microsoft.Acronyms 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:9 suggestion 'NPC' has no definition. Microsoft.Acronyms 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:294 suggestion Verify your use of 'allows' Microsoft.Vocab with the A-Z word list. 13:319 warning Use first person (such as Microsoft.FirstPerson 'my') sparingly. 13:340 suggestion 'be processed' looks like Microsoft.Passive passive voice. 13:425 suggestion 'be used' looks like passive Microsoft.Passive voice. 13:507 suggestion 'is located' looks like Microsoft.Passive passive voice. 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:181 suggestion 'are located' looks like Microsoft.Passive passive voice. 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:199 suggestion 'is passed' looks like passive Microsoft.Passive voice. 30:381 warning Use first person (such as Microsoft.FirstPerson 'my') sparingly. 32:4 suggestion 'Spicing It Up' should use Microsoft.Headings sentence-style capitalization. 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:1 suggestion Try to keep sentences short (< Microsoft.SentenceLength 30 words). 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:10 suggestion Try to keep sentences short (< Microsoft.SentenceLength 30 words). 51:40 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 51:201 suggestion 'NPC' has no definition. Microsoft.Acronyms 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:40 suggestion 'was checked' looks like Microsoft.Passive passive voice. 56:146 suggestion 'was checked' looks like Microsoft.Passive passive voice. 56:184 suggestion Verify your use of 'as well Microsoft.Vocab as' with the A-Z word list. 56:210 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 56:284 suggestion 'was put' looks like passive Microsoft.Passive voice.✖ 6 errors, 42 warnings and 19 suggestions in 1 file.