xesite/blog/site-update-hero-images.mar...

102 lines
4.5 KiB
Markdown
Raw Normal View History

---
title: "Site Update: Hero Images"
date: 2022-06-08
---
For a while I've been wondering how I can add dramatic flair to my website with
so-called "hero images". These images are tools that let you describe the mood a
website wants to evoke. I've been unsure how to best implement these on my
website for a while, but with the advent of MidJourney and other image
generation APIs/algorithms I think I have found a way to create these without
too much effort on my part and the results are pretty fantastic:
<xeblog-hero file="secret-to-life" prompt="the secret to life, the universe and everything, concept art"></xeblog-hero>
I have generated a bunch of other images that I'm going to use for my other
posts. I'll give out a desktop wallpaper sized version of each of these images
on my [Patreon](https://patreon.com/cadey).
Under the hood this is powered by
[lol_html](https://github.com/cloudflare/lol-html) and
[Maud](https://maud.lambda.xyz/). The magic is mostly contained in a function
that generates a `<figure>` HTML element (which I just learned exists today). I
use a function that looks like this for generating the `<xeblog-hero>` snippets:
```rust
pub fn xeblog_hero(file: String, prompt: Option<String>) -> Markup {
html! {
figure.hero style="margin:0" {
picture style="margin:0" {
source type="image/avif" srcset={"https://cdn.xeiaso.net/file/christine-static/hero/" (file) ".avif"};
source type="image/webp" srcset={"https://cdn.xeiaso.net/file/christine-static/hero/" (file) ".webp"};
img style="padding:0" alt={"hero image " (file)} src={"https://cdn.xeiaso.net/file/christine-static/hero/" (file) "-smol.png"};
}
figcaption { "Image generated by MidJourney" @if let Some(prompt) = prompt { " -- " (prompt) } }
}
}
}
```
I have it wired up with lol_html like this:
```rust
lol_html::element!("xeblog-hero", |el| {
let file = el.get_attribute("file").expect("wanted xeblog-hero to contain file");
el.replace(&crate::tmpl::xeblog_hero(file, el.get_attribute("prompt")).0, ContentType::Html);
Ok(())
})
```
The result is that I can declare hero images with HTML fragments like this:
```html
<xeblog-hero file="miku-dark-souls" prompt="hatsune miku, elden ring, dark souls, concept art, crowbar"></xeblog-hero>
```
And I get this:
<xeblog-hero file="miku-dark-souls" prompt="hatsune miku, elden ring, dark souls, concept art, crowbar"></xeblog-hero>
<xeblog-conv name="Mara" mood="hacker">This is powered by the
[`<figure>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/figure)
tag, which is a new discovery to us. This is probably one of the most useful
tags we never knew about and removed the need to write a bunch of annoying CSS
and HTML.</xeblog-conv>
The webp and AVIF versions of the hero images have a higher resolution version
so that it looks nicer on retina screens. However, the png versions of these are
locked to a resolution of 800x356 pixels because I was unable to crush them
below a size of half a megabyte at full resolution. Realistically, this should
only affect older browsers on slower hardware, so I don't expect this to have
too much impact on most users.
<xeblog-conv name="Cadey" mood="coffee">If you don't want to see these hero
images, you can remove them with a userstyle like this:
```css
figure.hero {
display: none;
}
```
</xeblog-conv>
I'm likely going to convert over most of my website templates to use Maud. I'm
very happy with it and I think it is incredibly useful to express your HTML in
Rust instead of something that has to be compiled to Rust. In practice it
reminds me of the Nim library [emerald](http://flyx.github.io/emerald/), which
lets you write HTML using Nim functions similar to how you use Maud.
Here's a few more examples of hero images I have generated:
<xeblog-hero file="the-forbidden-shape" prompt="the forbidden shape"></xeblog-hero>
<xeblog-hero file="great-wave-cyberpunk" prompt="the great wave off of kanagawa, cyberpunk, hanzi inscription"></xeblog-hero>
Normally I will only have one image per post and it will usually be after the
introduction paragraph. The prompt will usually be related to the article topic,
but sometimes I will take artistic liberty. If you have suggestions for prompts,
please [contact me](/contact) with those ideas.
I hope these updates on how I've been messing with my site are interesting. I'm
trying to capture the spirit of how I'm implementing these changes as well as
details of how everything fits together.