Compare commits

...

121 Commits

Author SHA1 Message Date
3c3b74a571 Add posts 2025-03-28 20:36:05 -05:00
28f58173bd Update /tags/ header 2025-03-28 20:35:56 -05:00
c123c068e3 Update changelog 2025-03-28 20:35:48 -05:00
3c67472adc Update blogroll 2025-03-28 20:35:40 -05:00
94ec8fa443 Update blogroll and wish pages 2025-03-12 11:05:25 -05:00
bdb4dbc46e Add masto ID 2025-02-22 19:13:24 -06:00
c38cb78b05 Add Maroma article 2025-02-22 19:10:27 -06:00
857f856e05 Update /wish 2025-02-21 10:08:42 -06:00
2b59cd2475 Update /wish 2025-02-20 12:12:08 -06:00
92638b30af Update blogroll 2025-02-17 11:39:46 -06:00
457c905ba7 Add masto id 2025-02-14 00:27:28 -06:00
860cfc8d8c Add article, minor fixes 2025-02-14 00:22:43 -06:00
e43efcaed8 Update /me 2025-02-11 16:12:36 -06:00
f4b0dff348 Fix my goddamn blogroll 2025-02-07 16:39:53 -06:00
b9124f18ab Add friendica to /me 2025-02-06 10:14:55 -06:00
bd05208aee Deprecate cowsay of the day 2025-02-06 10:14:38 -06:00
a25d8ef163 Update changelog 2025-02-04 18:43:36 -06:00
2de19c8882 Fix typo 2025-02-04 18:43:27 -06:00
793b6482b2 Re-implement open graph etc 2025-02-04 18:42:57 -06:00
9e62744415 Add article 2025-02-04 18:42:36 -06:00
a915341e5c Big update: add quiz function, new post 2025-02-02 17:40:57 -06:00
a98006f918 Fix buttonContainer issue 2025-01-24 15:35:43 -06:00
8bbb071a34 Update README 2025-01-24 14:28:40 -06:00
de0e840578 Fix another XML issue 2025-01-24 14:27:03 -06:00
35367c5b6f Update changelog 2025-01-24 14:26:47 -06:00
8a78ee2b9f Improve now page 2025-01-24 14:20:16 -06:00
ec4c5d259b Fix xsl error
How dare I try to use an <hr>?!
2025-01-24 14:05:00 -06:00
1c3ab2d1fb Fix button margin 2025-01-24 13:47:10 -06:00
a9acf53d90 Fix link 2025-01-24 13:39:47 -06:00
5c117de06f Add gallery to index. 2025-01-23 15:34:14 -06:00
54797ddb2b Add gallery 2025-01-23 15:33:59 -06:00
153b178c40 UI updates 2025-01-23 14:24:51 -06:00
ef37d7622d Update changelog 2025-01-23 14:23:00 -06:00
7c06d746d4 Styling tweaks 2025-01-23 14:22:51 -06:00
a2dd293bf0 Update wishlist 2025-01-23 14:22:35 -06:00
aaae71adf9 Deprecate comment embedding in favor of button 2025-01-23 14:21:53 -06:00
f758f1c973 Change postlist header 2025-01-23 14:20:46 -06:00
4a4b2464da Re-size post image 2025-01-23 14:20:24 -06:00
7063473cd7 Add entry to blogroll 2025-01-23 14:20:08 -06:00
9defa3baf2 Add now entry 2025-01-23 14:19:42 -06:00
b83e4132ee Add post 2025-01-23 14:19:33 -06:00
c615de4b0b Add "essays" tag 2024-12-18 23:15:34 -06:00
e8185fb3a7 Add post 2024-12-18 23:15:20 -06:00
6e21b47f30 Update changelog 2024-12-16 23:44:36 -06:00
78f6392e87 Update peertube instance 2024-12-16 23:44:22 -06:00
e3c6a95680 Add mastodon ID to post 2024-12-16 23:41:50 -06:00
0e22c8028f Add article 2024-12-16 23:33:21 -06:00
3244e9a889 Update peertube urls 2024-12-16 23:33:11 -06:00
39ee777d1b Add entry to blogroll 2024-12-15 18:42:48 -06:00
c935223848 Add link to site stats 2024-12-15 15:31:16 -06:00
5b46c84afb Add /wish 2024-12-14 20:20:33 -06:00
b0106e6666 A heap of changes, whoops 2024-12-11 13:15:47 -06:00
7bdc97f0c6 change 2024-12-09 20:42:03 -06:00
12558a1a2d Small, unimportant change 2024-12-09 20:40:43 -06:00
1e1df2fb4b Update synopsis 2024-12-09 20:34:01 -06:00
c060e0efb7 Add article 2024-12-09 20:32:34 -06:00
82d1c3cd67 Figure styling for video embeds 2024-12-09 20:32:25 -06:00
fe242632d6 Add new tags 2024-12-09 20:32:05 -06:00
ea264309f7 Type fix 2024-12-03 19:11:25 -06:00
7916f91751 Update post 2024-12-02 18:36:12 -06:00
115c9497df Add post 2024-12-02 18:32:37 -06:00
686239ea03 Implement image galleries 2024-12-02 17:42:20 -06:00
51a1693265 Minor tweaks to h3 and sup 2024-11-12 18:47:17 -06:00
0ad1596646 Add black metal article 2024-11-12 18:47:00 -06:00
11b4d84044 Add loops link to /me 2024-11-12 12:47:28 -06:00
e7ebe8d22d Tweak link button styling 2024-11-12 12:47:08 -06:00
09a3a32a83 Update blogroll 2024-11-11 10:20:18 -06:00
82db6b1ba2 Allow unescaped HTML markup in blogroll descriptions 2024-11-11 10:20:08 -06:00
8849f10e88 Add Inverse 2024-11-05 11:09:36 -06:00
00be4291f2 Add The Pudding to blogroll 2024-10-25 13:08:43 -05:00
5cc54bf34e Add animal justice blog feed 2024-10-24 10:44:48 -05:00
fbff81a7da Update Kate Editor link 2024-10-24 10:42:27 -05:00
9fbf30bf16 Add Ed Zitron to blogroll 2024-10-24 10:42:16 -05:00
41ae3fc47b Add Liberation News to blogroll 2024-10-24 10:36:52 -05:00
68a7454e72 New post 2024-10-23 23:26:04 -05:00
8ad99a35d4 Add audio embed feature 2024-10-23 22:40:08 -05:00
a908843984 Add audio embed feature 2024-10-23 22:39:32 -05:00
bfdb9f8419 Update /me 2024-10-23 18:19:12 -05:00
a7ec4e9335 Add now post 2024-10-06 19:04:23 -05:00
c6ea0176a3 Add <strong> styling for <figcaption> 2024-10-06 18:30:28 -05:00
bdcda7f2db Fix blog name 2024-09-30 06:34:08 -05:00
5d475f4bf3 Add new post 2024-09-29 15:10:57 -05:00
0fbfbc0b78 Fix link 2024-09-26 10:13:07 -05:00
cb8999f50a Add some feeds to the blogroll 2024-09-25 13:51:55 -05:00
d0a1785f23 Add link to opml per opml.org 2024-09-25 13:26:18 -05:00
f3c58d09da Update .gitignore 2024-09-25 13:25:40 -05:00
7095d8850b Tidy up, style blogroll 2024-09-25 13:06:12 -05:00
0284950ba5 Add about/privacy 2024-09-25 13:05:10 -05:00
7754b310c3 Add /about/colophon 2024-09-25 13:05:01 -05:00
4add841e55 Add base in which <p> spans all columns by default 2024-09-25 13:04:41 -05:00
3ff627cdc8 Remove netlify.toml as I don't use netlify 2024-09-25 13:03:53 -05:00
b7e997515e Update buttons on index 2024-09-25 13:03:36 -05:00
75aa8e4a33 Add category 2024-09-25 13:03:14 -05:00
fb06d54ea5 Add buttons to /blog/ 2024-09-25 13:03:01 -05:00
cb33208e54 Add blogroll features 2024-09-25 13:02:36 -05:00
6328a531a7 Add sitemap page for humans 2024-09-25 13:01:59 -05:00
1ba8841d32 Update /about/ copy 2024-09-25 13:01:29 -05:00
bc18e89d8d Update README with blogroll and opml feature 2024-09-25 13:00:42 -05:00
f8610fe915 Update license copyright year 2024-09-25 13:00:18 -05:00
b4c2a76949 Add post 2024-09-21 18:00:09 -05:00
a44a1c4431 Update default post image 2024-09-21 17:59:58 -05:00
5bf446c5c2 Fix typo 2024-09-21 17:59:42 -05:00
5e324f2afd Nest some stuff 2024-09-21 17:59:28 -05:00
dd2c327613 Fix footnote hr selector 2024-09-20 23:59:01 -05:00
21b66dd28f Style footnotes 2024-09-20 23:57:00 -05:00
6dc2db4c52 Fix prettier config 2024-09-20 23:55:41 -05:00
acb55c80a1 Move punctuation after links 2024-09-20 23:55:16 -05:00
2cf0c6ce1d Add post 2024-09-20 23:54:51 -05:00
d328e79da9 metadata tweak 2024-08-23 17:40:12 -05:00
34c37f37e1 Minor page updates 2024-08-23 17:33:33 -05:00
3ec15ed8e2 Tweaks to structured data 2024-08-23 17:33:22 -05:00
5389651b27 add masto id 2024-08-20 17:52:49 -05:00
afd8a3ca6e stuff 2024-08-20 17:49:47 -05:00
3cf4345042 Add post 2024-08-20 17:49:32 -05:00
c153a2a60d Abandon hope of getting 11ty image plugin working 2024-08-19 18:24:11 -05:00
7c40b754db Update matrix user 2024-08-19 12:43:16 -05:00
4a476a0207 Prevent layout shift 2024-08-13 23:07:16 -05:00
21377ff19f Ensure text visibility while fonts load 2024-08-13 22:47:47 -05:00
092c806226 Fix active page li color 2024-08-13 22:46:19 -05:00
c5121f01ca Fix accessibility issue
Fix <li> inside <a> so screenreader can parse nav
2024-08-13 22:34:00 -05:00
d64b6e15cd Merge pull request 'Blah' (#3) from responsive-images into main
Reviewed-on: #3
2024-08-13 22:58:26 -04:00
200 changed files with 5620 additions and 535 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
_site/
node_modules/
package-lock.json
.kateproject.notes

View File

@ -1,20 +1,13 @@
TODO:
Integrate est. read time
Integrate % done in article
Investigate pagination for /blog/
Integrate recipe structured data for recipe type articles
No line breaks in inline code fences
Style inline code fences with background
Integrate ins plugin
Fediring?
Add "Now" to RSS feed.
Performance / Accessibility:
---------------------------------------
Lazy load images
Remove unecessary fonts
change font-display to "swap"
Caching
Add explicit image dimensions?

View File

@ -1,6 +1,6 @@
GPL3 License
Copyright (c) 2023 Nathan Upchurch
Copyright (c) 2023-2024 Nathan Upchurch
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -11,7 +11,7 @@ My blog, originally based on the very helpful eleventy-base-blog v8, although it
### Fediverse Integration
* Mastodon [toot embedding](https://upchur.ch/gitea/n_u/nathanupchurch.com/wiki/Home#embed-a-toot-from-mastodon-using-the-toot-shortcode)
* [Commenting](https://upchur.ch/gitea/n_u/nathanupchurch.com/wiki/Home#adding-comments-via-mastodon) via Mastodon
* Link to post discussion on Mastodon
### Indieweb
* [Auto-generated linktree-style page](https://upchur.ch/gitea/n_u/nathanupchurch.com/wiki#me) for the blog owner with support for custom attributes such as: `rel="me"`
@ -20,18 +20,14 @@ My blog, originally based on the very helpful eleventy-base-blog v8, although it
* All blog posts
* Each individual tag
* /now page that nicely handles posts tagged with "now"
* Blogroll generated from _data/blogroll.js, with an automatically updated .opml so that visitors can import every blog in the list
* Image galleries
### Technical
* Reusable web components:
* Card
* Mastodon comment
* Profile picture
* Embedded toot
### Fun
* Image galleries
* Quizzes
### Quality of Life
* Copyright notice, default post image, alt text, and author details defined in `metadata.js`.
* "Read Next" highlighting the previous blog post at the bottom of every post
* robots.txt tells AI scrapers to GTFO
### Weird and Wonderful
* [Accessible cowsay output embedding](https://upchur.ch/gitea/n_u/nathanupchurch.com/wiki#add-a-cowsay-to-a-post)

715
_data/blogroll.js Normal file
View File

@ -0,0 +1,715 @@
export default {
categories: [
{
name: "Climate Change",
blogs: [
{
title: "Grist",
feedUrl: "https://grist.org/feed/",
url: "https://grist.org/",
description:
'Grist is dedicated to highlighting climate solutions and uncovering environmental injustices. (Thanks to <a href="https://werd.io/2024/non-profit-newsrooms-that-speak-to-power">werd.io</a> for the recommendation.)',
},
],
},
{
name: "Comics",
blogs: [
{
title: "Incidental Comics",
feedUrl:
"http://www.incidentalcomics.com/feeds/posts/default?alt=rss",
url: "http://www.incidentalcomics.com",
description: "Nice comics about words, et cetera.",
},
{
title: "XKCD",
feedUrl: "https://xkcd.com/rss.xml",
url: "https://xkcd.com",
description: "Does XKCD needs an introduction?",
},
],
},
{
name: "Design",
blogs: [
{
title: "Adam Silver",
feedUrl: "https://adamsilver.io/atom.xml",
url: "https://adamsilver.io/",
description:
"Adam Silver is a designer and frontend engineer from London, UK.",
},
{
title: "Autumn Kotsiuba",
feedUrl: "https://autumnkotsiuba.wixsite.com/portfolio/blog-feed.xml",
url: "https://autumnkotsiuba.wixsite.com",
description: "Autumn blogs about UX content design.",
},
{
title: "Abduzeedo",
feedUrl: "https://abduzeedo.com/rss.xml",
url: "https://abduzeedo.com/",
description:
"Abduzeedo is a collective of individual writers sharing articles about design, photography, and UX. It was founded by Fabio Sasso in 2006 as a personal blog, later growing to become a digital publication with several writers from all over the world, working independently.",
},
{
title: "Admire the Web",
feedUrl:
"https://feeds.feedburner.com/AdmireTheWeb-TheVeryBestWebDesignInspiration",
url: "https://admiretheweb.com/",
description: "Web design inspiration.",
},
{
title: "Alphabettes",
feedUrl: "https://www.alphabettes.org/feed/",
url: "https://www.alphabettes.org/",
description:
"Alphabettes.org is a showcase for work, commentary, and research on lettering, typography, and type design. Our loose network is here to support and promote the work of all women and nonbinary people in our fields.",
},
{
title: "Creative Review",
feedUrl: "https://www.creativereview.co.uk/feed/",
url: "https://www.creativereview.co.uk/",
description:
"Creative Review has been bringing the creative community together since 1980, first as a print magazine and now across more platforms than ever.",
},
{
title: "Dave Smyth",
feedUrl: "https://davesmyth.com/commonplace-feed",
url: "https://davesmyth.com",
description:
"Dave Smyth is a designer and developer interested in privacy, type and ethics.",
},
{
title: "Design By Women",
feedUrl: "https://designby-women.com/feed/",
url: "https://designby-women.com/",
description:
"Founded by graphic designer Mary Hemingway in June 2020, Design by Women aims to showcase and celebrate women, gender expansive and gender non-conforming creatives currently working in the design industry and to inspire emerging under-represented creatives to pursue a career in design.",
},
{
title: "DIELINE",
feedUrl: "https://thedieline.com/feed/",
url: "https://thedieline.com/",
description:
"DIELINE is a creative platform dedicated to serving the global packaging community.",
},
{
title: "Friends of Type",
feedUrl: "https://friendsoftype.com/feed/",
url: "https://friendsoftype.com/feed/",
description:
"Friends of Type features original typographic design and lettering fresh visual content practically every day.",
},
{
title: "Grumpy Website",
feedUrl: "https://grumpy.website/feed.xml",
url: "https://grumpy.website",
description: "Grumpy takes on UI mistakes.",
},
{
title: "Identity Designed",
feedUrl: "https://identitydesigned.com/feed/",
url: "https://identitydesigned.com/",
description:
"Identity Designed is a website and book series devoted to the design of visual identities.",
},
{
title: "It's Nice That",
feedUrl: "http://feeds2.feedburner.com/itsnicethat/SlXC",
url: "https://www.itsnicethat.com/",
description:
"Our mission is to inspire the global creative community. We share stories, offer insights and bring people together to help them make more of their creativity.",
},
{
title: "I Love Typography",
feedUrl: "https://ilovetypography.com/feed",
url: "https://ilovetypography.com/",
description: "Talking about type.",
},
{
title: "Jamie Clarke Type",
feedUrl: "https://jamieclarketype.com/rss.xml",
url: "https://jamieclarketype.com",
description:
"Im an independent type designer and lettering artist based near Bristol, UK. I draw letters for clients worldwide and have almost three decades of experience as a designer and typographer.",
},
{
title: "Libre Arts",
feedUrl: "https://librearts.org/index.xml",
url: "https://librearts.org",
description: "News on FLOSS creative software.",
},
{
title: "Logo Design Love",
feedUrl: "https://www.logodesignlove.com/feed",
url: "https://www.logodesignlove.com/",
description:
"Logo Design Love is a website and book devoted to logos, symbols, icons, and marks.",
},
{
title: "PRINT Magazine",
feedUrl: "https://www.printmag.com/feed/",
url: "https://www.printmag.com/",
description:
"Where creative people gather to inspire and build design dialogue.",
},
{
title: "Print.pm",
feedUrl: "https://print.pm/rss",
url: "https://print.pm/",
description: "Daily inspiration for print lovers.",
},
{
title: "Siteinspire",
feedUrl: "https://www.siteinspire.com/websites/feed",
url: "https://www.siteinspire.com/",
description: "A showcase of the webs finest design + talent.",
},
{
title: "The Design Blog",
feedUrl: "https://thedsgnblog.com/rss",
url: "https://thedsgnblog.com",
description:
"The Design Blog is a carefully curated platform for design and creative inspiration featuring works of designers, studios, and creatives from around the world.",
},
{
title: "TypeOff.",
feedUrl: "https://www.typeoff.de/rss",
url: "https://www.typeoff.de",
description:
"A blog from Dan Reynolds, a design researcher based in Wuppertal, Germany.",
},
{
title: "UX Daily",
feedUrl: "https://www.interaction-design.org/rss/site_news.xml",
url: "https://www.interaction-design.org",
description: "The Worlds Largest Free Online Resource on UX Design.",
},
{
title: "Visuelle",
feedUrl: "https://visuelle.co.uk/feed/",
url: "https://visuelle.co.uk",
description:
"Graphic Design and everything in between. Curated by David Bennett Creative Director at opx.studio.",
},
],
},
{
name: "Food & Beverage",
blogs: [
{
title: "Cocktail Doodle",
feedUrl: "https://cocktaildoodle.substack.com/feed",
url: "https://cocktaildoodle.substack.com",
description:
"A charming (but perhaps abandoned) blog from cocktail expert Luke Andrews.",
},
{
title: "Sarah's Vegan Kitchen",
feedUrl: "https://sarahsvegankitchen.com/feed/",
url: "https://sarahsvegankitchen.com",
description:
"Sarah has years of recipes including complex staples like vegan cultured butter.",
},
],
},
{
name: "General Interest",
blogs: [
{
title: "Big Think",
feedUrl: "https://bigthink.com/feed",
url: "https://bigthink.com",
description: "Big thoughts on big issues.",
},
{
title: "Clients from Hell",
feedUrl: "https://notalwaysright.com/tag/clients-from-hell/feed",
url: "https://notalwaysright.com/tag/clients-from-hell",
description:
"Cathartic stories about clients behaving badly from notalwaysright.com.",
},
{
title: "kottke.org",
feedUrl: "https://feeds.kottke.org/main",
url: "https://kottke.org",
description: "Home of fine hypertext products since 1998.",
},
{
title: "Neatorama",
feedUrl: "https://www.neatorama.com/feed",
url: "https://www.neatorama.com/",
description: "Yep, Neatorama's still around!",
},
{
title: "The Pudding",
feedUrl: "https://pudding.cool/rss.xml",
url: "https://pudding.cool",
description:
"The Pudding is a digital publication that explains ideas debated in culture with visual essays.",
},
{
title: "The Reframe",
feedUrl: "https://www.the-reframe.com/rss/",
url: "https://www.the-reframe.com/",
description:
"Essays on politics and narrative fiction from A.R. Moxon.",
},
{
title: "Webcurios",
feedUrl: "https://webcurios.co.uk/feed",
url: "https://webcurios.co.uk",
description:
"A regular(-ish) newsletterblogtypething all about stuff on the internet that its author finds interesting and thinks you might too.",
},
],
},
{
name: "Health",
blogs: [
{
title: "ADDitude",
feedUrl: "https://www.additudemag.com/feed/",
url: "https://www.additudemag.com/",
description:
"The worlds most trusted resource for families and adults living with ADHD and related conditions, and for the professionals who work with them.",
},
{
title: "The Gauntlet",
feedUrl: "https://www.thegauntlet.news/feed",
url: "https://www.thegauntlet.news",
description:
"A newsletter covering the current science on, and commentary related to, the unmitigated spread of COVID.",
},
],
},
{
name: "Incense, Fragrance, and Perfumery",
blogs: [
{
title: "Apothecary's Garden Blog",
feedUrl: "https://apothecarysgarden.com/blogs/blog.atom",
url: "https://apothecarysgarden.com/blogs/blog",
description:
"Explore the world of natural aromatics, and the communities that bring them to us.",
},
{
title: "Ayala Moriel Parfums - SmellyBlog",
feedUrl: "https://ayalamoriel.com/blogs/smellyblog.atom",
url: "https://ayalamoriel.com/blogs/smellyblog",
description:
"Ayala Moriel Parfums is an independent artisan perfume house dedicated to the art of natural perfumery.",
},
{
title: "A whiff of Ambrosia",
feedUrl: "https://whiffofambrosia.wordpress.com/feed/",
url: "https://whiffofambrosia.wordpress.com/",
description: "Incense reviews and more. (Abandoned?)",
},
{
title: "Dr. Incense",
feedUrl: "https://dr-incense.com/blogs/dr-incense-blog.atom",
url: "https://dr-incense.com/blogs/dr-incense-blog",
description:
"Traditional incense maker and founder of the Incense Culture Association of Singapore, and Nanyang Culture Academy.",
},
{
title: "Glass Petal Smoke",
feedUrl: "https://glasspetalsmoke.blogspot.com/feeds/posts/default",
url: "https://glasspetalsmoke.blogspot.com/",
description:
"Decoder of flavors and fragrances. Creator of Smell & Tell programming.",
},
{
title: "Incense Apprentice",
feedUrl: "https://incenseapprentice.substack.com/feed",
url: "https://incenseapprentice.substack.com",
description: "Exploring incense making with Sara Gray.",
},
{
title: "Incense In The Wind",
feedUrl: "https://incenseinthewind.blogspot.com/feeds/posts/default",
url: "https://incenseinthewind.blogspot.com/",
description: "Incense reviews, rankings, and information.",
},
{
title: "Kikoh Incense",
feedUrl: "https://kikohincense.com/blogs/news.atom",
url: "https://kikohincense.com/blogs/news",
description:
"Detailed descriptions of incense listening sessions from the Kikoh Incense web store.",
},
{
title: "KyaraZen",
feedUrl: "https://www.kyarazen.com/feed/",
url: "https://www.kyarazen.com/",
description:
"Very informative (but perhaps abandoned) blog from world-renowned incense maker KyaraZen.",
},
{
title: "Olfactory Rescue Service",
feedUrl: "https://olfactoryrescueservice.wordpress.com/feed",
url: "https://olfactoryrescueservice.wordpress.com",
description:
"The ultimate retail incense resource providing incense writing and reviews.",
},
{
title: "Ratnagandh",
feedUrl: "https://ratnagandh.wordpress.com/feed/",
url: "https://ratnagandh.wordpress.com/",
description: "Short incense reviews.",
},
{
title: "Rauchfahne",
feedUrl: "https://blog.rauchfahne.de/en/feed/",
url: "https://blog.rauchfahne.de/en/",
description:
"Incense reviews and writing in German and English from incense maker, enthusiast, and industry insider Irene.",
},
{
title: "Reed's Handmade Incense Blog",
feedUrl: "https://reedshandmadeincense.com/blog/feed/",
url: "https://reedshandmadeincense.com/blog/",
description:
"Writing on incense, tea, and other topics from the Reed's Handmade Incense web store.",
},
{
title: "The Parfum Apothecary - Learning & Culture",
feedUrl:
"https://www.theparfumapothecary.com/blogs/learning-culture.atom",
url: "https://www.theparfumapothecary.com/blogs/learning-culture",
description: "Writing on perfume and its history. (Abandoned?)",
},
],
},
{
name: "LGBTQ+",
blogs: [
{
title: "Uncloseted Media",
feedUrl: "https://www.unclosetedmedia.com/feed",
url: "https://www.unclosetedmedia.com/",
description:
"Uncloseted Media is a new Investigative media organization committed to providing you with objective, nonpartisan, rigorous, LGBTQ-focused journalism that examines Americas anti-LGBTQ ecosystem and elevates the voices of everyday American heroes.",
},
],
},
{
name: "News: International",
blogs: [
{
title: "Bellingcat",
feedUrl: "https://www.bellingcat.com/feed/",
url: "https://www.bellingcat.com/",
description:
'Bellingcat is an independent investigative collective of researchers, investigators and citizen journalists brought together by a passion for open source research. (Thanks to <a href="https://werd.io/2024/non-profit-newsrooms-that-speak-to-power">werd.io</a> for the recommendation.)',
},
{
title: "openDemocracy",
feedUrl: "https://www.opendemocracy.net/en/feed",
url: "https://www.opendemocracy.net/",
description:
"High-quality journalism which challenges power, inspires change and builds leadership among groups underrepresented in the media. (Predominantly U.K. focused)",
},
{
title: "Techdirt",
feedUrl: "https://www.techdirt.com/feed/",
url: "https://www.techdirt.com/feed",
description:
"Started in 1997 by Floor64 founder Mike Masnick and then growing into a group blogging effort, the Techdirt blog relies on a proven economic framework to analyze and offer insight into news stories about changes in government policy, technology and legal issues that affect companies ability to innovate and grow.",
},
],
},
{
name: "News: U.S.A.",
blogs: [
{
title: "Popular Information",
feedUrl: "https://popular.info/feed",
url: "https://popular.info/",
description: "News for people who give a damn.",
},
{
title: "Reveal from the Center for Investigative Reporting",
feedUrl: "https://revealnews.org/feed",
url: "https://revealnews.org/",
description:
"Democracy faces an unprecedented threat from an authoritarian movement built on lies and contempt for the rule of law. The first and most critical defense of democracy—a robust, independent free press—has been missing in action. Corporate and billionaire media owners have shied away from confrontation, engaged in false equivalence, and sought to curry favor with Donald Trump. It is hardly surprising that readers and viewers are fleeing from these outlets. Americans need an alternative. The Contrarian is that alternative: unflinching, unapologetic, and unwavering in its commitment to truth-telling.",
},
{
title: "The Contrarian",
feedUrl: "https://themarkup.org/feeds/rss.xml",
url: "https://contrarian.substack.com/",
description:
'The Markup investigates how powerful institutions are using technology to change our society. (Thanks to <a href="https://werd.io/2024/non-profit-newsrooms-that-speak-to-power">werd.io</a> for the recommendation.)',
},
{
title: "The Markup",
feedUrl: "https://themarkup.org/feeds/rss.xml",
url: "https://themarkup.org",
description:
'The Markup investigates how powerful institutions are using technology to change our society. (Thanks to <a href="https://werd.io/2024/non-profit-newsrooms-that-speak-to-power">werd.io</a> for the recommendation.)',
},
],
},
{
name: "Personal Blogs",
blogs: [
{
title: "Andy Bell",
feedUrl: "https://andy-bell.co.uk/feed.xml",
url: "https://andy-bell.co.uk",
description:
"Designer, front-end developer and the founder of Set Studio and Piccalilli.",
},
{
title: "Darek Kay",
feedUrl: "https://darekkay.com/atom.xml",
url: "https://darekkay.com",
description:
"Front-end developer and an accessibility advocate, currently working at IBM.",
},
{
title: "Dom Corriveau",
feedUrl: "https://blog.ctms.me/index.xml",
url: "https://blog.ctms.me/",
description:
"Thoughts, opinions, wild speculation, and haphazard technical advice from Dom.",
},
{
title: "Ed Zitron's Where's Your Ed At",
feedUrl: "https://www.wheresyoured.at/rss/",
url: "https://www.wheresyoured.at/",
description: " The Words of Ed Zitron, a PR person and writer.",
},
{
title: "Ellie Kennard",
feedUrl: "https://www.elliekennard.ca/feed",
url: "https://www.elliekennard.ca",
description: "Photography and thoughts in story form.",
},
{
title: "Garbage Collector",
feedUrl: "https://blog.zedas.fr/index.xml",
url: "https://zedas.fr/",
description:
"The little space of a writer, tinkerer, and a coffee addict.",
},
{
title: "Later On",
feedUrl: "https://leisureguy.ca/rss",
url: "https://leisureguy.ca",
description:
"Writing on wet shaving, politics, whole food plant based diets, and more.",
},
{
title: "Luke Andrews",
feedUrl: "https://world.hey.com/lukeandrews/feed.atom",
url: "https://world.hey.com/lukeandrews",
description: "A sparse (abandoned?) blog from Luke Andrews.",
},
{
title: "MediaActivist",
feedUrl: "https://www.mediaactivist.com/rss/",
url: "https://www.mediaactivist.com/",
description:
"The website of Jay Baker (they/he), a long-time guerrilla journalist and documentarian.",
},
{
title: "Ploum.net",
feedUrl: "https://ploum.net/atom_en.xml",
url: "https://ploum.net/index_en.html",
description:
"Writing on tech and free / libre and open source philosophy.",
},
{
title: "Rosnovsky Park",
feedUrl: "https://rosnovsky.us/feed/feed.xml",
url: "https://rosnovsky.us/",
description:
"Writing on web development, hiking, and random hobbies from the venerable benefactor, founder, and admin of the lounge.town Mastodon instance.",
},
{
title: "Simone",
feedUrl: "https://simone.org/rss",
url: "https://simone.org/",
description:
"Explore modern life via thought-provoking essays, pictures, and conversations.",
},
{
title: "Steven Kennard : Turned Art, Sculpture and Photography",
feedUrl: "https://stevenkennard.com/blog/rss",
url: "https://stevenkennard.com/blog",
description:
"Steven Kennard is a woodturner, sculptor and photographer living and working in Nova Scotia, Canada.",
},
{
title: "Stories by Ellen Feinberg",
feedUrl: "https://ellensusie59.medium.com/feed",
url: "https://ellensusie59.medium.com",
description: "Uptown Chicago gal. Irreverent/Irrelevant/Sarcastic.",
},
{
title: "Thefoggiest.dev",
feedUrl: "https://thefoggiest.dev/feed",
url: "https://thefoggiest.dev",
description: "The personal blog of Diederick de Vries of Amsterdam.",
},
],
},
{
name: "Politics: U.S.A.",
blogs: [
{
title: "Liberation News",
feedUrl: "https://www.liberationnews.org/feed/",
url: "https://www.liberationnews.org/",
description: "Newspaper of the Party for Socialism and Liberation.",
},
{
title: "ProPublica",
feedUrl: "https://www.propublica.org/feeds/propublica/main/",
url: "https://www.propublica.org/",
description:
'ProPublica is an independent, nonprofit newsroom that produces investigative journalism with moral force. (Thanks to <a href="https://werd.io/2024/non-profit-newsrooms-that-speak-to-power">werd.io</a> for the recommendation.)',
},
{
title: "The 19th",
feedUrl: "https://19thnews.org/feed/",
url: "https://19thnews.org/",
description:
'An independent, nonprofit newsroom reporting on gender, politics and policy. (Thanks to <a href="https://werd.io/2024/non-profit-newsrooms-that-speak-to-power">werd.io</a> for the recommendation.)',
},
{
title: "The Marshall Project",
feedUrl: "https://www.themarshallproject.org/rss/recent.rss",
url: "https://www.themarshallproject.org/",
description:
'The Marshall Project seeks to create and sustain a sense of national urgency about the U.S. criminal justice system. (Thanks to <a href="https://werd.io/2024/non-profit-newsrooms-that-speak-to-power">werd.io</a> for the recommendation.)',
},
],
},
{
name: "Tech",
blogs: [
{
title: "9to5Linux",
feedUrl: "https://9to5linux.com/rss",
url: "https://9to5linux.com/",
description: "Linux news, reviews, tutorials, and more",
},
{
title: "Aftermath",
feedUrl: "https://aftermath.site/feed",
url: "https://aftermath.site/",
description:
"Aftermath is an independent, worker-owned website about video games and internet culture",
},
{
title: "It's FOSS",
feedUrl: "https://itsfoss.com/feed/",
url: "https://itsfoss.com/",
description: "Making You a Better Linux User.",
},
{
title: "LinuxInsider",
feedUrl: "https://www.linuxinsider.com?rss=1",
url: "https://www.linuxinsider.com",
description: "Linux News & Information From Around the World.",
},
{
title: "LOW←TECH MAGAZINE",
feedUrl: "https://solar.lowtechmagazine.com/posts/index.xml",
url: "https://solar.lowtechmagazine.com/posts/",
description:
"This is a solar-powered website, which means it sometimes goes offline.",
},
{
title: "Planet KDE",
feedUrl: "https://planet.kde.org/global/atom.xml",
url: "https://planet.kde.org/",
description:
"A feed aggregator that collects what the contributors to the KDE community are writing on their respective blogs.",
},
{
title: "Pluralistic",
feedUrl: "https://pluralistic.net/feed/",
url: "https://pluralistic.net/",
description: "Daily links from Cory Doctorow.",
},
{
title: "TorrentFreak",
feedUrl: "http://torrentfreak.com/feed",
url: "http://torrentfreak.com/",
description: "Breaking File-sharing, Copyright and Privacy News.",
},
{
title: "Werd I/O",
feedUrl: "https://werd.io/feed",
url: "https://werd.io",
description:
"Writing at the intersection of technology, democracy, and society by Ben Werdmuller.",
},
{
title: "We Distribute",
feedUrl: "https://wedistribute.org/rss",
url: "https://wedistribute.org",
description: "Connecting threads across the Web.",
},
],
},
{
name: "Veganism",
blogs: [
{
title: "Animal Justice",
feedUrl: "https://animaljustice.ca/category/blog/feed",
url: "https://animaljustice.ca/category/blog",
description:
"Read the latest news from the fight for stronger laws and better enforcement for animals in Canada.",
},
{
title: "Vegan Horizon",
feedUrl: "https://veganhorizon.substack.com/feed",
url: "https://veganhorizon.substack.com",
description:
"The vegan newsletter you've been waiting for! Brave, disruptive, to the point.",
},
],
},
{
name: "Web Development",
blogs: [
{
title: "CSS Tricks",
feedUrl: "https://css-tricks.com/feed",
url: "https://css-tricks.com",
description:
"Tips, Tricks, and Techniques on using Cascading Style Sheets.",
},
{
title: "Chris Coyier",
feedUrl: "https://chriscoyier.net/feed/",
url: "https://chriscoyier.net",
description: "Web craftsman, blogger, author, speaker.",
},
{
title: "Jim Nielsens Blog",
feedUrl: "https://blog.jim-nielsen.com/feed.xml",
url: "https://blog.jim-nielsen.com",
description:
"20+ years at the intersection of design & code on the web.",
},
{
title: "Own Your Web",
feedUrl: "https://buttondown.email/ownyourweb/rss",
url: "https://buttondown.com/ownyourweb",
description:
"A newsletter by Matthias Ott about designing, building, creating, and publishing for and on the Web.",
},
],
},
],
};

View File

@ -1,24 +0,0 @@
export default {
onScience: `
_________________________________________
( Once, when the secrets of science were )
( the jealously guarded property of a )
( small priesthood, the common man had no )
( hope of mastering their arcane )
( complexities. Years of study in musty )
( classrooms were prerequisite to )
( obtaining even a dim, incoherent )
( knowledge of science. )
( )
( Today all that has changed: a dim, )
( incoherent knowledge of science is )
( available to anyone. )
( )
( -- Tom Weller, "Science Made Stupid" )
-----------------------------------------
o ^__^
o (oo)\\_______
(__)\\ )\\/\\
||----w |
|| ||`
}

363
_data/galleries.js Normal file
View File

@ -0,0 +1,363 @@
export default [
{
title: "Pop Tart Flavor Memes",
description:
"One day, almost certainly when I ought to have been doing something more important, I discovered a meme format featuring Pop Tart boxes edited to have outlandish flavors on the packaging. Naturally, I had to collect as many as I could find. Here's what I've got:",
synopsis: "Some very unusual Pop Tart flavors…",
url: "/img/gallery/poptarts/",
date: new Date("November 26, 2024"),
galleryImage: "pop_tart_flavor_2.webp",
galleryImageAlt: "",
pictures: [
{
title: "Frosted New England Clam Chowder",
filename: "pop_tart_flavor_1.webp",
altText: "",
thumbAltText: "Frosted New England Clam Chowder",
caption: "",
},
{
title: "Frosted Tree Bark",
filename: "pop_tart_flavor_2.webp",
altText: "",
thumbAltText: "Frosted Tree Bark",
caption: "",
},
{
title: "Frosted Boot Leather",
filename: "pop_tart_flavor_3.webp",
altText: "",
thumbAltText: "Frosted Boot Leather",
caption: "I've dropped this bad boy on a twitter thread or two.",
},
{
title: "Frosted Kermit",
filename: "pop_tart_flavor_4.webp",
altText: "",
thumbAltText: "Frosted Kermit",
caption: "Is it worth it?",
},
{
title: "Frosted Bare Chest",
filename: "pop_tart_flavor_5.webp",
altText: "",
thumbAltText: "Frosted Bare Chest",
caption: "",
},
{
title: "Frosted Lysol Wipes",
filename: "pop_tart_flavor_6.webp",
altText: "",
thumbAltText: "Frosted Lysol Wipes",
caption: "",
},
{
title: "Mine Tarts",
filename: "pop_tart_flavor_7.webp",
altText: "Minecraft Frosted Grass Block",
thumbAltText: "Minecraft Frosted Grass Block",
caption: "",
},
{
title: "Frosted Earth Worms",
filename: "pop_tart_flavor_8.webp",
altText: "",
thumbAltText: "Frosted Earth Worms",
caption: "",
},
{
title: "Frosted Ground Beef",
filename: "pop_tart_flavor_9.webp",
altText: "",
thumbAltText: "Frosted Ground Beef",
caption: "",
},
{
title: "Frosted Black Coffee",
filename: "pop_tart_flavor_10.webp",
altText: "",
thumbAltText: "Frosted Black Coffee",
caption: "Unironically: I'd eat this.",
},
{
title: "Frosted Gasoline",
filename: "pop_tart_flavor_11.webp",
altText: "",
thumbAltText: "Frosted Gasoline",
caption: "",
},
{
title: "Frosted Tide Pods",
filename: "pop_tart_flavor_12.webp",
altText: "",
thumbAltText: "Frosted Tide Pods",
caption: `I once saw a lady drop a container of Tide Pods in the supermarket; without thinking I blurted out: "Oop, five second rule!" and didn't even get a laugh. Brutal.`,
},
{
title: "Frosted Hot Dog Water",
filename: "pop_tart_flavor_13.webp",
altText: "",
thumbAltText: "Frosted Hot Dog Water",
caption:
"Frankly, I'd sooner have the frosted lysol wipe Pop Tarts. 🤮",
},
{
title: "NY Style Sewer Rat",
filename: "pop_tart_flavor_14.webp",
altText: "",
thumbAltText: "NY Style Sewer Rat",
caption: "",
},
{
title: "Frosted Caviar",
filename: "pop_tart_flavor_15.webp",
altText: "",
thumbAltText: "Frosted Caviar",
caption: "",
},
{
title: "Frosted Elmer's Glue",
filename: "pop_tart_flavor_16.webp",
altText: "",
thumbAltText: "Frosted Elmer's Glue",
caption: "",
},
{
title: "Crusty!",
filename: "pop_tart_flavor_17.webp",
altText: "Crusty! Cement Flavor",
thumbAltText: "Crusty! Cement Flavor",
caption: "",
},
{
title: "Frosted Nuclear Waste",
filename: "pop_tart_flavor_18.webp",
altText: "Frosted Nuclear Waste: Made with real waste!",
thumbAltText: "Frosted Nuclear Waste: Made with real waste!",
caption: "",
},
{
title: "Frosted Beans",
filename: "pop_tart_flavor_19.webp",
altText: "",
thumbAltText: "Frosted Beans",
caption: "I'd give it a shot.",
},
{
title: "Shower Pack",
filename: "pop_tart_flavor_20.webp",
altText:
"Shower Pack, 3 in 1 formula! Shampoo, conditioner, and body wash.",
thumbAltText:
"Shower Pack, 3 in 1 formula! Shampoo, conditioner, and body wash.",
caption: "",
},
{
title: "Limited Edition",
filename: "pop_tart_flavor_21.webp",
altText: "Limited Edition: Just the Crust",
thumbAltText: "Limited Edition: Just the Crust",
caption: "",
},
{
title: "Frosted McDonald's Sprite",
filename: "pop_tart_flavor_22.webp",
altText: "Frosted",
thumbAltText: "Frosted",
caption: "",
},
{
title: "Frosted Fresh Cut Grass",
filename: "pop_tart_flavor_23.webp",
altText: "",
thumbAltText: "Frosted Fresh Cut Grass",
caption: "",
},
{
title: "Frosted Windex",
filename: "pop_tart_flavor_24.webp",
altText: "",
thumbAltText: "Frosted Windex",
caption: "",
},
{
title: "Frosted Popcorn Ceiling",
filename: "pop_tart_flavor_25.webp",
altText: "",
thumbAltText: "Frosted Popcorn Ceiling",
caption: "",
},
{
title: "Frosted Sharkboy & Lavagirl",
filename: "pop_tart_flavor_26.webp",
altText: "",
thumbAltText: "Frosted Sharkboy & Lavagirl",
caption: "",
},
{
title: "Frosted The Sun",
filename: "pop_tart_flavor_27.webp",
altText: "",
thumbAltText: "Frosted The Sun",
caption: "I don't know why, but I feel like these would be delicious.",
},
{
title: "Frosted Axe",
filename: "pop_tart_flavor_28.webp",
altText: "Frosted Axe body Spray",
thumbAltText: "Frosted Axe body Spray",
caption: "I would simply die.",
},
{
title: "Frosted Miracle Whip",
filename: "pop_tart_flavor_29.webp",
altText: "",
thumbAltText: "Frosted Miracle Whip",
caption: "",
},
{
title: "Frosted Water",
filename: "pop_tart_flavor_30.webp",
altText: "",
thumbAltText: "Frosted Water",
caption: "I'd give it a shot.",
},
{
title: "Encrusted",
filename: "pop_tart_flavor_31.webp",
altText: "Encrusted Play-Doh",
thumbAltText: "Encrusted Play-Doh",
caption: "They'd smell delicious at least.",
},
{
title: "Frosted Aluminum Foil",
filename: "pop_tart_flavor_32.webp",
altText: "",
thumbAltText: "Frosted Aluminum Foil",
caption: "",
},
{
title: "Frosted Orange Juice and Toothpaste",
filename: "pop_tart_flavor_33.webp",
altText: "",
thumbAltText: "Frosted Orange Juice and Toothpaste",
caption: "Honestly, this may be the worst of them all.",
},
],
},
{
title: "Shots from April 2024",
description:
"Sol and I went out for a walk down the street with a couple of cameras.",
synopsis:
"Sol and I went out for a walk down the street with a couple of cameras.",
url: "/img/gallery/april2024/",
date: new Date("January 23, 2025"),
galleryImage: "april_2024_4.webp",
galleryImageAlt: "",
pictures: [
{
title: "Sol shoots some flowers.",
filename: "april_2024_1.webp",
altText:
"A person in a beanie staring down a camera viewfinder at some tulips.",
thumbAltText:
"A person in a beanie staring down a camera viewfinder at some tulips.",
caption: "",
},
{
title: "We were being watched…",
filename: "april_2024_2.webp",
altText: "Some cats staring at us through a window screen.",
thumbAltText: "Some cats staring at us through a window screen.",
caption: "Somehow I don't mind these nosy neighbors.",
},
{
title: "A pole.",
filename: "april_2024_3.webp",
altText: "A closeup of a black painted pole with stickers on it.",
thumbAltText: "A closeup of a black painted pole with stickers on it.",
caption: "",
},
{
title: "Love this storefront.",
filename: "april_2024_4.webp",
altText:
"A storefront painted vividly with lots of colors, dots and flowers.",
thumbAltText:
"A storefront painted vividly with lots of colors, dots and flowers.",
caption: "",
},
{
title: "Another pole.",
filename: "april_2024_5.webp",
altText: "A wide, beige painted pole covered in ads and notices.",
thumbAltText: "A wide, beige painted pole covered in ads and notices.",
caption: "",
},
{
title: "Can't get enough of that pole.",
filename: "april_2024_6.webp",
altText:
"A mushroom-like green canopy on top of the beige pole, with lettering spelling out Roscoe Village.",
thumbAltText:
"A mushroom-like green canopy on top of the beige pole, with lettering spelling out Roscoe Village.",
caption: "",
},
{
title: "The infamous Chicago Rat Hole.",
filename: "april_2024_7.webp",
altText:
"An impression in the sidewalk of what is likely a squirrel; it is filled with coins and rocks left as tribute.",
thumbAltText:
"An impression in the sidewalk of what is likely a squirrel; it is filled with coins and rocks left as tribute.",
caption: "That has to be a squirrel.",
},
{
title: "A courtesy to cyclists.",
filename: "april_2024_8.webp",
altText:
"A crusty old parking meter with a ghost sticker and graffiti on it. Inside of the meter window reads: Meter remains as a courtesy to cyclists. Please pay at pay box.",
thumbAltText:
"A crusty old parking meter with a ghost sticker and graffiti on it. Inside of the meter window reads: Meter remains as a courtesy to cyclists. Please pay at pay box.",
caption: "",
},
{
title: "A brick building.",
filename: "april_2024_9.webp",
altText:
"The front of a red brick building with two potted plants in front of the door. The wall has many of those little square glass-tiles to allow in light while affording privacy.",
thumbAltText:
"The front of a red brick building with two potted plants in front of the door. The wall has many of those little square glass-tiles to allow in light while affording privacy.",
caption: "",
},
{
title: "Weed.",
filename: "april_2024_10.webp",
altText:
"A closeup of a dandelion ready to have its seeds blown into the wind.",
thumbAltText:
"A closeup of a dandelion ready to have its seeds blown into the wind.",
caption: "",
},
{
title: "Another creative storefront",
filename: "april_2024_11.webp",
altText:
"A storefront with painted illustrations of a woman giving a baby a bath, and several stylized women carrying baskets of fruit and flowers on their heads.",
thumbAltText:
"A storefront with painted illustrations of a woman giving a baby a bath, and several stylized women carrying baskets of fruit and flowers on their heads.",
caption: "",
},
{
title: "A robin crossing the street.",
filename: "april_2024_12.webp",
altText:
"A robin runs across the street, casting a long shadow for such a small fellow.",
thumbAltText:
"A robin runs across the street, casting a long shadow for such a small fellow.",
caption: "",
},
],
},
];

View File

@ -3,88 +3,106 @@ export default {
logo: "/img/logo.svg",
url: "https://nathanupchurch.com/",
language: "en",
description: "The personal website and blog of Nathan Upchurch.",
description:
"The personal website and blog of Nathan Upchurch, where I write about incense, free and open source software, design, vegan cooking, music, and all sorts of other topics that I find interesting.",
author: {
givenName: "Nathan",
familyName: "Upchurch",
name: "Nathan Upchurch",
email: "blog@upchur.ch",
url: "https://nathanupchurch.com/me",
profilePic: "/img/CN20191025_301_Srt_SQUARE_crop.jpg"
profilePic: "/img/CN20191025_301_Srt_SQUARE_crop.jpg",
},
copyrightNotice: "© Nathan Upchurch 2022 - 2024",
defaultPostImageURL: "/img/vasilina-sirotina-1NMPvajSt9Q-unsplash_copy.avif",
defaultPostImageAlt: "The default post image: a close picture of the dark green leaves of a plant.",
blogrollUrl: "/blogroll/nathanUpchurchBlogroll.opml",
copyrightNotice: "© Nathan Upchurch 2022 - 2025",
defaultPostImageURL: "/img/logo_post.svg",
defaultPostImageAlt: "The logo for this blog: a capital letter N.",
mastodonHost: "lounge.town",
mastodonUser: "nathanu",
postlistHeaderText: "Latest posts from the blog:",
postlistHeaderText: "Latest blog posts:",
socialLinks: [
{
title: "My Blog",
linkURL: "https://nathanupchurch.com",
linkDisplay: "My Blog",
iconURL: "/img/logo.svg"
iconURL: "/img/logo.svg",
},
{
title: "Friendica",
linkURL: "https://friendica.world/profile/nathan",
customAttribute: `rel="me"`,
linkDisplay: "Friendica",
iconURL: "/img/friendica.svg",
},
{
title: "Mastodon",
linkURL: "https://lounge.town/@nathanu",
customAttribute: `rel="me"`,
linkDisplay: "Mastodon",
iconURL: "/img/mastodon.svg"
iconURL: "/img/mastodon.svg",
},
{
title: "Email Me",
linkURL: "Mailto:blog@upchur.ch",
linkDisplay: "Email",
iconURL: "/img/envelope.svg"
iconURL: "/img/envelope.svg",
},
{
title: "Matrix",
linkURL: "https://matrix.to/#/@nathanu:matrix.org",
linkURL: "https://matrix.to/#/@nathan:upchur.ch",
linkDisplay: "Matrix",
iconURL: "/img/matrix-org.svg"
iconURL: "/img/matrix-org.svg",
},
{
title: "Signal",
linkURL:
"https://signal.me/#eu/j-om4cfsGXtfKo0UX28EQfEL_Gd1KpJr8nQpI9Smhdsb-r98eT5F6obQ1BcYZCcW",
linkDisplay: "Signal",
iconURL: "/img/Signal-Logo-White.svg",
},
{
title: "BookWyrm",
linkURL: "https://ramblingreaders.org/user/NathanU",
linkDisplay: "BookWyrm",
iconURL: "/img/book.svg"
iconURL: "/img/book.svg",
},
{
title: "Pixelfed",
linkURL: "https://pixelfed.social/@nathanu",
linkDisplay: "Pixelfed",
iconURL: "/img/pixelfed.svg"
iconURL: "/img/pixelfed.svg",
},
{
title: "Lemmy",
linkURL: "https://lemmy.ml/u/NathanUp",
linkDisplay: "Lemmy",
iconURL: "/img/Lemmy_logo.svg"
iconURL: "/img/Lemmy_logo.svg",
},
{
title: "PeerTube",
linkURL: "https://dalek.zone/a/nathan_upchurch/",
linkURL: "https://makertube.net/a/nathan/video-channels",
linkDisplay: "PeerTube",
iconURL: "/img/peertube.svg"
iconURL: "/img/peertube.svg",
},
{
title: "Keyoxide Identity Profile",
linkURL: "https://keyoxide.org/31E809FAEA1532AC91BBDCF1EC499D3513F69340",
linkDisplay: "Keyoxide Identity Profile",
iconURL: "/img/keyoxide.svg"
}
iconURL: "/img/keyoxide.svg",
},
],
webrings: [
{
name: "Fediring",
ringURL: "https://fediring.net/",
previousURL: "https://fediring.net/previous?host=nathanupchurch.com",
nextURL: "https://fediring.net/next?host=nathanupchurch.com"
nextURL: "https://fediring.net/next?host=nathanupchurch.com",
},
{
name: "Geekring",
ringURL: "https://geekring.net/",
previousURL: "http://geekring.net/site/350/previous",
nextURL: "http://geekring.net/site/350/next"
}
]
}
nextURL: "http://geekring.net/site/350/next",
},
],
};

View File

@ -9,5 +9,7 @@
{% if webring.nextURL %}<a href="{{ webring.nextURL }}">→</a>{% endif %}
</span>
{% endfor %}
{% endif %}</p>
{% endif %}
<a href="/sitemap/">Sitemap</a>
</p>
</footer>

View File

@ -0,0 +1,29 @@
<section class="postlist">
<div class="postlist-item-container">
{% for gallery in galleries | reverse %}
{% if not numberOfGalleriesToShow or loop.index <= numberOfGalleriesToShow %}
<article class="postlist-item">
<a href="../gallery/{{ gallery.title | slugify }}" class="postlist-link">
<div class="post-image-container">
<img class="post-image" {% if gallery.galleryImage %} src="{{ gallery.url }}{{ gallery.galleryImage }}" alt="{{ gallery.galleryImageAlt }}" {% else %} src="{{ metadata.defaultPostImageURL }}" alt="{{ metadata.defaultPostImageAlt }}"{% endif %}>
</div>
</a>
<div class="post-copy">
<a href="../gallery/{{ gallery.title | slugify }}" class="postlist-link">
<h3>
{{ gallery.title }}
</h3>
</a>
{% if not hideGalleryDescriptions %}<p>{{ gallery.synopsis | truncate(105) | safe }}</p>{% endif %}
<div class="post-metadata">
<div class="post-metadata-copy">
<p>Posted on the&nbsp;<time class="postlist-date" datetime="{{ gallery.date | htmlDateString}}">{{ gallery.date | niceDate("LLLL yyyy") }}</time></p>
</div>
</div>
</div>
</article>
<hr>
{% endif %}
{% endfor %}
</div>
</section>

View File

@ -2,10 +2,9 @@
<html lang="{{ metadata.language }}">
<head>
{% include "metadata.njk" %}
{#- Bundle CSS #}
{%- css %}{% include "public/css/index.css" %}{% endcss %}
{%- css %}{% include "public/css/webfonts/webfonts.css" %}{% endcss %}
<style>{% getBundle "css" %}</style>
<link rel="stylesheet" type="text/css" href="/css/index.css" />
<link rel="stylesheet" type="text/css" href="/css/webfonts/webfonts.css" />
<link rel="stylesheet" type="text/css" href="/css/code.css" />
{% include "structuredData.njk" %}
{% include "umami.html" %}
</head>

View File

@ -2,7 +2,7 @@
layout: layouts/base.njk
showPostListHeader: yep
---
<h1>Hi there, friend.</h1>
<p class="nodropcap page-block">My name is Nathan Upchurch. Welcome to my personal website and blog, where I write about <a href="./tags/incense/">incense,</a> <a href="./tags/foss-floss/">free and open source software,</a> design, <a href="./tags/vegan-cooking/">vegan cooking,</a> music, and all sorts of <a href="/tags">other topics</a> that I find interesting. Learn more <a href="about">about me,</a> see <a href="now">what Ive been up to lately,</a> or have a look at my latest blog posts below.</p>
<h1>I'm Nathan; welcome&nbsp;friend.</h1>
<p class="nodropcap page-block">My name is Nathan Upchurch, and this is my personal website and blog, where I write about all sorts of <a href="/tags">things</a> that I find interesting. On this website, you can learn more <a href="about">about me</a>, see <a href="now">what Ive been up to lately</a>, <a href="blog">read my blog</a>, look at some <a href="galleries">pictures</a>, or explore the <a href="sitemap">sitemap</a> to see what else you can do here.</p>
{{ content | safe }}

View File

@ -1,8 +1,6 @@
---
layout: layouts/baseBareBones.njk
hideNav: please
layout: layouts/linksPage.njk
---
{%- css %}{% include "public/css/me.css" %}{% endcss %}
<div class="links-container">
<img class="profilePic" src="{{ metadata.author.profilePic }}">
<h1 class="socialTitle">Nathan Upchurch</h1>

View File

@ -2,10 +2,10 @@
<html lang="{{ metadata.language }}" class="barebones">
<head>
{% include "metadata.njk" %}
{#- Bundle CSS #}
{%- css %}{% include "public/css/index.css" %}{% endcss %}
{%- css %}{% include "public/css/webfonts/webfonts.css" %}{% endcss %}
<style>{% getBundle "css" %}</style>
<link rel="stylesheet" type="text/css" href="/css/me.css" />
<link rel="stylesheet" type="text/css" href="/css/index.css" />
<link rel="stylesheet" type="text/css" href="/css/webfonts/webfonts.css" />
{% include "umami.html" %}
</head>
<body class="barebones">

View File

@ -1,10 +1,8 @@
---
layout: layouts/base.njk
---
{# Only include the syntax highlighter CSS on blog posts #}
{%- css %}{% include "public/css/code.css" %}{% endcss %}
<article class="post">
<h1>{{ title }}</h1>
<h1>{{ title | safe }}</h1>
{% if not hideMetadata %}
<div class="post-metadata">
{% if author %}
@ -13,7 +11,7 @@ layout: layouts/base.njk
{% endif %}
<div class="post-metadata-copy">
<p>{% if author.url %}<a href="{{ author.url }}">{% endif %}
{% if author.name %}{{ author.name }},&nbsp;{% endif %}{% if author.url %}</a>{% endif %}<time datetime="{{ page.date | htmlDateString }}">{{ page.date | readableDate }}</time></p>
{% if author.name %}By {{ author.name }}{% endif %}{% if author.url %}</a>&nbsp;•&nbsp;{% endif %}<time datetime="{{ page.date | htmlDateString }}">{{ page.date | niceDate }}</time></p>
{% else %}
{% if metadata.author.profilePic %}
@ -21,7 +19,7 @@ layout: layouts/base.njk
{% endif %}
<div class="post-metadata-copy">
<p>{% if metadata.author.url %}<a href="{{ metadata.author.url }}">{% endif %}
{% if metadata.author.name %}{{ metadata.author.name }},&nbsp;{% endif %}{% if metadata.author.url %}</a>{% endif %}<time datetime="{{ page.date | htmlDateString }}">{{ page.date | readableDate }}</time></p>
{% if metadata.author.name %}By {{ metadata.author.name }}{% endif %}{% if metadata.author.url %}</a>&nbsp;•&nbsp;{% endif %}<time datetime="{{ page.date | htmlDateString }}">{{ page.date | niceDate }}</time></p>
{% endif %}
@ -44,4 +42,3 @@ layout: layouts/base.njk
{{ content | safe }}
</article>
{% include "mastodonComments.njk" %}
{% include "nextLast.njk" %}

View File

@ -0,0 +1,53 @@
---
layout: layouts/post.njk
structuredData: none
---
{{ content | safe }}
<section class="quiz">
<form onsubmit="handleQuizSubmit(); return false">
{% for question in questions %}
{% set q = loop.index %}
<div class="questionBox">
<p class="quizQuestion">{{ q }}. {{ question.title }}</p>
{% if question.image %}
<figure>
<a href="{{ question.image }}">
<img src="{{ question.image }}" alt="{{ question.imageAlt }}">
</a>
{% if question.imageCaption %}
<figcaption>{{ question.imageCaption }}</figcaption>
{% endif %}
</figure>
{% endif %}
<div class="answersBox">
{% for answer in question.answers %}
<div class="answerBox">
<input class="answer" type="radio" value="{{ answer.points }}" id="q{{ q }}a{{ loop.index }}" name="{{ q }}" required>
<label for="q{{ q }}a{{ loop.index }}">{{ answer.name }}</label>
</div>
{% endfor %}
</div>
</div>
{% endfor %}
<script src="/js/quiz.js"></script>
<button>Submit</button>
</form>
</section>
{% for consequence in consequences %}
<dialog class="consequence" data-points-threshold="{{ consequence.points }}">
<h2>{{ consequence.title }}</h2>
<p>{{ consequence.spiel }}</p>
{% if consequence.image %}
<img src="{{ consequence.image }}" alt="{{ consequence.imageAlt }}">
{% endif %}
<details>
<summary>Score Details</summary>
<p class="scoreDetails"></p>
</details>
<form method="dialog">
<button>Thanks</button>
</form>
</dialog>
{% endfor %}

View File

@ -1,81 +1,12 @@
{% if mastodon_id %}
<section class="" id="comment-section">
<h2>Comments</h2>
<div class="comment-ingress"></div>
<div id="comments" data-id="{{ mastodon_id }}">
<p>Loading comments...</p>
</div>
<div class="continue-discussion">
<a class="link-button" href="https://{{ metadata.mastodonHost }}/@{{ metadata.mastodonUser }}/{{ mastodon_id }}">
<button type="button">
Reply on Mastodon to comment &#187;
<img src="/img/mastodon.svg">
Discuss on Mastodon &#187;
</button>
</a>
</div>
</section>
<template id="comment-template">
<wc-card>
<wc-comment
author_name=""
author_url=""
avatar_url=""
comment_content=""
publish_date=""
sharp_corner="">
</wc-comment>
</wc-card>
</template>
<script type="module">
import {dateSuffixAdder, monthMap, timeFormatter} from "../../js/modules/mastodonDateTools.js";
const renderComment = (comment, target, parentIdm) => {
const node = document
.querySelector("template#comment-template")
.content.cloneNode(true);
const dateObj = new Date(comment.created_at);
const dateTime = `${dateObj.getDate()}${dateSuffixAdder(dateObj.getDate())} of ${monthMap[dateObj.getMonth()]}, ${dateObj.getFullYear()}, at ${timeFormatter(dateObj.getHours(), dateObj.getMinutes())}`;
node.querySelector("wc-comment").setAttribute("author_name", comment.account.display_name);
node.querySelector("wc-comment").setAttribute("author_url", comment.url.replace(/\/[0-9]+/, ""));
node.querySelector("wc-comment").setAttribute("avatar_url", comment.account.avatar_static);
node.querySelector("wc-comment").setAttribute("comment_content", comment.content);
node.querySelector("wc-comment").setAttribute("publish_date", dateTime);
target.appendChild(node);
}
async function renderComments() {
const commentsNode = document.querySelector("#comments");
const mastodonPostId = commentsNode.dataset?.id;
if (!mastodonPostId) {
return;
}
commentsNode.innerHTML = "";
const originalPost = await fetch(
`https://{{ metadata.mastodonHost }}/api/v1/statuses/${mastodonPostId}`
);
const originalData = await originalPost.json();
renderComment(originalData, commentsNode, null);
const response = await fetch(
`https://{{ metadata.mastodonHost }}/api/v1/statuses/${mastodonPostId}/context`
);
const data = await response.json();
const comments = data.descendants;
comments.forEach((comment) => {
renderComment(comment, commentsNode, mastodonPostId);
});
}
renderComments();
</script>
{% endif %}

View File

@ -2,6 +2,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ title or metadata.title }}</title>
<link rel="icon" type="image/x-icon" href="/img/logo_favicon.svg">
<link rel="blogroll" type="text/xml" href="{{ metadata.blogrollUrl }}">
<meta name="description" content="{{ description or metadata.description }}">
<meta name="robots" content="noai, noimageai">
<meta name="generator" content="{{ eleventy.generator }}">

View File

@ -2,14 +2,9 @@
<h2 class="visually-hidden">Top level navigation menu</h2>
<ul class="nav">
{%- for entry in collections.all | eleventyNavigation %}
<a class="nav-item" href="{{ entry.url }}"{% if entry.url == page.url %} aria-current="page" data-currentpage="true"{% endif %}>
<li>{{ entry.title }}</li>
</a>
<li class="nav-item" {% if entry.url == page.url %} aria-current="page" data-currentpage="true"{% endif %}><a href="{{ entry.url }}">{{ entry.title }}</a></li>
{%- endfor %}
<a class="nav-item" href="/feed/feed.xml">
<li class="subscribe">
{% include "rssLogo.njk" %}Feed
</li>
</a>
<li class="subscribe nav-item"><a href="/feed/feed.xml">{% include "rssLogo.njk" %}Feed</a>
</li>
</ul>
</nav>

View File

@ -1,23 +1,44 @@
<section class="postlist">
{% if showPostListHeader %}<h2>{{ metadata.postlistHeaderText }}</h2>{% endif %}
<div class="postlist-item-container">
{% for post in postslist | reverse %}
<article class="postlist-item{% if post.url == url %} postlist-item-active{% endif %}">
<a href="{{ post.url }}" class="postlist-link">
<div class="post-image-container">
<img class="post-image" {% if post.data.imageURL %} src="{{ post.data.imageURL }}" alt="{{ post.data.imageAlt }}" {% else %} src="{{ metadata.defaultPostImageURL }}" alt="{{ metadata.defaultPostImageAlt }}"{% endif %}>
</div>
</a>
<div class="post-copy">
{% if showPostListHeader %}<h2>{{ metadata.postlistHeaderText }}</h2>{% endif %}
<div class="postlist-item-container">
{% for post in postslist | reverse %}
<article class="postlist-item{% if post.url == url %} postlist-item-active{% endif %}">
<a href="{{ post.url }}" class="postlist-link">
<h3>
{% if post.data.title %}{{ post.data.title }}{% else %}<code>{{ post.url }}</code>{% endif %}
</h3>
<div class="post-image-container">
<img class="post-image" {% if post.data.imageURL %} src="{{ post.data.imageURL }}" alt="{{ post.data.imageAlt }}" {% else %} src="{{ metadata.defaultPostImageURL }}" alt="{{ metadata.defaultPostImageAlt }}"{% endif %}>
</div>
</a>
<time class="postlist-date" datetime="{{ post.date | htmlDateString }}">{{ post.date | readableDate("LLLL yyyy") }}</time>
{% if post.data.synopsis %}<p>{{ post.data.synopsis | truncate(105) | safe }}</p>{% else %}{{ post.content | truncate(105) | safe }}{% endif %}
</div>
</article>
{% endfor %}
</div>
<div class="post-copy">
<a href="{{ post.url }}" class="postlist-link">
<h3>
{% if post.data.title %}{{ post.data.title | safe }}{% else %}<code>{{ post.url }}</code>{% endif %}
</h3>
</a>
<div class="post-metadata">
<div class="post-metadata-copy">
<p>
{% if post.data.author %}
{% if post.data.author.url %}<a href="{{ post.data.author.url }}">{% endif %}{% if post.data.author.name %}By {{ post.data.author.name }}{% endif %}{% if post.data.author.url %}</a>&nbsp;•&nbsp;{% endif %}{% else %}<a href="{{ metadata.author.url }}">By {{ metadata.author.name }}</a>&nbsp;•&nbsp;{% endif %}<time datetime="{{ post.date | htmlDateString }}">{{ post.date | niceDate }}</time>
</p>
<ul>
{%- for tag in post.data.tags | filterTagList %}
{%- set tagUrl %}/tags/{{ tag | slugify }}/{% endset %}
<li>
<a
href="{{ tagUrl }}"
class="post-tag">
{{ tag }}&nbsp;
</a>
</li>
{%- endfor %}
</ul>
</div>
</div>
</div>
</article>
<hr>
{% endfor %}
</div>
</section>

View File

@ -1,19 +1,25 @@
{% if title %}
{% if title and structuredData != "none" %}
<!-- Structured Data -->
<script type="application/ld+json">
{
"@context": "https://schema.org/",
"@type": "Article",
"headline": "{{ title }}",
"@type": "BlogPosting",
"articleBody": "{{ content | striptags }}"
"author": {
"@type": "Person",
"name": "{{ metadata.author.name }}"
"familyName": "{{ metadata.author.familyName }}",
"givenName": "{{ metadata.author.givenName }}",
"image": "{{ metadata.url }}{{ metadata.author.profilePic }}",
"name": "{{ metadata.author.name }}",
"url": "{{ metadata.author.url }}"
},
"datePublished": "{{ date }}",
"description": "{% if synopsis %}{{ synopsis}}{% endif %}",
"headline": "{{ title }}",
"image": "{% if imageURL %}{{ imageURL | htmlBaseUrl(metadata.url) }}{% else %}{{ metadata.defaultPostImageURL | htmlBaseUrl(metadata.url) }}{% endif %}",
"inLanguage": "{{ metadata.language }}",
"name": "{{ title }}",
"url": "{{ page.url | htmlBaseUrl(metadata.url) }}",
"articleBody": "{{ content | striptags }}"
}
</script>
<!-- Open Graph -->

View File

@ -1,5 +1,7 @@
---
layout: layouts/403.njk
permalink: 403.html
title: Nathan Upchurch | 403
structuredData: none
eleventyExcludeFromCollections: true
---

View File

@ -1,5 +1,7 @@
---
layout: layouts/404.njk
permalink: 404.html
title: Nathan Upchurch | 404
structuredData: none
eleventyExcludeFromCollections: true
---

View File

@ -1,5 +1,7 @@
---
layout: layouts/post.njk
title: Nathan Upchurch | About Feeds
structuredData: none
hideMetadata: yep
---
# How to use feeds.

View File

@ -0,0 +1,13 @@
---
layout: layouts/base.njk
title: Nathan Upchurch | Colophon
structuredData: none
---
# Colophon
## What I used to build this website
I built this website using [the 11ty static site generator](https://www.11ty.dev/), free and open source variable typefaces [Fraunces](https://fraunces.undercase.xyz/)[^1] and [Manrope](https://www.gent.media/manrope)[^2], and plain-old HTML, CSS, with some vanilla JavaScript for the web components that I built to handle comments. I used the handy calculators on [utopia.fyi](https://utopia.fyi)[^3] to help me implement fluid typography and spacing. [Here's the repo](https://upchur.ch/gitea/n_u/nathanupchurch.com) in case you'd like to have a look at the source.
[^1]: Designed by Phaedra Charles and Flavia Zimbardi, with contributions by Ethan Cohen, and Andy Clymer.
[^2]: Designed by Mikhail Sharanda with thanks to Mirko Velimirovic for contribution.
[^3]: Created by James Gilyead & Trys Mudford.

View File

@ -2,21 +2,22 @@
layout: layouts/base.njk
eleventyNavigation:
key: About
order: 3
order: 2
---
<article>
<h1>About me and this website Ive built.</h1>
<p>Im a prolific vegan home cook, classical trombonist, a <abbr title="Free/Libre Open Source Software">FLOSS</abbr> enthusiast, daily GNU/Linux user and unabashed <a href="https://kde.org/">KDE</a> stan, speaker of subpar elementary Spanish, incense maker and appreciator, writer, electronics hobbyist, designer, programmer, music producer, print lover, and human with too many interests and too little time.</p>
<h1>About me and my&nbsp;website.</h1>
<p class="page-block nodropcap">Im a prolific vegan home cook, classical trombonist, incense maker, a <abbr title="Free/Libre Open Source Software">FLOSS</abbr> enthusiast, daily GNU/Linux user and unabashed <a href="https://kde.org/">KDE</a> stan, designer, programmer, music producer, print lover, and human with too many interests and too little time. This is my little corner of the internet where I talk about whatever I like without worrying about maintaining a personal brand, or constraining subject matter to topics which might help advance my career or establish me as a thought leader. Im here to express myself and have fun writing about topics I enjoy. If youd like to learn more about my professional accomplishments and work, Ill link my professional website here when I get around to it.</p>
<p>This is my personal website and blog, a little corner of the internet where I can talk about whatever I like without worrying about maintaining a personal brand, or constraining subject matter to those topics which might help advance my career or establish me as a thought leader. Im here to express myself as a human and have fun writing about topics I enjoy. If youd like to learn more about my professional accomplishments and work, Ill link my professional website here soon.</p>
<a href="./colophon/">
<button type="button">Colophon »</button>
</a>
<h2>About this website</h2>
<p>This website is made with <a href="https://www.11ty.dev/">the 11ty static site generator</a>, free and open source variable typefaces <a href="https://fraunces.undercase.xyz/">Fraunces</a> and <a href="https://www.gent.media/manrope">Manrope</a>, along with plain-old HTML, CSS, and some vanilla JavaScript for the web components that I built to handle comments. I used the handy calculators on <a href="https://utopia.fyi">utopia.fyi</a> to help me implement fluid typography and spacing.</p>
<a href="../me/">
<button type="button">Contact »</button>
</a>
<p>I dont collect any of your personal information, full-stop. All webfonts, icons, and images are hosted locally (these things can sometimes be used to <a href="https://www.firstpost.com/world/how-google-uses-fonts-to-track-what-users-do-online-and-sell-data-to-advertisers-12496552.html">track people across the internet</a> otherwise). I use <a href="https://umami.is/">umami</a>, an open source, privacy-respecting analytics tool, to see how many people visit this website.</p>
<a href="./privacy/">
<button type="button">Privacy »</button>
</a>
<p>Miss when the internet was fun? Find more interesting personal blogs at <a href="https://blogroll.org">blogroll.org</a>, <a href="https://ooh.directory/">ooh.directory</a>, or surf through the webrings at the bottom of the page.</p>
<h2>Contact Me</h2>
<p>If you would like to say something nice, ask a question, or simply follow me on the fediverse, <a href="../me">heres where you can find me</a>.</p>
</article>

View File

@ -0,0 +1,10 @@
---
layout: layouts/base.njk
title: Nathan Upchurch | Privacy
structuredData: none
---
# Privacy Statement
## Data collection and use
I dont collect any of your personal information, full-stop. All webfonts, icons, and images are hosted locally (these things can sometimes be used to [track people across the internet](https://www.firstpost.com/world/how-google-uses-fonts-to-track-what-users-do-online-and-sell-data-to-advertisers-12496552.html) otherwise). I use [umami](https://umami.is), an open source, privacy-respecting analytics tool, to see [how many people visit this website](https://umami.upchur.ch/share/7P3yYsqAsvpdlb03/nathanupchurch.com).

12
content/ai.md Normal file
View File

@ -0,0 +1,12 @@
---
layout: layouts/base.njk
title: Nathan Upchurch | AI
structuredData: none
---
# AI Statement
## Is AI used for this website?
Absolutely no prose, code, or image that comprises a part the content of this website, nor any code that comprises the website itself was generated from AI products, also known as 'ocean-boiling plagiarism machines'. You may rest assured that this will not change.
## AI Permissions
I do my utmost to ensure that my work is not hoovered wholesale and regurgitated by AI products by including an [ai.txt file](/ai.txt) and disallowing known crawlers in my [robots.txt file](/robots.txt), but just in case it will ever become meaningful in any legal sense, I'd like to make it clear here that I do not grant permission for any content on this website to be used as training data for any AI project, or for any portion of this website to be scraped by bots associated with AI projects.

View File

@ -1,13 +1,22 @@
---
layout: layouts/base.njk
title: Nathan Upchurch | Blog
structuredData: none
eleventyNavigation:
key: Blog
order: 2
order: 3
---
<h1>Nathans Blog.</h1>
<h1>My personal blog.</h1>
<p class="page-block nodropcap">
Looking for something in particular? Have a look at <a href="/tags/">this convenient list of post categories</a> to filter results by topic.
I write about whatever I like here, from <a href="/tags/storytime">personal stories</a>, to <a href="/tags/gnu-linux">tech</a>, <a href="/tags/vegan-cooking">food</a>, and <a href="/tags/incense">incense</a>.<br />
<a href="/tags/">
<button type="button">Topics »</button>
</a>
<a href="../blogroll/">
<button type="button">Blogroll »</button>
</a>
</p>
<h2>Whats New:</h2>
{% set postslist = collections.posts %}

View File

@ -4,6 +4,7 @@ description: "An attempt at a lavender incense stick goes remarkably well thanks
date: 2024-07-28
tags:
- Incense
- Incense Making
synopsis: "An attempt at a lavender incense stick goes remarkably well thanks to an unusual technique."
imageURL: /img/sending-incense-samples.webp
imageAlt: An uncapped fountain pen on top of a pretty, gold-foiled pad of paper beside some envelopes with stamps featuring coffee drinks on them.

View File

@ -0,0 +1,59 @@
---
title: "Black Metal: Fraught Genre, Incredible Tunes"
description: Learning to appreciate extreme metal, problems in the scene, and some killer black metal tunes.
date: 2024-11-12
tags:
- Music
synopsis: Learning to appreciate extreme metal, problems in the scene, and some killer black metal tunes.
imageURL: /img/black_metal.webp
imageAlt: A very creepy picture of a priest in the dark holding a bible with his hand on the head of a man lying on a table wearing a gas mask and a straitjacket.
mastodon_id: "113472856465004642"
---
The beauty of extreme metal genres eludes many a music lover. I was one of them, until in 2007 a friend and I were able to snag some free tickets to Ozzfest by drinking far too many cans of Monster. I'd been into some slightly heavier music; I'm still a big Rammstein fan, but I just didn't *get* all of that screaming nonsense… until I saw it live.
The power of music is its ability to make you feel: opening you up like a tin can, cramming you full of new emotions and bolstering existing ones, allowing them to override the habitual suppression you've long since stopped noticing; more than mere entertainment, in this way, listening to music becomes a means of exploring, experiencing, and feeling themes and emotions on your terms. As the bass from those gargantuan sub-woofers tears through your body like the drums of a pipe band alongside amplified human screams, growls, and gurgles—the sounds of anger, fear, anguish, and death: seeing a metal act in the flesh *does* something to you.
On that summer day in Texas, I was stricken with an appreciation for metal that I've had ever since. Black metal and death metal populate my music collection alongside tenor trombone concertos, DJ Screw, and drum and bass bangers to this day.
## The big problem with black metal
If you're new to the genre it's important to know, however, that black metal is not without controversy. It's common knowledge that much extreme metal is anti-religious (a position to which I am not unsympathetic) and deliberately provocative to the faithful, as you will see below (Christians: you have been warned), but it is often an unpleasant surprise to those new to the scene that black metal has, to put it frankly, a nazi problem.
Devastatingly satirized by [Neckbeard Deathcamp](https://neckbearddeathcamp.bandcamp.com/), the problem is so widespread that [reddit](https://www.reddit.com/r/LetsTalkMusic/comments/tncgjc/metalheads_how_do_i_find_out_if_the_band_i_found/) [is](https://www.reddit.com/r/MetalForTheMasses/comments/17dt56y/best_nonnsbm_black_metal_bands/) [laden](https://www.reddit.com/r/musicsuggestions/comments/w2rdfl/black_metal_thats_not_racist/) [with](https://www.reddit.com/r/MetalForTheMasses/comments/198cmzz/what_are_some_non_nazi_black_metal_bands/) [threads](https://www.reddit.com/r/MetalForTheMasses/comments/1e0krm6/what_are_some_black_metal_bands_that_dont_have/) started by people looking for safe picks to listen to. While you may, somehow, be able to "separate the art from the artist," it is especially important to avoid supporting white supremacist black metal groups in any way: mere word of mouth leads to revenue, and neo-nazis in the black metal scene use those funds to directly support recruitment and violence.[^1] Seriously, don't even talk about these bands with people; they don't deserve the attention, and [giving it to them can be dangerous](https://www.splcenter.org/fighting-hate/intelligence-report/2000/arrest-german-neo-nazi-reveals-growing-internationalization-white-power-music-scene).[^2]
With all that said, there is plenty of black metal made by good people, and it isn't especially hard to find. Reddit's [/r/rabm subreddit](https://www.reddit.com/r/rabm/) highlights explicitly leftist bands, so check there for some *definitely* safe choices, and before you go booking tickets to see that cool new band you found on Spotify[^3], it might be worth looking them up on [the metal archives](https://www.metal-archives.com/), specifically checking the "themes" section, reading their lyrics, and sniffing around reddit a bit.
## Is it worth the effort?
Absolutely. Extreme metal as a whole is known to host some of the most incredible musicians of the modern era; they say that the best drummers in the world either play jazz or death metal; metal guitarists are conspicuously excellent, and vocals that might sound like the consequence of some terrible disease require a great deal of skill to reproduce safely. A wide range of subgenres means that there's something for everyone in the world of extreme metal, whether you'd prefer to visit your city's orchestra or a basement math-rock show. Here are some killer black metal tunes that I'm rather fond of:
### Blacker Than Black - Mora Prokaza
{% audio "Blacker Than Black", "Mora Prokaza", "/audio/black_metal/session_Blacker Than Black.mp3", "/audio/black_metal/mora_prokaza_by_chance_album_cover.webp" %}
The most normal track on Mora Prokaza's incredibly bizarre album *By Chance*, *Blacker than Black* is a gentle introduction to the rapped vocal style of the album, without the unique instrumentation and distinctly un-metal song structures found in other tracks.
### I'm Not Yours - Mora Prokaza
{% audio "I'm Not Yours", "Mora Prokaza", "/audio/black_metal/session_I'm Not Yours.mp3", "/audio/black_metal/mora_prokaza_by_chance_album_cover.webp" %}
This is what Mora Prokaza's *By Chance* is all about: 808 sub bass, repetitive rapped black metal vocals compressed into percussive triplets, instrumentation incongruous with either black metal or trap: this album is nuts, and I'm here for it.
### The Thousand Tombs of Western Promise - Wayfarer
{% audio "The Thousand Tombs of Western Promise", "Wayfarer", "/audio/black_metal/session_The Thousand Tombs of Western Promise.mp3", "/audio/black_metal/wayfarer_american_gothic_album_cover.webp" %}
A distinctly American take on the genre, Wayfarer integrates blues with black metal in a way that's immensely satisfying and brings a sweeping musicality to their songs that can often be found missing outside of classically influenced, orchestral-leaning acts.
### Tyrannical - Rotting Christ
{% audio "Tyrannical", "Rotting Christ", "/audio/black_metal/session_Tyrannical.mp3", "/audio/black_metal/rotting_christ_sanctus_diavolos_album_cover.webp" %}
From one of my favorite albums of all time, *Tyrannical* is a fine example of one of the qualities I appreciate most in the Greek black metal genre mainstay Rotting Christ; the group is capable of creating music without ego. This track is pure vibes — individual musicians are always secondary to the goals of the composition, and the results are magical.
### Athanati Este - Rotting Christ
{% audio "Athanati Este", "Rotting Christ", "/audio/black_metal/session_Athanati Este.mp3", "/audio/black_metal/rotting_christ_sanctus_diavolos_album_cover.webp" %}
Athanati Este is a sludgy soundscape of staccato riffage punctuated by religious sounding chants and traditional percussion. The layering and treatment of the vocals, alongside the bells, really contributes to a nicely filled frequency range, which I appreciate.
### The Perpetual Horrors - Naglfar
{% audio "The Perpetual Horrors", "Naglfar", "/audio/black_metal/session_The Perpetual Horrors.mp3", "/audio/black_metal/naglfar_pariah_album_cover.webp" %}
Finally, a more traditional black metal tune. Just listen to that double bass pedal go, those impeccable vocals… there are those who will deride anything that doesn't sound like passing traffic recorded through an inch of styrofoam as metalcore; I am not among them. The musicality here is incredible; *The Perpetual Horrors* brings you along for a ride in a five-minute track that never gets boring.
### VI - Au-Dessus
{% audio "VI", "Au-Dessus", "/audio/black_metal/session_VI.mp3", "/audio/black_metal/au-dessus_end_of_chapter_album_cover.webp" %}
Starting with a droning vocal harmony, a repeating guitar riff, and gently syncopated drums, *VI* undulates between a more traditional black metal track, and a dramatic hard rock tone a la the chorus of Hurt's *Rapture*. Emphasis stays with the instrumentation, the vocals kept low in the mix as though they're coming from somewhere else. The effect is a full slow-moving soundscape that is, like Rotting Christ's *Tyrannical*, simply a vibe.
[^1]: This applies for supporting any sort of bigot: buying or even indirectly encouraging the purchase of anything that puts money into the hands of a bigot supports not only their lifestyle, but their activities, and amplifies their reach.
[^2]: So if you know something I don't about any of the bands I've featured here, do let me know so that I can remove them.
[^3]: It's better to buy music outright than use streaming services that barely pay artists, restrict how you use the music you pay for, and stand in the way of the preservation of music as a part of human culture. See [defectivebydesign.org/spotify](https://www.defectivebydesign.org/spotify) for more information.

View File

@ -0,0 +1,50 @@
---
title: "The Blog Questions Challenge"
description: Why I do this whole blogging thing.
date: 2025-03-12
tags:
- Meta
synopsis: Why I do this whole blogging thing.
---
If you haven't seen this going around the internet, you might be spending too little time on [the indieweb](https://indieweb.org/)! The blog questions challenge asks bloggers to talk about how and why they do what they do. Here's mine.
## Why did you start blogging in the first place?
As is common among those with ADHD, I've long felt that I have quite a lot to say and not enough people in my life who have the patience and willingness to sit through endless lengthy monologues; I have a lot of thoughts on a lot of things! Years ago I had a website where I published some of my ghastly teenage poetry—I think I write now for the same reason I did then: sometimes it just feels like I'll burst if I don't.
## What platform are you using to manage your blog and why did you choose it?
I'm using [Eleventy, AKA 11ty](https://www.11ty.dev/), which is a static site generator. A static site generator is a program that lets you code templates for your website, describe how it should work, and then it spits out pages based on your setup so that you don't have to code each new page or post. Static sites don't rely on a server running a content management system; they're literally just a bunch of files that you can host anywhere. They're fast and unhackable.
I chose Eleventy specifically because it's very flexible, and because I'm comfortable with JavaScript.
## Have you blogged on other platforms before?
I've used WordPress in the past, and I use it at work. It makes the editing experience nice and simple (something that is not true with Eleventy), but it also feels fragile and unwieldy to me so I try to avoid it where I can.
## How do you write your posts? For example, in a local editing tool, or in a panel/dashboard that's part of your blog?
I am a big fan of [KDE](https://kde.org/)'s [Kate](https://kate-editor.org/) text editor. No Electron bloat or Microsoft spyware, lots of great tools and plugins, and it's fast as all get out. Honestly, I'm a bit of a Kate evangelist, because I want to see more people working on plugins and language support for it rather than VS Code.
I must admit, I don't always want to use a code editor for blog posts, especially for longer, more involved posts and essays. So when this mood takes me, I'll use [Ghostwriter](https://ghostwriter.kde.org/). Another fabulous KDE project, Ghostwriter is a simple Markdown editor with neat features like distraction-free and fullscreen modes, and writing statistics like word-count and reading-ease.
## When do you feel most inspired to write?
Honestly, I can never predict when the urge will take me, or when hyperfocus will drive me onwards into the wee hours. Sometimes I'll have something cooking for a while, and I'll get swept away with it when I happen upon a text file where I've outlined the idea. Historically, I'm more productive in every way in the evening, but as I've been fiercely battling my circadian rhythm now for several years in the hopes of adapting to a more workplace friendly schedule, I'm occasionally raring to go in the morning provided I've had a good 9-12 hours of sleep.
## Do you publish immediately after writing, or do you let it simmer a bit as a draft?
Usually, finishing a post has me feeling like I've just run the gauntlet, so I'm itching to upload as soon as possible. If it's a longer piece or I've noticed my focus failing, I'll sometimes either have my partner give it a read or I'll sleep on it and re-read before running my `update-website` Zsh alias.
## What are you generally interested in writing about?
Lately mostly incense and computer stuff, but I'd also like to write some longer pieces on some of my core beliefs and opinions. For instance, I'm working on an essay about my feelings toward religion and spirituality. These types of posts are long, involved, and have to be done with some delicacy as they always carry the possibility of upsetting people, so it's going to take some time to get them out.
## Who are you writing for?
In general, I don't think I'm writing for any person or group in particular, including myself. With some posts, I'm just trying to put out a viewpoint that I haven't seen others write about, such as my [post on a tool that allows people to strip the storytelling from recipe blogs](https://nathanupchurch.com/blog/let-us-waffle/). When I write things like that, I'm writing to add what I think is a unique view to an ongoing conversation. For other things, I'm writing because [I think it's important that the information is made available](https://nathanupchurch.com/blog/making-incense/), or to [show support to a project or cause](https://nathanupchurch.com/blog/scribus-1-7-0-from-strength-to-strength/).
I think that writing [incense reviews](https://nathanupchurch.com/blog/maroma-incense-of-auroville-sandalwood-cedarwood/), however, is mostly for myself. I was once [a cocktail bartender](https://makertube.net/w/boNV8AQcufwtaZVg9vUh1Q). When I started out at a high-end Chicago cocktail lounge, the beverage director would ask the bar-back to bring us two Glencairn glasses, each containing a pour of one of the 500+ spirits on the wall behind the bar. He'd then ask me to write down what the spirit was, how long it had been aged, the proof, and five tasting notes. Once you've tasted enough spirits it's not terribly hard to do, so I became quite good at it, but I always found the process quite stressful nonetheless. I worked in coffee for some time after that, and I found coffee cuppings even more anxiety-inducing[^1] because the strong fragrances would burn my nose out almost immediately. When swishing spirits around in my mouth, I don't ever feel that my ability to distinguish flavor notes diminishes, but fragrance can be fleeting as the brain compensates for the presence of whatever aromatics are floating into your sniffer. For the same reasons, I find reviewing incense quite difficult. Posting reviews gives me a reason to keep at it, to keep learning and expanding my 'olfactory library,' and to improve at picking out and identifying notes. It also helps me to be more objective and analytical when testing my own incense.
## What's your favourite blog post?
I'm quite proud of *[What Do We Expect from Fragrance? Natural Incense in an Unnatural World ](../what-do-we-expect-from-fragrance/)*. It sums up my views on how fragrance is used and abused in our time, and where incense fits into all of this.
## Any future plans for your blog? Maybe a redesign, a move to another platform, or adding a new feature?
I never actually sat down and planned out a design for my website; I just started writing code, so I'm forever self-conscious of the design of my site. At some point I may sit down and actually put together a concept and execute on it. Will that satisfy me? Who knows.
## Who's next?
To avoid unduly burdening anyone individually, I'm going to do as [Alistair Shepherd](https://alistairshepherd.uk/writing/blog-questions-challenge/) did and say that if you haven't done one of these yet and you'd like to: you're up!
[^1]: Coffee is harder than cocktails full stop. Once you've got the hang of the basic cocktail categories and their builds, you're singing, whereas coffee is temperamental, and more technically difficult on every level. I promise you that the job of your favorite barista at any decent shop is much more difficult than that of any fancy cocktail bartender.

View File

@ -4,6 +4,8 @@ description: I make a simple, three-ingredient, red cedar and frankincense batch
date: 2024-05-08
tags:
- Incense
- Incense Making
- Incense Builds (Recipes)
synopsis: I make a simple, three-ingredient, red cedar and frankincense batch of incense sticks.
imageURL: /img/cedar_frank.webp
imageAlt: A bunch of coreless incense sticks on top of some cedar planks next to a pile of frankincense tears.

View File

@ -1,14 +0,0 @@
---
title: Cowsay of the Day Science
description: An ASCII cow postulates on the state of science education in the modern world.
date: 2024-01-02
tags:
- Cowsay of the Day
synopsis: An ASCII cow postulates on the state of science education in the modern world.
imageURL: /img/cowsayOfTheDay.avif
imageAlt: An ASCII cow with a thought bubble containing the word wut
mastodon_id: "111688829907363670"
---
As a big-old nerd, I spend a lot of time in the terminal on my computer. When you spend a lot of time somewhere, you want it to be comfortable. As a part of making my terminal more homey, I've set it up to give me a random quote each time I start a new session, delivered, of course, by a cow. Here's today's cowsay of the day:
{{ cowList.onScience | cowsay | safe }}

View File

@ -3,6 +3,7 @@ title: Free Software is the Future for SMEs and Small Nonprofits
description: Tech giants aren't meeting the needs of SMEs and nonprofits. Combined with digital privacy concerns, a perfect storm is brewing for increased adoption of free and open source software for these organizations.
date: 2022-10-28
tags:
- Essays
- FOSS/FLOSS
- Digital Privacy
synopsis: Tech giants aren't meeting the needs of SMEs and nonprofits. Combined with digital privacy concerns, a perfect storm is brewing for increased adoption of free and open source software for these organizations.

188
content/blog/galleries.md Normal file
View File

@ -0,0 +1,188 @@
---
title: Adding Image Galleries to My Website
description: At last, I've gotten around to implementing image galleries.
date: 2024-12-02
tags:
- Site Updates
- Eleventy
synopsis: At last, I've gotten around to implementing image galleries.
imageURL: /img/isabella-fischer-X2l9M6jsS7E-unsplash.webp
imageAlt: Some very tasty looking pop tarts with pink icing and sprinkles.
mastodon_id: "113586087349853099"
---
I've been meaning to add an image gallery feature to this website for ages, and I'm happy to finally announce that I've done it! If you'd like to see my very first image gallery in action, [here's a gallery of PopTart memes I've collected](../../gallery/pop-tart-flavor-memes/). If you're a massive nerd and would like to read about how I implemented this feature on my [Eleventy](https://www.11ty.dev/) website, read on.
Note: this is a fast and loose description of the process. It should be helpful if you're trying to do this yourself, but don't expect to be able to copy and paste my implementation. See [the repo](https://upchur.ch/gitea/n_u/nathanupchurch.com) to copy and paste my spaghetti.
## Specifying new galleries
First of all, I had to decide how new galleries would be specified so that Eleventy could work its magic. There are a few approaches here, such as utilizing template frontmatter, directories of images, or using a data file in my site's `_data` directory. After weighing up the pros and cons, I decided to use the latter option, even though it's not the most ergonomic. So I created `_data/galleries.js`, which looks like this[^1]:
``` javascript
export default [
{
title: "",
description: "",
synopsis: "",
url: "",
date: new Date(""),
galleryImage: "",
galleryImageAlt: "",
pictures: [
{
title: "",
filename: "",
altText: "",
thumbAltText: "",
caption: "",
},
],
},
];
```
## Gallery index pagination
Now that I know how I'll go about specifying my galleries, I need to paginate the gallery index pages; the pages that feature thumbnails of each image in the gallery and allow the user to navigate to the images. To do this, I created `content/galleries.njk`:
``` html
---{% raw %}
pagination:
data: galleries
size: 1
alias: gallery
layout: layouts/base.njk
tags: gallery
eleventyComputed:
title: "{{ gallery.title }}"
permalink: "/gallery/{{ gallery.title | slugify }}/"
description: "{{ gallery.description }}"
---
<h1>{{ gallery.title }}</h1>
<p>{{ gallery.description }}</p>
<section>
{% for picture in gallery.pictures %}
<a href="/gallery/{{ gallery.title | slugify }}/{{ picture.filename | slugify }}/">
<div>
<img alt="{{ gallery.thumbAltText }}" class="gallery-image" src="{{ gallery.url }}{{ picture.filename }}">
</div>
</a>
{% endfor %}{% endraw %}
</section>
```
By ensuring that each gallery index page is tagged "gallery," they will automatically be grouped into a new collection by that name, which is important so that I can filter galleries out from post lists and other things throughout my site.
## Generating image pages
I considered using a lightbox / modal sort of arrangement for viewing images, but I decided against it as it can be tricky to get accessibility right for these patterns, and I wanted to avoid using JavaScript if possible. What I chose to do instead was to create a page for each image, which would feature buttons to navigate to the next / previous image, and to return to the gallery. The first step was to create a collection containing all gallery images in my Eleventy config file:
``` javascript
// Collections
eleventyConfig.addCollection("galleryImages", (collection) => {
const galleries = collection.getAll()[0].data.galleries;
let galleryImages = [];
galleries.forEach((gallery) => {
gallery.pictures.forEach((picture, i, arr) => {
picture.containingGallery = `${gallery.title}`;
picture.baseUrl = `${gallery.url}`;
i ? (picture.previousImage = arr[i - 1].filename) : null;
i + 1 != arr.length ? (picture.nextImage = arr[i + 1].filename) : null;
galleryImages.push(picture);
});
});
```
You may notice that I did a little jiggery-pokery in that callback function to provide information about each image that isn't included in `_data/galleries.js` because it would have been a pain to include or would have unecessarily inflated the tile size, specifically: the filenames of images before and after the current image (should they exist), and the URL of the gallery that the image belongs to. We can use this information to have our image pages generated in the same directory as their parent gallery index, and to generate next / previous buttons to help the user navigate through the gallery. This information is added to the `galleryImages` collection object in memory so that we can use it when we paginate the image pages using `content/galleryImage.njk`:
``` html{% raw %}
---
pagination:
data: collections.galleryImages
size: 1
alias: picture
layout: layouts/base.njk
eleventyComputed:
title: "Image: {{ picture.title }}"
permalink: "/gallery/{{ picture.containingGallery | slugify }}/{{ picture.filename | slugify }}/"
description: "{{ picture.title }} from gallery: {{ picture.containingGallery}}"
---
<article>
<h1>{{ picture.title }}</h1>
<div>
{% if picture.previousImage %}
<a href="../{{ picture.previousImage | slugify }}">
<button type="button">Previous</button>
</a>
{% endif %}
<a href="/gallery/{{ picture.containingGallery | slugify }}/">
<button type="button">Gallery</button>
</a>
{% if picture.nextImage %}
<a href="../{{ picture.nextImage | slugify }}">
<button type="button">Next</button>
</a>
{% endif %}
</div>
<figure>
<a href="{{ picture.baseUrl }}/{{ picture.filename }}">
<img src="{{ picture.baseUrl }}/{{ picture.filename }}" alt="{{ picture.altText }}">
</a>
{% if picture.caption %}
<figcaption>
{{ picture.caption }}
</figcaption>
{% endif %}
</figure>
</article>{% endraw %}
```
Et voilà; we have galleries! But before we can call this project done, it would be nice to have a page that lists all galleries on the site for the benefit of visitors. For this, I created `/content/galleries/index.njk`:
``` html{% raw %}
---
layout: layouts/base.njk
eleventyNavigation:
key: Pics
order: 4
---
<h1>Image Galleries</h1>
<p>
Some pictures I thought would be worth posting.
</p>
<section>
<div>
{% for gallery in galleries %}
<article>
<a href="../gallery/{{ gallery.title | slugify }}" class="postlist-link">
<div>
<img {% if gallery.galleryImage %} src="{{ gallery.url }}{{ gallery.galleryImage }}" alt="{{ gallery.galleryImageAlt }}" {% else %} src="{{ metadata.defaultPostImageURL }}" alt="{{ metadata.defaultPostImageAlt }}"{% endif %}>
</div>
</a>
<div>
<a href="../gallery/{{ gallery.title | slugify }}" class="postlist-link">
<h3>
{{ gallery.title }}
</h3>
</a>
<time datetime="{{ gallery.date | htmlDateString}}">{{ gallery.date | readableDate("LLLL yyyy") }}</time>
<p>{{ gallery.synopsis | truncate(105) | safe }}</p>
</div>
</article>
{% endfor %}
</div>
</section>
```{% endraw %}
Note that `readableDate()` and `htmlDateString` are custom filters that came with the [Eleventy Base Blog template](https://github.com/11ty/eleventy-base-blog) that I based my website on. They require Luxon:
``` javascript
eleventyConfig.addFilter("readableDate", (dateObj, format, zone) => {
// Formatting tokens for Luxon: https://moment.github.io/luxon/#/formatting?id=table-of-tokens
return DateTime.fromJSDate(dateObj, { zone: zone || "utc" }).toFormat(
format || "dd LLLL yyyy",
);
});
eleventyConfig.addFilter("htmlDateString", (dateObj) => {
// dateObj input: https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-date-string
return DateTime.fromJSDate(dateObj, { zone: "utc" }).toFormat("yyyy-LL-dd");
});
```
You may be thinking that this all seems a convoluted, and I agree! If you know of a simpler way to accomplish this functionality, do feel free to let me know, but for now, I'm just happy that I finally have the ability to add image galleries to this website.
[^1]: Thanks to those who answered [my cry for help](https://lounge.town/@nathanu/113574428382435982)!

View File

@ -4,6 +4,8 @@ description: Failing to make the most delicious batch of incense ever.
date: 2024-04-13
tags:
- Incense
- Incense Making
- Incense Builds (Recipes)
synopsis: My grand designs crumble as I fail to make the most delicious batch of incense ever devised.
imageURL: /img/_DSC0079_copy.avif
imageAlt: A small pile of short smooth brown incense sticks on a piece of MDF.

View File

@ -4,6 +4,8 @@ description: "I finally figure out how to make myrrh work in a composition."
date: 2024-08-05
tags:
- Incense
- Incense Making
- Incense Builds (Recipes)
synopsis: "I finally figure out how to make myrrh work in a composition."
imageURL: /img/pexels-david-roberts-940521-8323579.webp
imageAlt: A beautiful light-pink dog rose, rosa canina.

View File

@ -0,0 +1,75 @@
---
title: "Making Incense: A Cursory Guide"
description: A quick how-to on making Japanese style incense.
date: 2024-12-16
tags:
- Incense
- Incense Making
synopsis: A quick how-to on making Japanese style incense.
imageURL: /img/siftinsagesquare.webp
imageAlt: A sieve containing fluffy ground green sage beside a small pile of fine green powder.
mastodon_id: "113666537272260557"
---
While I like to post incense builds, I haven't yet posted on exactly how to go about turning raw ingredients into Japanese style incense sticks. Here's a 1,000 mile overview of the process to accompany a video I recently uploaded to my new PeerTube instance on that very topic. For more info, you can check out [IncenseDragon](https://www.youtube.com/c/IncenseDragon) on YouTube, read this [very useful article](https://blog.rauchfahne.de/en/2023/02/19/making-your-own-incense-sticks-basic-knowledge-and-useful-information/) by Irene of Rauchfahne.de, peruse [incensemaking.com](https://incensemaking.com), and look through some [posts flaired with "incense making"](https://www.reddit.com/r/Incense/?f=flair_name%3A%22Incense%20Making%22) on the [incense subreddit](https://reddit.com/r/incense). Making incense is a difficult, involved process, and this is only a shallow overview; I highly recommend looking through these resources for more in-depth information.
<figure><div style="position: relative; padding-top: 56.25%;"><iframe title="Japanese Style Incense Making Process" width="100%" height="100%" src="https://makertube.net/videos/embed/8864549d-204b-4f48-884e-ca912cf4235c" frameborder="0" allowfullscreen="" sandbox="allow-same-origin allow-scripts allow-popups allow-forms" style="position: absolute; inset: 0px;"></iframe></div><figcaption>More or less the full process of making incense. It didn't go perfectly, but I think it's important to show that too. This is also the first time I've attempted to make a video like this; making incense is hard as is, let alone while trying to film the process!</figcaption></figure>
## What you'll need: the bare minimum
1. A scale
2. A mortar and pestle
3. A 140 mesh sieve
4. An extruder
5. A drying screen
6. A respirator
### A scale
If you can, get something quite fine, like a milligram scale. This will help you make very small test batches before you commit to a build.
### A mortar and pestle
You can't get all your ingredients pre-powdered, so you're going to need something to crush resins and grind herbs. It's a labor intensive method, but it produces very little heat - perfect for delicate aromatics. At some point, you'll likely want to expand your grinding capabilities, especially if you want to grind your own woods, but that's a topic for another time.
### A 140 mesh sieve
100 microns seems to be the magic number for incense powders; ingredients reduced to this size perform better in terms of fragrance, and ease of extrusion. Your sticks will burn more slowly, and you'll be able to use less binder in the dough. Sieve carefully, allowing only the finest particles to pass through.
### An extruder
I use [one of these (not an affiliate link)](https://www.aliexpress.us/item/3256804509917099.html). There are many options available, but try to find an extruder that gradually comes to a point rather than one that takes interchangeable plates - they'll produce rough sticks. Also avoid anything made of plastic; I promise you it won't be strong enough.
### A drying screen
Again, there are many options, some of which you may have already laying around. I use [one of these (also not an affiliate link)](https://www.aliexpress.us/item/3256806230786054.html).
### A respirator
I almost forgot to mention this, but [as Irene points out](https://blog.rauchfahne.de/en/2023/02/19/making-your-own-incense-sticks-basic-knowledge-and-useful-information/) this is an important piece. Inhaling fine powders of any kind is very very bad for you. Don't mess about with this one: use a proper respirator, or at least a well-fitted n95 mask.
## Coming up with a build
If you don't have a build / recipe to go by, it can be a challenge to work out what ingredients to use and in what proportions. While you can find builds in many places, eventually you're going to have to sit down and do some testing. Fundamentally, incense is comprised of three key components: base, binder, and aromatics. Some ingredients can occupy more than one of these categories. It's difficult to give even rough ratios for these components, because they will differ wildly with the specific ingredients used. What I recommend is combining ingredients in different ratios and burning them as a trail on a bed of ash, little by little. For instance, try burning a trail of 70% sandalwood and 30% frankincense. How does it burn; does it stay lit? Which fragrance is more prominent? Is it aromatic, or mostly smoky? How does this build change when 10% of the sandalwood is exchanged for lavender, or patchouli? Once you've got a fragrance you're happy with, incorporate some binder and try to burn again.
I could write extensively on this piece alone, but for now, here are some general rules to get you started:
* Herbs and flowers quickly become acrid unless used in low percentages. In [my Silver Tip build](../silvertip/), for example, I can only get away with 10% osmanthus flowers before my build begins to smell bad.
* Oily woods such as mid to high quality sandalwood, palo santo, and agarwood can be used at high percentages without smelling too smoky.
* Resins are good not only fragrant, but some can be used for binding and temperature regulation. Too much will prevent your sticks from burning, so work your way up slowly with resins.
* Less is more. It's always tempting to cram as much of an aromatic material into a stick as you can. Instead, try to see how little you can get away with for a more refined profile.
* Gum binders such as guar gum, xanthan gum, and tragacanth can be used at very low percentages — I've seen as low as 3%. Wood binders such as litsea glutinosa can require much larger percentages. After you've successfully incorporated a binder into the sample you used for a trail-burn test, try adding a drop or two of water and rolling a small stick by hand to see how the dough performs.
## Grinding
Possibly the most difficult aspect of incense making, the key to grinding quality powders is to keep things cool. Use electric grinders in short bursts, allowing ample time to cool, or use methods that generate less heat. Not only does heat release aromatics that you want to retain, resins get sticky. If using a mortar and pestle, it can help to freeze resins along with your mortar and pestle to keep from gumming up the works. It may be easiest to buy pre-powdered woods at first; while resins and herbs aren't especially difficult to powder at home, grinding wood is another beast altogether.
## Sieving
Sieve slowly and gently, being careful that only the finest particles pass through the screen. The best advice I can give here is to try to enjoy the time you spend sieving as best you can, because you're going to be spending a lot of time this way.
## Forming a dough
First thoroughly blend together your dry powdered ingredients, then add water with great trepidation while stirring until a dough begins to come together. As soon as you are able, knead this dough with your hands, adding water as necessary to form a smooth dough that doesn't crack when rolled into a ball. Too much water will result in a difficult extrusion and more warping during drying; too little will result in an even more difficult extrusion. Aim for the consistency of clay.
## Extrusion
Load the dough into your extruder, being very careful to avoid introducing any air bubbles. Carefully extrude the incense either onto a board, or directly onto your drying screen.
## Straightening and drying
Trim your sticks into even lengths while wet, and gently roll them with either a board, or your fingers, until they are straight. Carefully lay them side by side on your drying screen, and place a board against the length of the sticks to prevent too much horizontal warping as they dry. Cover the sticks with another board to prevent vertical warping, and allow the sticks to dry slowly over the course of a day or two.
## Curing
Although your incense may appear dry, it can take some time for much of the moisture to work its way out. Ingredients also benefit from time for the aromatics to settle and meld together into a cohesive composition. Give your sticks a couple of weeks before you judge them too harshly; you may notice changes in fragrance for up to a year.
## Conclusion
This is how I make my sticks, which I extrude to ~2mm and about 10" long to be broken into 5" lengths after drying. Hopefully, any builds I post here ought to work when extruded to this size in the way I have described; all sorts of factors affect incense fragrance and its ability to burn, so I can't make any guarantees as to how your incense will turn out if you follow one of my builds for a different extrusion diameter.
Incense making is a dying art even in cultures with strong incense traditions; it's a laborious exercise that requires extensive trial and error, but the results can be beautiful in ways that no other art-form can emulate. Unfortunately, incense makers tend to be opaque with their practices, and information is scarce in the English speaking world, so it is my hope that this guide can be a useful launching point for someone wishing to start down the fragrant path.

View File

@ -0,0 +1,173 @@
---
title: "Building a Quiz System With Eleventy"
description: "Remember when internet quizzes were a thing? I wanted to bring them to my website."
date: 2025-02-04
tags:
- Site Updates
- Eleventy
synopsis: "Remember when internet quizzes were a thing? I wanted to bring them to my website."
imageURL: ""
imageAlt: ""
mastodon_id: "113948404881440370"
---
You might seen my [recent toot](https://lounge.town/@nathanu/113936929893588739) about the [fancy new "How Much of a Linux Nerd are You?" quiz](/quizzes/how-much-of-a-linux-nerd-are-you/) on my website. Some time ago, I realized that I missed taking fun internet quizzes and decided to implement a quiz system on my own site that would allow me to easily make fun quizzes to share. Here's how I built it with [Eleventy](https://www.11ty.dev/).
## The plan
First, I had to decide what sort of quizzes I wanted to be able to make. Some quizzes are designed to score the quiz-taker in order to place them into a category at the end, like those fun Buzzfeed quizzes that used to be so popular. Other quizzes are designed to test the quiz-takers knowledge of a subject, with each question having a definite right answer. I wanted to be able to do both, and I wanted my quizzes to be fairly flexible.
I decided to arrange things so that the quiz-author can enter any number of questions, answers, and consequences. While any number of answers can be entered for a given question, only one answer can be selected at a time, and every question must be answered. Each answer is assigned a number of points by the quiz author: positive, negative, or zero, and consequences each have a certain points threshold after which they are eligible to appear.
A consequence is a result that appears in a modal when the quiz-taker clicks the "submit" button at the end. It shows text defined by the quiz author, an image if the author chooses to include one, and it contains a "Score Details" dropdown that shows the number of points scored on each question.
I decided that I didn't want to use a global data file, not only because it isn't terribly ergonomic, but also because it's much simpler to take advantage of Eleventy's tag/collection system when possible, and frankly, I hoped to avoid some of the faffing about I had to do when [implementing image galleries](/blog/galleries/).
## Setting up the content directory
As I was going to use markdown files to build my quizzes, I needed to set up a content directory, `/content/quizzes/`, and set some defaults in `/content/quizzes/quizzes.11tydata.js` to make sure that everything I put inside of it was automatically tagged as a quiz, and would use the correct layout.
```javascript
export default {
tags: ["quiz"],
layout: "layouts/quizzes.njk",
};
```
By tagging these files as quizzes, a new [collection](https://www.11ty.dev/docs/collections/) containing all of my quizzes will be created, and I can add this collection to the `filterTagList` filter in my config file that allows me to easily omit everything that isn't a blog post from post-lists on my site, but that's out of scope for this article.
## Quiz Structure
YAML (or in fact any markup or programming language that respects whitespace) is no fun, but at least I won't wind up with a gargantuan JavaScript data file like I have [for my galleries](https://upchur.ch/gitea/n_u/nathanupchurch.com/src/branch/main/_data/galleries.js). Here's what `/content/quizzes/my-quiz.md` might look like:
``` yaml
---
title: ""
description: ""
date: 2025-02-04
imageURL: ""
imageAlt: ""
consequences:
- title: ""
points: 0
spiel: ""
image: ""
imageAlt: ""
questions:
- title: ""
image: ""
imageAlt: ""
imageCaption: ""
answers:
- name: ""
points: 0
---
This is a great quiz that I'm sure you'll have fun taking.
```
This results in a nice JavaScript object we can iterate through. In the body of the markdown document, beneath the front matter, is the text that can be injected via `{% raw %}{{ content }}{% endraw %}`. You'll see in a bit that this will go at the top of the quiz, beneath the title, which is injected with my post layout. This is so that it's easy to use markdown to style this part of the content, include images, et cetera, without worrying about trying to get that working while including it in the YAML.
## The quiz layout
Alright! Now that we have the quiz structure nailed down, we can write `/includes/layouts/quizzes.njk` which will iterate through the data and spit out an HTML form for us. I'm using the loop index number as the question number, which I can also use to set the `name` attribute for each of the answer `<input>` elements related to a given question. By doing this, the browser knows that the answers beneath a question are all related and will only allow the quiz-taker to select one of them.
I'm going to add a link to our yet-to-be-written script here and set the form to call `handleQuizSubmit()` on submit (`return false` prevents the page from refreshing when the submit button is clicked). Don't ask me why I put the script there precisely; as it isn't called until the submit button is clicked, I suppose it could go just about anywhere.
The points threshold for each consequence is stored in the [dataset](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset) `data-points-threshold` so that we can use these numbers in our JavaScript.
The answers are assigned an ID that looks like this: `q[questionNumber]a[answerNumber]`. Beyond using this to also populate the `for` property of their respective labels, you could use this to link to individual answers too.
```html
---
layout: layouts/post.njk
structuredData: none
---{% raw %}
{{ content | safe }}
<section class="quiz">
<form onsubmit="handleQuizSubmit(); return false">
{% for question in questions %}
{% set q = loop.index %}
<div class="questionBox">
<p class="quizQuestion">{{ q }}. {{ question.title }}</p>
{% if question.image %}
<figure>
<a href="{{ question.image }}">
<img src="{{ question.image }}" alt="{{ question.imageAlt }}">
</a>
{% if question.imageCaption %}
<figcaption>{{ question.imageCaption }}</figcaption>
{% endif %}
</figure>
{% endif %}
<div class="answersBox">
{% for answer in question.answers %}
<div class="answerBox">
<input class="answer" type="radio" value="{{ answer.points }}" id="q{{ q }}a{{ loop.index }}" name="{{ q }}" required>
<label for="q{{ q }}a{{ loop.index }}">{{ answer.name }}</label>
</div>
{% endfor %}
</div>
</div>
{% endfor %}
<script src="/js/quiz.js"></script>
<button>Submit</button>
</form>
</section>
{% for consequence in consequences %}
<dialog class="consequence" data-points-threshold="{{ consequence.points }}">
<h2>{{ consequence.title }}</h2>
<p>{{ consequence.spiel }}</p>
{% if consequence.image %}
<img src="{{ consequence.image }}" alt="{{ consequence.imageAlt }}">
{% endif %}
<details>
<summary>Score Details</summary>
<p class="scoreDetails"></p>
</details>
<form method="dialog">
<button>Thanks</button>
</form>
</dialog>
{% endfor %}{% endraw %}
```
All of the consequences are rendered as `<dialog>` elements that we can open as a modal later with our script. And look, I know people have opinions about JavaScript, but I really didn't fancy the extra build time, bandwidth, and effort it would have taken to avoid fourty lines of simple JavaScript, and to be honest, I *like* JavaScript. I think it's useful and fun to write, so there.
## The quiz script
As far as logic goes, in `/js/quiz.js` we first want to calculate the score, and get the data to populate the `<details>` elements in our consequence modals. This is handled by `score()`, which will return an object containing the total number of points scored and an array containing the points scored on each question. When we have that, we'll go ahead and `populateDetails()` and finally use `dishOutConsequences()` to launch the freshly updated `<dialog>` as a modal via `showModal()`.
```javascript
const score = (answers) => {
let total = 0;
let scores = [];
for (let i = 0; i < answers.length; i++) {
const questionNumber = answers[i].name;
if (answers[i].checked) {
total += Number(answers[i].value);
scores.push({
questionNumber: questionNumber,
points: answers[i].value,
});
}
}
return { totalPoints: total, scores: scores };
};
const dishOutConsequences = (consequences, points) => {
for (let i = consequences.length - 1; i >= 0; i--) {
if (points >= Number(consequences[i].dataset.pointsThreshold)) {
consequences[i].showModal();
return;
}
}
};
const populateDetails = (detailsElement, scores, total) => {
detailsElement.innerHTML = `Total Score: ${total} points<br />`;
for (let i = 0; i < scores.length; i++) {
detailsElement.innerHTML += `<br />Question ${scores[i].questionNumber >= 10 ? scores[i].questionNumber : "0" + scores[i].questionNumber}: ${scores[i].points} points`;
}
};
const handleQuizSubmit = () => {
const answers = document.getElementsByClassName("answer");
const consequences = document.getElementsByClassName("consequence");
const details = document.getElementsByClassName("scoreDetails");
const totalPoints = score(answers).totalPoints;
const scoreDetails = score(answers).scores;
for (let i = 0; i < details.length; i++) {
populateDetails(details[i], scoreDetails, totalPoints);
}
dishOutConsequences(consequences, totalPoints);
};
```
And with that, our quiz ought to be operational! After this, I went ahead and listed my latest quiz on my index page, but that's beyond the scope of this article. It took me some time to get around to finishing this, but as you can see, it wasn't terribly difficult at all. I hope you enjoyed reading about how I built my quiz system. Please let me know if you decide to implement something similar!

View File

@ -0,0 +1,46 @@
---
title: "Incense Review: Maroma Sandalwood and Cedarwood"
description: "Whole Foods replaced Shoyeido with these sticks from Auroville. I cannot fathom why."
date: 2025-02-22
tags:
- Incense
- Incense Review
synopsis: "Whole Foods replaced Shoyeido with these sticks from Auroville. I cannot fathom why."
imageURL: "/img/maroma_packaging.webp"
imageAlt: "Two paper incense sleeves on my couch. One is yellow and the other is orange."
mastodon_id: "114050541028761876"
---
Some time ago I as I perused the incense display of a nearby Whole Foods, hoping to see the Shoyeido sticks that once graced the shelves, I noticed a range of Indian-style sticks, their otherwise matching packaging in a variety of colors. Listed prominently on each package was the text: "Incense of Auroville." This caught my attention. Auroville is an intentional community I've had a passing interest in since I discovered that some shampoo bars I had purchased were made there[^1]. Often, Indian-style incense makes *heavy* use of oils, which I'm [not a great fan of](/blog/what-do-we-expect-from-fragrance/). The sandalwood and cedarwood varieties, however, listed fairly harmless looking ingredients. According to the packaging, both contained a bamboo stick, wood powders, macchilus macaranth (tree bark powder), with the addition of either sandalwood, or cedarwood, pine, and juniper, respectively. With all of this in mind, I snagged a couple of sleeves.
## Humor me while I appreciate the packaging
As a former print broker and a current designer and print nerd, I first have to take a second to admire the packaging.
[![Two paper incense sleeves on my couch. One is yellow and the other is orange.](/img/maroma_packaging.webp "I know they're not terribly exciting visually, but hear me out.")](/img/maroma_packaging.webp)
Sure, it's not cutting edge design, but this packaging was produced by someone who knows what they're doing. The sleeves appear to be litho printed on colored card-stock (between 200 and 250 g/m2[^2] if I were to guess) in four opaque inks[^3], with a nice metallic silver ink on the cedarwood sleeve. The sleeves are comprised of a single die-cut and scored piece that folds over on itself and is glued together, which would explain the large peg-hole[^4] that would accommodate for potential registration issues when glued and folded. The card-stock is also embossed with a subtle texture: linen for the sandalwood sticks, and a pebbled texture for the cedarwood.
I need you to understand that *hardly anyone* designs print like this anymore. In today's world of digital presses and cheap, mass-produced CMYK printing a la [Vistaprint](https://www.vistaprint.com/), this is not a cheap job. While many outsourced print work for SMEs goes to these large budget printers who run hundreds of jobs at once as quickly and cheaply as they can on standard house stocks, for these sticks, an honest-to-god clunking metal press was set up specially for each sleeve variety. This mode of production used to be standard, but is now largely considered higher-end. While Maroma's packaging is not quite on the same level in terms of process and materials, it does remind me of the kind of print I used to produce for clients like [Reid & Taylor](https://bondwiththebest.com/home/), or [Torrance Yachts](https://torranceyachts.com/). You love to see it. Not every product needs to be printed in full-color on bright-white gloss coated card-stock like a damned cereal box!
## Sandalwood
Now, on to the actual incense. Despite the ingredients list, the fragrance on the unlit sticks leads me to suspect that some oil may have been used. If this is the case, it has been used sparingly as this is not a strongly scented stick, neither before nor after it has been lit. During and after the burn, I don't detect any of the off-notes that mark the presence of large quantities of burning oils. The mild sandalwood fragrance smells more Australian than Indian to my nose; it's on the dry side, with little to none of that butteriness you might expect from santalum album.
[![A stick burning in a blue ceramid censer from Shoyeido on my coffee table. In the background you can see a pair of glasses, a mug, and a brass tealight incense warmer on a pile of glass coasters.](/img/maroma_sandalwood.webp "Fortunately, the fragrance of this stick will not soak into your soft furnishings. I can't say the same for the next one…")](/img/maroma_sandalwood.webp)
There is a wood-smoke note that comes through just as much as the sandalwood does, rendering the fragrance not a particularly clean one, especially when compared to something like Shunkohdo's delightful Sarasōju sticks. It's hard to say whether this comes from the "wood powders" mentioned in the ingredients list, the bamboo stick, a high burn-temperature due to stick thickness or the coarse grind of the ingredients, or all of the above—not that I mind a bit of smokiness in incense—I often quite enjoy this quality in Tibetan and Cambodian style sticks, but it really isn't what I'm looking for in a sandalwood stick.
Overall, Maroma's sandalwood sticks offer a mild, sweet, and earthy wood-smoke and sandalwood fragrance that is more inoffensive than pleasant; nonetheless, the sleeve I purchased is now empty.
## Cedarwood
Despite listed ingredients, this stick is very clearly oil-based. As opposed to the sandalwood sticks, which are wrapped in paper inside their card-stock sleeve, the cedarwood sticks come wrapped in plastic, presumably so as to prevent porous wrapping-paper from wicking up any oils.
The fragrance on the stick is very strong, soapy, and turpenous—even lavender-like. The experience of smelling the unlit stick reminds me a bit of using those pungent [inhalers for nasal congestion](https://www.amazon.com/Benzedrex-61023-Nasal-Decongestant-Inhaler/dp/B000X76K04); it's not exactly a pleasant experience, but you somehow want to keep doing it anyway. The fragrance upon lighting is bright, acidic, and juniper-forward. As the scent builds in the room, the cologne-like fragrance becomes increasingly sharp; after only a few minutes of burn time in my reasonably large office with a tall cathedral ceiling, it has utterly saturated the room and now evokes an under-ripe granny-smith apple. There is a moderately strong 'burning oil' off-note, as well as a spicy wood-smoke, similar to the that in their sandalwood stick. I am sure that the fragrance would be pleasant absent those off notes and its eye-watering strength, but as it is, it smells more like someone's lit a cigarette in the supermarket cleaning-chemical aisle.
## Conclusion and further reading
While I didn't mind having a sandalwood stick from Maroma burning, the cedarwood variety could not be further from the style of incense that I typically enjoy. [Like Irene of Rauchfahne](https://blog.rauchfahne.de/en/2024/11/23/pema-of-tibet-faircense-sandelholz-en/), my recommendation would be that those wanting a plain sandalwood fragrance look to Japanese style sticks, and unless you have a cathedral to fill with fragrance, I'd avoid the cedarwood too (and even then I'd prefer a thurible of frankincense).
If you'd like to read more, [Irene](https://blog.rauchfahne.de/en/category/reviews-en/reviews-sorted-by-brand/auroville-mereville-trust/), [Mike (?) of Olfactory Review Service](https://olfactoryrescueservice.wordpress.com/2009/12/18/sampler-notes-maroma-scented-mountain/), and [Steve of Incense in the Wind](https://incenseinthewind.blogspot.com/search?q=auroville) have written about a number of sticks that also appear to have been made in Auroville.
[^1]: My impression of the place, from the couple of videos I've watched about it, is that it's another landing site for wealthy, predominantly white, people who have a vague sense that something isn't quite right with western society / capitalism, but rather than confront this idea intellectually, investigate any sort of political theory, and organize / engage in mutual-aid, they choose to settle like kombucha sediment into some nebulous, ill-defined form of spirituality involving psychedelics and loose-fitting trousers. I could be wrong though.
[^2]: See [grammage](https://www.neenahpaper.com/resources/paper-101/glossary-of-terms#G) on Neenah Paper's online glossary.
[^3]: The two on the front, plus black and white ink on the back.
[^4]: Get your mind out of the gutter!

View File

@ -0,0 +1,17 @@
---
title: "A New Audio Web Component; Ballin"
description: "I've gone and built a not-so-fancy audio component for my blog."
date: 2024-10-23
tags:
- Music
- Site Updates
synopsis: "I've gone and built a not-so-fancy audio component for my blog."
imageURL: /audio/covers/ballin.webp
imageAlt: An uncapped fountain pen on top of a pretty, gold-foiled pad of paper beside some envelopes with stamps featuring coffee drinks on them.
mastodon_id: "113360498256457079"
---
Fresh from [my text editor](https://kate-editor.org/) comes a neat little web component that packages the native HTML `<audio>` tag inside a `<figure>` with a song name, title, and a graphic — an album cover perhaps. Here's what it looks like, featuring a very catchy drum and bass tune, "Ballin'," by Vibe Chemistry:
{% audio "Ballin", "Vibe Chemistry", "/audio/ballin.mp3", "/audio/covers/ballin.webp" %}
It's pretty basic for now; it doesn't even truncate an over-long title, but it'll do the job for the moment. My hope is to use this to play short song snippets so that I can talk about and review them. I think this falls pretty squarely under "fair use" in the United States, and there's no admin for litigious record companies to complain to but myself anyway; coincidentally, direct all copyright complaints to [me](/me/) to have any decent snippets of your IP replaced with samples of significantly lower quality.

View File

@ -0,0 +1,32 @@
---
title: Obligatory Site Updates Post
description: All the new stuff I've done on this website lately.
date: 2024-09-29
tags:
- Site Updates
synopsis: All the new stuff I've done on this website lately.
mastodon_id: "113222650648457852"
---
Here are a few new (and not-so-new, but good to know) features I've built for my humble website:
## A Sitemap for Humans
I now have a (human readable) [sitemap](/sitemap), linked in the footer of each page, for easier discovery of the pages that aren't listed in the menu at the top, such as [colophon](/about/colophon), and [privacy](/about/privacy) pages, which are now separate from the [about page](/about).
I haven't automated this yet, mainly because I'm not sure how to best go about it; if any [Eleventy](https://www.11ty.dev/) enthusiasts out there have any suggestions, please let me know by commenting below using Mastodon!
## New Buttons
Some pages now have buttons beneath their spiel that link to relevant pages that a reader may find useful. For instance, [colophon](/about/colophon), and [privacy](/about/privacy), and [contact](/me) pages, are linked from the [about page](/about); [/blog](/blog) now links to [tags](/tags), and…
## My Blogroll
If you've been on the internet for a while (and I mean a *while*), you may remember the humble [blogroll](/blogroll): a list of blogs followed by the author of the blog you're reading, provided both as a benefit to readers and to help share traffic with other people who write interesting stuff.
As I am close to entirely removed from corporate social media, I get my news predominantly from my [newsreader](/about-feeds), which I very much enjoy going through each morning, often with a warm cup of tea. My [blogroll](/blogroll) contains most of the feeds I subscribe to, and it even provides a [convenient and very neatly formatted .opml file](/blogroll/nathanUpchurchBlogroll.opml), which you can (in theory) use to subscribe to my entire blogroll at once by importing it into your feed reader. (I very much hope it works as I haven't actually tested it, but do let me know if you try it.)
The [blogroll](/blogroll) links to both the main website and the feed for every entry, and contains a short description for each. Please bear in mind that I have been adding these as I discover them, so if it turns out I've listed the blog of someone who says mean things to kittens or something, please tell me so that I can remove their entry.
The [blogroll](/blogroll) and [.opml](/blogroll/nathanUpchurchBlogroll.opml) *are* automated, because there are an awful lot of feeds there and I have no interest in writing all that markup myself. If you'd like to know how that's done, you can [check out the repo](https://upchur.ch/gitea/n_u/nathanupchurch.com).
## A Feed for Everyone
I write about all sorts of things, and I fully recognize that people who come here for posts such as [*The Secrets of Scrumptious Seitan*](/blog/the-secrets-of-scrumptious-seitan/) may not be especially interested in posts like [*How to Transfer Files Securely with the “scp” Command*](/blog/scp-command/), so I configured individual feeds for each tag.
What this means is if you go to the [blog](/blog) page, click on "Topics" to reach the [tags](/tags) page, and click on a tag, you'll find an RSS icon next to the title linked to a feed that only contains posts marked with that tag. Convenient, right?

View File

@ -5,6 +5,7 @@ date: 2024-01-10
tags:
- Quick Thoughts
- Incense
- Incense Making
synopsis: Learning about patience through an incense-making miscalculation.
imageURL: /img/dragons_blood_incense_copy.avif
imageAlt: A small piece of a coreless, Japanese-style incense stick burning in a black cast-iron burner.

View File

@ -0,0 +1,27 @@
---
title: "Rammstein Incense Cones: A Review"
description: "It's only natural that the pyrotechnics obsessed neue deutsche härte act would release a line of incense cones. Today I'm taking a look."
date: 2025-02-02
tags:
- Incense
- Incense Review
synopsis: "It's only natural that the pyrotechnics obsessed neue deutsche härte act would release a line of incense cones. Today I'm taking a look."
imageURL: /img/rammsteinShow_copy.webp
imageAlt: A shot from a Rammstein stadium tour showing the stage and great plumes of smoke from the pyrotechnics.
mastodon_id: "113936913424530239"
---
The German neue deutsche härte group Rammstein is known for many things. From their [controversial lyrics (NSFW)](https://www.reuters.com/article/lifestyle/rammstein-album-banned-from-display-in-germany-idUSTRE5A90ZK/) and [legally dubious stage antics (NSFW)](https://www.revolvermag.com/music/see-rammsteins-infamous-1998-family-values-show-landed-members-jail/), to their [over the top live performances](https://metalinjection.net/news/rammsteins-pyro-guy-discusses-the-insanity-of-his-job-how-much-fuel-the-band-uses), one thing the group is certainly *not* known for is conventional merchandise.
Far from the usual assortment of posters and t-shirts, the band's merch has ranged from [medical supplies](https://www.rammsteinshop.us/en/catalog/wound-plaster-rammplast.html) to [kitchen tools](https://www.rammsteinshop.us/en/catalog/cookie-shape-zerdrucken.html), [furniture](https://shop.rammstein.de/en/catalog/kreuztisch-oak.html), [torches](https://shop.rammstein.de/en/catalog/fire-torch-funkenstoss.html), and [*very* special editions of their albums (NSFW)](https://www.rammstein.de/en/news/rammstein-deluxe-2/). Despite this, I was inexplicably surprised to discover that the group had released official, Rammstein branded incense cones for sale on the band's online shop.
At $5.00 for a box of 24, I didn't have high expectations. The picture on [the website](https://www.rammsteinshop.us/en/catalog/incense-candles-rammstein.html) showed a handful of crudely formed black cones, the color likely due to a high charcoal content, which often indicates that the fragrance is constructed from oils rather than whole plant ingredients. Realistically, I wouldn't expect anything else at this price point. The website lists cedar, sandalwood, juniper wood, rosemary, juniper berries, myrrh, frankincense, and benzoin as components of the perfume.
The cones are manufactured by [KNOX](https://www.knox.de/), a large German manufacturer of incense cones and those delightful little wooden [incense "smokers"](https://www.youtube.com/watch?v=v0t-mlg2SoA) that I'm told are popular around the holidays in Germany. Steve of the [Incense in The Wind](https://incenseinthewind.blogspot.com/) blog recently wrote a number of reviews for a variety of KNOX cones; I must admit that after reading them I was steeling myself for the arrival of my Rammstein *Räucherkerzen*.
[![A cone burning in a cast iron burner beside the box of cones.](/img/rammstein_incense_cones.webp "They do look pretty metal.")](/img/rammstein_incense_cones.webp)
When the two small packages of cones arrived, they were identical in appearance to the images on the website. Despite being inside of a mailing box, a paper bag, a cardboard carton, and finally sealed inside of a small plastic bag, I could smell the cones before I even opened the outer box. The fragrance was woody; it was juniper-forward with a sharp, turpenous edge, all tied together with a *big* hit of sweet, creamy benzoin. I didn't detect much of the other resins mentioned, but that may be because I'm more used to the actual resin rather than extracts and imitations. I am not usually fond of highly concentrated scents, but I must admit I enjoyed this, even though even the outer packaging of the cones seems to contaminate everything it touches with fragrance—I'll often catch a whiff of these cones in their packaging while just walking around my apartment.
Upon lighting, I'm briefly met with the scent of burning paper and those off-notes typical of charcoal + oil incense, which is not exactly pleasant, but it does make me nostalgic for some of the cheap incense I used to burn as a teenager. Most of the fragrance that was present on the unlit cone has disappeared, leaving mellow cedar and sweet benzoin notes. As [Steve found in his review of KNOX' vanilla cones](https://incenseinthewind.blogspot.com/2025/01/knox-vanille-raucherkerzen-vanilla.html), these also burn hot and fast, with a large ember characteristic of a high charcoal content. Cones predominantly based on wood tend to have an ember that travels down the cone, but here the ember seems to just increase in size until it envelopes the entire cone at once beneath a thin layer of ash. The cones don't put out much smoke. The mild, sweet fragrance in the burn does linger in the room for some time, but it is so diminished from the powerful scent of the unlit cones that I'm not terribly worried about it soaking into the carpet, which is often a concern with cheaper, oil-based incense.
I didn't at all expect to say this, but I enjoy these cones. They are not an example of a high-quality incense, but I enjoy the fragrance despite it all. I suppose the beauty of cones that use highly concentrated fragrances is that they don't last long; I don't know whether I could tolerate an eleven-inch bamboo-cored stick of this, but I can absolutely enjoy a little cone. In addition, despite the off-notes that charcoal introduces, I wonder if it doesn't overcome one of the key challenges of the format: when making traditional incense cones with actual plants, the temperature increases as the ember grows, so by the time you get to the base, the scent can be quite coarse indeed. With these charcoal cones, it seems as though they start *hot* and stay that way, eliminating the challenge of dealing with a dramatic temperature increase over the course of the burn. Yea, somehow, I like these.

View File

@ -0,0 +1,42 @@
---
title: "Scribus 1.7.0: From Strength to Strength"
description: "Scribus has always been about substance. With 1.7.0 style, usability, and designer-focused features take the front seat."
date: 2025-02-13
tags:
- FOSS/FLOSS
- Libre Graphics
- Underrated Apps
synopsis: "Scribus has always been about substance. With 1.7.0 style, usability, and designer-focused features take the front seat."
imageURL: /img/scribus_splash.webp
imageAlt: "The new Scribus splash screen featuring a fountain pen drawing a stream with koi fish. The splash screen is surrounded by printer marks."
mastodon_id: "114000796038604843"
---
Looking around the internet, you could be forgiven for thinking that Scribus is dead. These days, FLOSS[^1] developers debate the merits of merge requests in public chat rooms, track bugs through GitHub issues, and announce releases through widely-circulated blog posts or sleek landing pages. In contrast, the Scribus developers work seemingly cloistered far away from popular modern conveniences like Matrix and, erm, *git*. Despite their hermetic reputation, however, it is quite possible to glean what's going on in the Scribus project. The SVN repository [is mirrored on GitHub](https://github.com/scribusproject/scribus), the [bug tracker](https://bugs.scribus.net/changelog_page.php) shows clear signs of activity, and the official website reveals a fairly [steady pace of development](https://www.scribus.net/news/). Hell, LibreArts reported on the release of 1.7.0 [just last week](https://librearts.org/2025/02/week-recap-2-feb-2025/#scribus-170).
To be fair, most casual users of the FLOSS desktop-publishing mainstay aren't sniffing around the bug tracker, and for the past few years it sure didn't seem as though much had changed judging by the clunky, dated interface and pixelated icons you'd be met with upon launch. This is likely what has driven many a would-be user to pen an expletive-ridden Reddit thread instead of diving in and gaining enough experience with the program to know what die-hard Scribus fans have known for years: that Scribus is a blisteringly competent piece of software.
## The trouble(?) with Scribus
The major pain point of Scribus is, ironically, one of its key strengths. Designers used to working in InDesign and the ilk are used to being able to throw together a document on the fly, using their desktop publishing program as more of a freeform creative tool than a tool to denote and apply structure. This is not how Scribus works best. Simple things like choosing a color on the fly aren't possible in Scribus; rather than flicking your mouse over to a color-wheel, in Scribus, you'll go to Edit > Colors and Fills, where you'll select and add a color to your document's color list. Only then can you apply that color to a fill or stroke. Working without paragraph or character styles applied to type can be done, but it's sub-ideal; you'll set up some styles to stop the pain long before your work is done. When working with Scribus, you need to come in with a plan. Designers who regularly churn out pretty but poorly prepared files (and let's admit it, that's most of us[^2]) are in for a bit of a hard time. But if you stick it out, when you realize that you're simply going to *have to* set up your files methodically and properly, Scribus begins to feel like a weapon.
## Enter 1.7.0
Despite what the denizens of Reddit have to say, Scribus has been suitable for professional work for *years* now, and naysayers have had even less to complain about since Adobe announced that Pantone colors would, like Scribus, [no longer come baked into their software](https://www.theverge.com/2022/11/1/23434305/adobe-pantone-subscription-announcement-photoshop-illustrator). With the release of 1.7.0, Scribus finally looks and feels like the mature, feature-rich, professional tool that it has been for some time.
[![](/img/scribus_color_dialog.webp "The new color dialog.")](/img/scribus_color_dialog.webp)
The user-interface has been completely overhauled, with new icons, a proper window docking system, and more intuitive controls throughout the program. [Customizable optical margins](https://bugs.scribus.net/view.php?id=10539) have been introduced, allowing for [hanging punctuation](https://en.wikipedia.org/wiki/Hanging_punctuation). A unique new feature that I'm quite excited about is the white space review mode that allows you to check for typographic rivers while avoiding the risk of displacing your contacts through repeated squinting. [The full release notes](https://www.scribus.net/scribus-1-7-0-released/) detail what truly feels like a milestone release.
[![A Scribus document with all text covered in black bars, exposing the white space between the words.](/img/scribus_white_space_preview.webp "White space preview in action.")](/img/scribus_white_space_preview.webp)
By highlighting these user-facing improvements in Scribus 1.7.0, I don't mean to diminish the tremendous work that has been done behind the scenes, not least the years of work getting Scribus ready to move to QT6. That work is important, but what excites me so much about this latest release is the change in direction it could represent for the project: these features are not the sort that would be imagined by developers and built for their personal convenience, these features clearly represent the needs of *designers*.
[![The new Scribus splash screen featuring a fountain pen drawing a stream with koi fish. The splash screen is surrounded by printer marks.](/img/scribus_splash.webp "Look at that fancy splash screen!.")](/img/scribus_splash.webp)
Counterintuitively, this isn't a natural consequence of building software that might be used by design professionals. Take Inkscape, for example. There will be those in the project who see their work solely as creating a tool that implements the SVG specification; this is a fundamentally different point of view from that held by someone like [Martin Owens](https://www.youtube.com/@doctormo) who sees it as his job to create features that make Inkscape users happier, more productive, and to make Inkscape a tool that better suits their needs. This is where you get features like the shape builder tool, and upcoming CMYK support, both very much unnecessary if your goal for the project is a technical one, but critical tools for users who want to use the program in a professional setting where time is at a premium and output may be going to print.
Inkscape's [duplicate transform](https://www.youtube.com/shorts/qsyrBrg4DT8) and Scribus' white space preview features are prime examples of the unique, needs-focused capabilities that emerge when users, designers, and developers come together on equal terms in FLOSS projects; magic happens. So let's hope this trend continues. Scribus is *the* FLOSS option for professional desktop publishing, a cornerstone of the libre-arts landscape. Combined with Scribus' wide feature-set and dedication to solid, dependable PDF output, it's easy to see why I've long been an outspoken fan of the project, even back when it was ugly 😉.
## A bright FLOSS future
It's a good time to be a [GNU/Linux](/quizzes/how-much-of-a-linux-nerd-are-you/) user. With the amazing work being done by [KDE](https://kde.org), and Linux gaming hitting the mainstream, a killer release like 1.7.0 from a FLOSS project that has (somewhat unfairly) garnered a reputation for being stodgy and slow-moving, if not (utterly unfairly) outright abandonware, feels like icing on the cake. Alongside the major advancements made by the [Inkscape](https://inkscape.org) and [Krita](https://krita.org/en/) teams, it's a beacon of hope to the small number of intrepid designers and artists who rely on FLOSS to do their work—our options are few, but they are mighty.
[^1]: Free / Libre Open Source Software
[^2]: As a working-file neat-freak, I was uniquely positioned to switch to Scribus.

43
content/blog/silvertip.md Normal file
View File

@ -0,0 +1,43 @@
---
title: "Silver Tip: an Incense Build Featuring Osmanthus and Mastic"
description: "I make a fresh, sweet, and green incense build reminiscent of the flavor of white tea"
date: 2024-09-20
tags:
- Incense
- Incense Making
- Incense Builds (Recipes)
synopsis: "I make a fresh, sweet, and green incense build reminiscent of the flavor of white tea."
imageURL: /img/testAsh.webp
imageAlt: "A small tin labelled 'test ash' beside a small glass jar containing matches."
mastodon_id: "113173725532729481"
---
If my memory serves me, some time ago I tried a stick from [Yi-Xin](https://craft-incense.com/) that contained osmanthus flowers and mastic gum. I recall enjoying the combination, so when I found a bag of dried osmanthus on sale while [doing some online grocery shopping](https://www.sayweee.com), I set out to make something using these ingredients.
Having read that osmanthus, like lavender, was one of those few flowers that could be used successfully in incense, I was brimming with confidence as I ground them finely and made an attempt at a batch of sticks containing 19% of the powder. The result was ghastly. At this percentage, alongside that characteristic beautiful fruity fragrance was a proportionate helping of the acrid scent of burning plant matter. Following this failure, I put aside my hubris, opened my tin of 'test ash'[^1] and began testing incense powders comprised of differing ratios of osmanthus and base-wood in a series of trail-burning tests, eventually finding that a ratio of 10% osmanthus to base wood seemed to return a reasonably good fragrance in the burn.
[![A small tin labelled "test ash" beside a small glass jar containing matches.](/img/testAsh.webp "My test ash; a very convenient way to perform a quick trail burn.")](/img/testAsh.webp)
Armed with this knowledge, I put together a build. The star aromatics sit atop a woody base of sandalwood and juniper sweetened by a touch of benzoin; the composition is slightly lifted with a minuscule amount of camphor, bound with guar gum and a little acacia gum. While also acting as a weak binder, the acacia gum is present to lower the burn temperature and strengthen the sticks.
## The Build
|Ingredient|Grams|% of Build|
|----------|------|-----------|
|Juniperus Virginiana|2.6|35.62%|
|Santalum Spicatum|2.6|35.62%|
|Osmanthus Fragrans|0.73|10%|
|Mastic Gum|0.5|6.85%|
|Acacia Gum|0.3|4.11%|
|Benzoin Siam|0.25|3.42%|
|Guar Gum|0.25|3.42%|
|Borneol Camphor|0.07|0.96%|
As with all of my incense, I extruded the dough into 2-2.5mm coreless sticks which I then dried on a mesh screen at room temperature and left to cure for a number of weeks.
## Conclusion
The sticks this build produces offer a [quiet listen](https://kikohincense.com/pages/listening-to-incense), but I find it very pleasant. Something about the combination of juniper, mastic, and osmanthus forms a fragrance that's at once green and fruity, with a bright, peachy, stone-fruit note, all atop a woody base. After a couple of months, the camphor is barely there on the stick; whether it is present in the burn is difficult to say without trying a build sans borneol.[^2]
My partner has a small wood-burning backpacking stove they like to use to make tea while camping. While I haven't yet had the pleasure, I have to imagine that making a cup of white tea on such a stove in a juniper forest would smell similar to the fragrance of this stick.
[^1]: I use the stick of a cotton swab to create a divot in the ash bed, which I carefully fill with incense powder to be tamped down, lit, and evaluated. When I'm done, I simply close the lid, shake the container, and drop it once or twice on a flat surface to smooth the ash and prepare it for the next use.
[^2]: Such a tricky ingredient, camphor. The tiniest amount can seem utterly overwhelming when blending or on a fresh stick, and as incense cures and ages, it seems as though it may or may not mellow out in the burn.

View File

@ -3,6 +3,7 @@ title: "Switching to GNU/Linux: Mentally"
description: The mindset shift that produces happy users of GNU/Linux and other Free/Libre and Open Source Software.
date: 2024-06-11
tags:
- Essays
- GNU/Linux
- FOSS/FLOSS
- KDE

View File

@ -0,0 +1,24 @@
---
title: "The Office Tech Wizard"
description: "Knowing how to operate a PDF viewer does not a tech wizard make; what it means to be good at your job."
date: 2024-09-21
tags:
- Quick Thoughts
- Rants
synopsis: "Knowing how to operate a PDF viewer does not a tech wizard make; what it means to be good at your job."
mastodon_id: "113178005978869507"
---
I came across [this submission to *Not Always Right*](https://notalwaysright.com/pdf-pretty-darn-futile-part-2/) today, and it got me thinking about some of the attitudes towards technology I've seen over the years. There is a contingent of people in many workplaces who believe they can do a perfectly good job without investing the time in learning about the tech they use each day; after all, their work gets done, doesn't it? We've all encountered this sort; the sort of person who's so far removed from a basic understanding of the tools they use each day that they'll brand you the office tech-wizard for knowing how to use the zoom function in a PDF viewer, copy and paste with the keyboard alone, or *(gasp!)* googling how to restart the print spooler when a job gets stuck. And sure, many of these folks do manage to get things done, but a problem arises when you consider *how.*
Early career folk don't have the luxury of being bad at their tools; it's sink or swim. So when older colleagues or those later in their career don't know how to use a particular piece of software, guess who has to pick up the slack? This isn't necessarily a problem in and of itself; there's nothing wrong with not knowing something and needing a bit of assistance, but this quickly becomes a problem when people decide that they are exempt from learning because of their age, position, workload, et cetera. At this stage, one individual's job becomes a team effort; because of someone's attitude towards technology, another person who also has their own tasks and responsibilities is *doing their job with them.*
In considering what it is to be good at one's job, let's leave outcomes off the table for a minute. If someone has to rely on a team to do their job, no matter the result, can they seriously claim to be good at it? Surely knowledge and experience are moot if someone cannot actually perform their work. What sort of value does this individual provide an organization when they systematically reduce the productivity of their more capable colleagues each day? Further, in what other industry can people get away with this attitude? It's unthinkable that there might be a mechanic who refused to learn to work a hammer, a writer who refuses to sharpen a pencil, or a microbiologist who can't operate a microscope and is just 'too swamped' to learn how to prepare a slide. To me, a white-collar worker not knowing how to use the zoom function in a PDF viewer is equally ridiculous when working with PDFs is something they do on a regular basis.
So when we consider whether we are good at what we do, atop knowledge, experience, and outcomes, let's include a few new criteria:
1. Do we create or reduce work for others?
2. Do we truly understand the tools that we use every day?
3. Can we perform basic maintenance and troubleshooting on our tools?
…or do we rely on a wizard?

View File

@ -0,0 +1,31 @@
---
title: That Time I Drew My Ex
description: The tale of the time I made my best effort to draw my live-modeling ex. Also some not-very-good art.
date: 2024-08-20
tags:
- Storytime
- Quick Thoughts
synopsis: The tale of the time I made my best effort to draw my live-modeling ex. Also some not-very-good art.
imageURL: /img/doodle.webp
imageAlt: A wiggly vector ice cream cone with a wee smiling face and colorful sprinkles. The cone is holding two smaller ice cream cones in its long, wiggly arms, one of which is wrapped around its body.
mastodon_id: "112996800811207774"
---
At the start of the pandemic, I had just begun a relationship with an artist who had the occasional gig doing a bit of nude live modeling.
[![A wiggly vector ice cream cone with a wee smiling face and colorful sprinkles. The cone is holding two smaller ice cream cones in its long, wiggly arms, one of which is wrapped around its body.](/img/doodle.webp "Not my ex")](/img/doodle.webp)
When he invited me to join a session via zoom, I was apprehensive. Drawing has never been my strong suit. I can *doodle,* but I can't *draw.* But hey, I thought, I'm not completely devoid of artistic skill. I *have* been doing design work for years; while graphic design is not art, it's at least art-adjacent. Hell, when I sit down and take my time, I can produce something that's downright fridge-worthy!
[![A crude oil pastel ocean-scape featuring a sunset. Wee boats bob about on the waves and little birds fly above them.](/img/pastel.webp "I'd put that on my fridge!")](/img/pastel.webp)
Prepared to do my best, I settled down with my laptop, some pencils, and a pad of paper. What I was not prepared for, however, was how quickly the poses would change. There I was, expecting a good chunk of time to carefully render my new boyfriend in loving detail, only to have the pose end before I'd even managed an outline! And so I changed my strategy: I decided to prioritize *speed.* That didn't work either. Here are some of the results:
[![A very speedily drawn cat, with what I think is my ex behind it. It looks like a sack of potatoes.](/img/quicklydrawncat.webp "I'm fairly certain this was supposed to be his cat.")](/img/quicklydrawncat.webp)
[![This drawing, honest to god, looks like a rotisserie chicken with a perm.](/img/chicken.webp "I really don't know what happened here.")](/img/chicken.webp)
After much scribbling, I did begin to improve, eventually turning out this:
[![A half decent drawing of what is quite clearly a human sitting on the floor.](/img/notbad.webp "I stopped while I was ahead here.")](/img/notbad.webp)
I put the pencil down after that.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 277 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 462 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 235 KiB

View File

@ -0,0 +1,88 @@
---
title: "The Skinny on Incense Stick Extruders"
description: "The good, the bad, and the ugly of manual incense stick extruders."
date: 2025-01-23
tags:
- Incense
- Incense Making
synopsis: "The good, the bad, and the ugly of manual incense stick extruders."
imageURL: /img/extruders/extr3_3x_tip_compressed.webp
imageAlt: "A close shot of an incense extruder tip with three extrusion holes."
mastodon_id: "113879431946665708"
author:
url: "/me/"
name: "Nathan Upchurch"
profilePic: "/img/CN20191025_301_Srt_SQUARE_crop.jpg"
---
Given that hobbyist incense making hasn't exactly been all the rage since the tang dynasty, finding good incense-making equipment for small-scale home production can be a bit of a tribulation. If you make Chinese or Japanese style coreless incense, one of the first hurdles on the way to kitting out your very own mini incense workshop is choosing a manual extruder. Now that I finally feel confident that I've overcome this particular hurdle, here's what I've learned:
## Where to Find a Suitable Extruder
When searching for manual extruders, the first thing you'll likely come across is something like a [Makin's](https://www.makins-usa.com/products.jsp?prod_catg_id=7) clay extruder. This style of extruder often comes with a series of small discs designed to extrude clay noodles of different diameters. These are best avoided; other incense makers have found that extruding incense through these flat discs tends to create noodles with [a coarse texture](https://youtu.be/snvDZbxHnU8?si=ap7oiw0iC_HQJhCy&t=245) that must be rolled smooth after extrusion. Omitting this style of extruder from your search *drastically* narrows your options, but searching "incense extruder" on the website of any major online retailer that dropships or stocks a large number of products from China is likely to net you results featuring extrusion tips better suited to incense making. If you are willing to wait a bit for delivery, however, rather than paying Walmart, Amazon, or Ebay a convenience tax, you will have no trouble finding manual extruders on AliExpress directly for much less of your hard-earned coin. Carl "The Incense Dragon" Neal also sells a [Makin's style extruder](https://www.theincensedragon.com/tools/p/incense-extruder-20) that includes a series of 3D-printed extrusion tips allowing smooth incense extrusion.
## Extruders I've Tried
### The Syringe-Style Extruder
The internet is riddled with [syringe-style incense extruders](https://www.aliexpress.us/item/3256804771983263.html). Despite [Carl's warning regarding plastic extruders](https://youtu.be/snvDZbxHnU8?si=p59DxZMXcw64BHfi&t=278), I had to give one a go just to see for myself how they performed.
[![A syringe-style clear plastic incense extruder with a metal tip.](/img/extruders/extr1_compressed.webp "Just say no.")](/img/extruders/extr1_compressed.webp)
I cannot recommend this style of extruder. When making incense dough, it's important to use as little water as possible to avoid excessive warping during the drying stage. When attempting to extrude dough of the usual level of hydration through a 2mm tip, I was physically unable to coax any dough whatsoever beyond the extrusion tip, and I am not a weak man. This extruder was a complete bust.
[![A small metal extrusion tip.](/img/extruders/extr1_tip_compressed.webp "I'm sure this would be great if you could get anything through it.")](/img/extruders/extr1_tip_compressed.webp)
There are a range of metal extrusion tips readily available for these extruders, so someone must be using them for *something,* but I found them completely unsuited for my purposes.
### The Aluminum Option
Also relatively easy to find, [these aluminum extruders](https://www.aliexpress.us/item/3256807354775579.html) are well-made and effective:
[![An aluminum incense extruder, similar to the Makin's clay extruder, but with a longer tip for incense extrusion.](/img/extruders/extr2_compressed.webp "Truly a good, affordable option.")](/img/extruders/extr2_compressed.webp)
So long as you keep the o-ring on the piston lubricated and your dough doesn't have any large chunks, the extrusion tip produces a nice, smooth noodle of incense dough, and the turning action greatly reduces the hand-strength required to operate the device.
[![The tip for the aluminum incense extruder.](/img/extruders/extr2_tip_compressed.webp "Various tips are also available.")](/img/extruders/extr2_tip_compressed.webp)
There are a couple of small issues, namely that the caps on the turning rod can come unscrewed mid-batch if they aren't firmly screwed on, and the soft metal is prone to damage if you aren't careful. Despite these nitpicks, however, I have no hesitation in recommending this style of extruder to any incense maker focusing on thin coreless sticks.
### My First Stainless Steel Extruder
As I've been working on scaling up my production to a level that would allow me to sell a few orders of incense here and there, my interest was sparked in [this stainless steel extruder on AliExpress](https://www.aliexpress.us/item/3256806453629799.html):
[![A heavy-duty looking stainless steel incense extruder, with a black grip around the center tube.](/img/extruders/extr3_compressed.webp "Looks good, doesn't it? Well it isn't.")](/img/extruders/extr3_compressed.webp)
Specifically, I hoped that the optional extrusion tip with three outlets and the vise accessory would allow me to speed up the extrusion process. I also liked the idea of a heavy-duty item that would last for many years. I bought the "high order style," which comes with four extrusion tips, a grip, some o-rings and small cleaning tools, and the extruder itself. I also ordered the three-outlet extrusion tip, and the "sucker holder," AKA a vacuum-base vise.
[![The three-outlet tip.](/img/extruders/extr3_3x_tip_compressed.webp "Not as useful as you might think.")](/img/extruders/extr3_3x_tip_compressed.webp)
To start, the three-hole extrusion tip worked, but as anyone who works with [larger manual extruders](https://www.aliexpress.us/item/3256807859213019.html?utparam-url=scene%3Asearch%7Cquery_from%3A) knows, the flow rate from each hole isn't necessarily even. This is less of a problem when you're extruding, say, six to twelve sticks at once at a proper station with a waste bucket and a stack of boards to catch the extruded incense, but when you're hand-cranking three sticks at a time and one is firing out like billy-oh, another is extruding at the usual rate, and the last seems frightened of daylight, you realize that you would have been better off just using a normal single-outlet tip.
[![A single-outlet tip.](/img/extruders/extr3_tip_compressed.webp "The large tips that fit this extruder also retain rather a lot of dough that doesn't get extruded.")](/img/extruders/extr3_tip_compressed.webp)
The vise *was* useful, however; it's much more efficient to be able to keep the extruder in one place and have a free hand to catch the sticks on a board. The problem I faced with it was that in order to get the extruder to fit within the vise, I had to fasten an included aluminum ring around the main body of the extruder using two grub-screws. These grub screws cut into the grip on the tube, which eventually tore from the force applied during extrusion.
[![The vise alongside the aluminum ring that allows it to hold an extruder.](/img/extruders/vise_compressed.webp "Genuinely pretty useful, just not with the grip on the extruder it is sold alongside.")](/img/extruders/vise_compressed.webp)
The extruder itself appeared to be assembled from mostly off-the-shelf parts, and not especially good ones. The rings that held the turning-rod in place rusted immediately after I got them a little wet, the threads were crunchy and coarse, and the interior of the dough-tube was very dirty. Perhaps most strangely of all, the piston, or plunger, that actually pushed the dough down the tube was not attached to the threaded rod at all, unlike the aluminum extruder.
[![A little plunger.](/img/extruders/extr3_plunger_compressed.webp "Note the scoring on top; it didn't come like that.")](/img/extruders/extr3_plunger_compressed.webp)
The plunger is made of mostly brass parts that screw together and a rubber o-ring. It's very thick, reducing room for dough, and the soft brass is rapidly worn away by the stainless steel threaded rod as it spins loosely down the dough tube during extrusion, leaving sparkly grit to get mixed into your next batch of incense. It continued to wear even after I had filed and sanded down the raised parts on the end of the threaded rod.
As a result of all this, the plunger becomes more worn with every use, the dough tube becomes covered in grime, and the extrusion action is crunchy and rough. I was *very* disappointed in this extruder, and I cannot recommend it. The silver lining here is the vise, which will work with any of the metal extruders listed; in my opinion it's a worthwhile purchase.
### My Current Extruder
[This extruder](https://www.amazon.com/dp/B0DP3H8CCL) was an enigma. I hadn't seen it anywhere before it surfaced several pages deep into an Amazon search.
[![A stainless steel incense extruder that looks much better made than the last one.](/img/extruders/extr4_compressed.webp "Could this be the one?")](/img/extruders/extr4_compressed.webp)
I tried to find a Chinese source through a reverse image search. Tineye, Google, Bing, and Yandex turned up nothing. Only when I began to search the sales copy in the Amazon listing did I find the item for sale elsewhere ~~but I still never managed to find a single instance of this product being sold on AliExpress (if you manage to find one, [do let me know](/me/))~~.[^1]
It *looked* great: stainless steel; a knurled dough tube; various accessories included. The Amazon listing didn't show it, but when I looked at other listings I saw that the piston appeared to be attached to the threaded rod. Jackpot!
When it arrived, I noticed a few things immediately. The knurling was shallow and not especially neat, as though it had been etched twice over and the etchings didn't quite align. The tips shown weren't included; instead of five tapered tips in different sizes, I received three flat 2mm tips. That might be a deal-breaker for some, as I don't even know where you'd begin to find additional tips for this thing, but as I extrude 2mm sticks almost exclusively, I don't mind. I'm also not bothered by the ugly knurling either, because the performance of this extruder is great.
To begin with, the threaded rod isn't some industrial looking piece of hardware like the last stainless extruder; it looks more like a high-quality leadscrew you'd expect to see on a laser cutter or some other piece of CNC equipment where precise, measured movement is critical. This keeps the extrusion action exceptionally smooth. The threads on all of the other caps are also nicely machined, and the small extrusion tips have minimal space to accumulate wasted dough after a batch is extruded.
[![The tip for my current extruder.](/img/extruders/extr4_tip_compressed.webp "Perfect!")](/img/extruders/extr4_tip_compressed.webp)
Fitted into my vise, this extruder is a dream. The smoothness and consistency of the extrusion makes one-handed operation a breeze. I did add some o-rings to the turning rod to reduce noise, and while I do find myself wishing it didn't fit quite so loosely inside the cap on the leadscrew, these really are nitpicks of the best extruder I've used to date.
[^1]: I have since found what appears to be the same item on [AliExpress](https://www.aliexpress.us/item/3256807712368107.html?utparam-url=scene%3Asearch%7Cquery_from%3A), [Taobao](https://vn.world.taobao.com/item/858074002289.htm), [Wepost](https://www.wepost.com.my/shops/taobao-items/554179126072.html?sku_properties=1627207:2846750301) (which has a [very dramatic video](https://cloud.video.taobao.com/play/u/719156502/p/2/e/6/t/1/440842077674.mp4) showing the extruder in operation), and [1688.com](https://detail.1688.com/offer/750437159209.html). Accessories also appear to be available through these sources.

View File

@ -0,0 +1,46 @@
---
title: "Meine Welt: It May be Time For Till&nbspLindemann to Retire"
description: "You always hope that your favorite musicians will retire before they do anything too embarrassing."
date: 2025-03-28
tags:
- Music
- "TW: SA"
synopsis: "You always hope that your favorite musicians will retire before they do anything too embarrassing."
imageURL: /img/till.webp
imageAlt: A black and white photo of Till Lindemann looking sad.
---
Over his storied career, Till Lindemann has been given a lot of grace. Both he, as a lyricist, and the Neue Deutsche Härte powerhouse he fronts, have made some questionable decisions over the years. Many of these missteps might perhaps be chalked up to the era, such as the unfortunate fat-suits in Rammstein's *Keine Lust* music video. We might also see the red-face in *Amerika* as ignorance rather than malice, given it was donned by a group some 5,000 miles away from the peoples being insulted, and in 2004, no less. Likewise, as a queer Rammstein fan I always saw *Mann gegen Mann* as a statement on the ridiculousness inherent in the rabid homophobia that was common at the time. The trouble with satire, however, is that you can never be perfectly sure whose side is being satirized, and Lindemann's later work threatens to cast an unflattering light upon lyrics written decades ago.
In 2015, you didn't have to be on the bleeding edge of contemporary thought on matters of social justice to recognize that *Ladyboy* and *Fat* of Till Lindemann and Peter Tägtgren's *Skills in Pills* was, to put it mildly, problematic. Still, Rammstein has never taken itself too seriously; it didn't seem terribly incongruent or damning that Till would opt to play the clown in an ill-advised politically-incorrect shock-rock album that, let us admit, did contain the odd banger. Till's attempts at a contemporary *Leah Sublime[^1]* certainly ring hollow compared to much his lyrics for Rammstein—which, while also often juvenile and shocking, explore themes of love, lust, obsession, gender, and the body in interesting and compelling ways—but never have I felt that they betray anything more insidious than a blurry view of the boundaries of poor taste. Further, Rammstein detractors have so long 'spent spouting the tide'[^2] of satanic-panic style criticism and speculation as to the group's messaging and politics, that it was eventually forced to be quite frank on the matter. As Lewis Twilby reported in Edinburgh University's history, classics, and archaeology magazine, *[Retrospect Journal](https://retrospectjournal.com/2019/10/20/deutschland-by-rammstein-a-look-at-cultural-memory-in-germany/)*:
> in a 2011 interview with Rolling Stone Lindemann said that he is a socialist and that We used to be either punks or goths We hate Nazis!. This is highlighted by their song Links 2,3,4, which is a direct reference to the labour movement song Einheitsfrontlied.
Famously refusing to provide almost any detail whatsoever on the meaning of Rammstein's lyrics, it's hard to glean much about the mind behind them unless they are quite explicit. For this, Lindemann's *Meine Welt* was all the more shocking. The video, released hours ago, opens with a gagged Lindemann, wearing a cross and being pushed in a wheelchair by an angry mob of women wielding signs featuring slogans such as "Kill Till," "Toxic Masculinity," and "Female Revenge." A melancholy piano solo plays as the camera closes in on the women's scowling faces as they yell and chant. Particular focus is placed on those in the crowd with piercings, or shaven heads. As the beat picks up, the video transitions to AI generated slop: gory and alien-looking childbirth imagery. The first verse begins[^3]:
> Naughty, unabashed<br />
Unknown and unshaven<br />
Unteachable, clueless<br />
Insatiable, unpunished<br />
Immovable, so unspeakable<br />
Shameless and unbearable<br />
Useless, uncovered<br />
Unaesthetic, unlicked
The chorus follows:
> Somehow, someday<br />
We'll start over from scratch<br />
Somehow and somewhere<br />
Life laughing, senses happy<br />
I'll show you my world<br />
A place for lost souls<br />
When apersonfallsfrom heaven<br />
They won'tcount the stars
Knowing the history of Till's work with Rammstein, you *might* argue that this is a *Mann gegen Mann*-esque parody of the embarrassing "men's rights" crowd who seriously argue that women attempting to protect themselves from sexual assault and lift impunity from the men who commit it is a mysandrist witch-hunt, if it were not for the mewling chorus and, oh yes, the fact that Till [was himself accused of sexual misconduct a couple of years ago](https://www.bbc.com/news/entertainment-arts-66646096). Due to a lack of evidence, the investigation was dropped, and while this says nothing about whether or not Till committed the acts he was accused of, when these sorts of accusations occur, we have a unique opportunity to learn something about the individual to whom they are directed. Of course a range of emotions might be expected under the circumstances, but I think it's fair to say that releasing a music video two years later portraying oneself as a Christ-like figure while characterizing women as an angry, "unaesthetic," "unshaven," "unteachable," and "unlicked," mob is neither a decent nor reasonable response—even if allegations were false, or indeed, malicious.
This is a deeply embarrassing moment for Till Lindemann, or at least it ought to be. If we were to stretch the benefit of the doubt to encircle the earth, it would be difficult to believe that this release is parody, and it would remain in egregious taste in any case. In addition, the martyr act from these famous figures accused of god-knows-what is consistently pathetic—are we to feel sorry for these multimillionaires who suffer no legal consequences and fail to miss a single wayward drop of revenue following the release of the shocking allegations leveled toward them? While we don't tend to expect better from public figures, when they are known to espouse leftist beliefs, we certainly hope for it, and it's a tremendous disappointment every time. As lyricist for Rammstein, Till's behavior also threatens to cast aspersions on the band's entire body of work, potentially eroding the good faith that gave the writing an air of irony, exploration, and at times a sense of literary value as it straddled the line bordering outright vulgarity. A poetic exploration of sexual violence can sometimes be useful and cathartic for those affected—Rammstein fans have been known to write in to the band to say as much—but the work takes on a different tone entirely when its author is accused of sexual misconduct and uses the experience as an excuse to express outright misogyny *via music video* while playing the martyr.
The release also says something about where Till is (or rather, isn't) artistically. Rammstein songs have historically been replete with references to classic literature, German culture, and wordplay, their videos visually arresting and multifaceted in their storytelling—barring the odd *Pussy* affair, but the lyrics, message, and egregious quantities of AI slop in *Meine Welt* indicate to me that either Till is losing touch with both the zeitgeist and his eye for quality simultaneously, or that perhaps someone else had been reigning him in all along. In either case, the man is sprinting towards self-parody, and the teenager in me desperately wishes he had retired first.
[^1]: If you don't get this reference, count yourself lucky and don't investigate further.
[^2]: Forgive me.
[^3]: Lyrics via [genius.com](https://genius.com/Genius-english-translations-till-lindemann-meine-welt-english-translation-lyrics).

View File

@ -3,6 +3,7 @@ title: ADGs - Alternative Diet Guests and Foodservice
description: Breaking down the alternative-diet restaurant experience to offer some perspective and advice to foodservice professionals and proprietors.
date: 2023-10-03
tags:
- Essays
- Vegan Cooking
- Restaurants
synopsis: Breaking down the alternative-diet restaurant experience to offer some perspective and advice to foodservice professionals and proprietors.

View File

@ -0,0 +1,38 @@
---
title: "Washing Frankincense"
description: Reducing off-notes and improving resin fragrance in combustible incense by dissolving gum content.
date: 2024-12-09
tags:
- Incense
- Incense Making
synopsis: Reducing off-notes and improving resin fragrance in combustible incense by dissolving gum content.
imageURL: /img/frankincense_washed_ground_dried_ground.webp
imageAlt: A sieve containing frankincense powder.
mastodon_id: "113626197934900329"
---
Plant resins come with varying amounts of water-soluble gum content. Beyond the temperature-reducing aspect innate to resins in combustible incense, these gums can further affect how much of a given resin you can include in a build. As anyone who has burned resins on charcoal can attest, with resins high in gum content, the burning gum can introduce off-notes. Gums also serve as binders in incense sticks; while a little is helpful for producing a performant dough that extrudes well and a more rigid, break-resistant incense stick, too much can prevent combustible incense from remaining lit.
Naturally, I've been curious for some time as to how dissolving and discarding resin gums might impact the performance of a resin in combustible incense. Given all of the considerations I mentioned earlier, using resin in combustible incense is trickier than you might at first imagine, yet incense artisans like Yi-Xin manage to produce [very clean sticks](https://craft-incense.com/products/white-magic) using resins with a high gum content. Could dissolving the gum be the answer? When a fellow member of an incense chat group mentioned this type of processing, she unknowingly gave me the final push I needed to give it a go.
## The "washing" process
1. Grind your resin as finely as you are able.
2. Stir the ground resin into a large quantity of water in a container.
3. Let the resin and water sit overnight in the fridge.
4. When the solids have all settled beneath the water, pour the water off the top, while being careful not to lose the solids.
5. Spread the resin solids onto a sheet of wax paper and let dry.
## How it went
In my first attempt I utilized a paper coffee filter to separate the remaining resin from the gum-containing water; it took an eternity and resulted in a sticky mess on my kitchen floor, so I don't recommend it. That disaster is the reason why I moved to the method above wherein the water used to dissolve the gum content is poured off of the solids. This is based on a technique I used back in [my days as a cocktail bartender](https://makertube.net/w/boNV8AQcufwtaZVg9vUh1Q) to make ginger syrup[^1]. I do plan to attempt filtration again later with a lab vacuum filtration kit. After washing and drying the remaining material, I was left with a pleasantly crumbly mass adhered to the wax paper, which I gathered up into a container.
[![A closeup of a pile of crumbly looking chunks of frankincense in a small plastic deli container.](/img/frankincense_washed_dried.webp "Very satisfying to crumble between your fingers.")](/img/frankincense_washed_dried.webp)
Once dried, re-grinding the resin was incredibly quick and easy. I passed the ground material through a 140 mesh sieve and was met with a very fine, fragrant, and free-flowing white powder:
<figure><div style="position: relative; padding-top: 56.25%;"><iframe title="Washed Hojari Frankincense" width="100%" height="100%" src="https://makertube.net/videos/embed/e387a29a-dc61-4e3a-80a5-ccb1c1b3fda0" frameborder="0" allowfullscreen="" sandbox="allow-same-origin allow-scripts allow-popups allow-forms" style="position: absolute; inset: 0px;"></iframe></div><figcaption>Hojari frankincense resin after being ground, washed, dried, ground once more, and sieved through a 140 mesh screen. The tiny spoon is for making Chinese incense seals.</figcaption></figure>
I tested the processed frankincense against an unprocessed powder in a trail-burning test at 30% resin to 70% sandalwood. While I was hardly scientific about it, my impression was that the processed frankincense was significantly improved in fragrance quantity and quality when burning compared to the unprocessed powder.
Needless to say, I'm pretty happy with the result. I'm very keen to give this a go with some of the myrrhs I've collected, and I am excited to have a greater degree of control as to just how much gum is used in a build. Following this experiment, I processed all of the Hojari frankincense I had in preparation for a bright frankincense-forward build that I'll share soon.
[^1]: First we peeled fresh ginger with a spoon to preclude any bitterness that might be introduced by the papery skin, then we would juice the ginger, let the starches settle in the fridge overnight and pour the clarified juice off of the top the following day, after which we'd combine the juice 1:1 by volume with water; et voilà, we have ginger syrup.

View File

@ -0,0 +1,36 @@
---
title: "What Do We Expect from Fragrance? Natural Incense in an Unnatural World"
description: How our expectations influence the way we experience fragrance and where natural incense fits in.
date: 2024-12-18
tags:
- Essays
- Incense
- Incense Making
synopsis: How our expectations influence the way we experience fragrance and where natural incense fits in.
imageURL: /img/incense_seal.webp
imageAlt: A burning incense seal in a flat brass censer.
mastodon_id: "113677779325283607"
---
Smoke was the first breath of early civilization, its rising plumes a synonym for human presence. This byproduct of life-sustaining flame has been constant companion to our evolution as a species, changing not only human lives, but [human bodies](https://www.psu.edu/news/research/story/where-theres-smoke-and-mutation-there-may-be-evolutionary-edge-humans). As the ubiquity of smoke rendered transparent to our ancestors' noses the once harsh notes of burning plant matter, there must have been a sense of magic when our forebears happened to toss a well-resinated tree branch or a fragrant herb upon the coals. It is little wonder, then, that the word "perfume" [stems from the Latin "perfumare,"](https://www.etymonline.com/word/perfume) translating to "through smoke."
## A rose by any other… chemical composition?
In these ancient times, the mention of a rose might have brought two fragrances to mind: that of a freshly blossomed rose in the bush, and that of the petals on the coals of a fire or burned in a censer. Later, enthusiasts of nerikoh or other forms of non-combustible incense would also become familiar with the fruity, acidic notes of gently heated rose petals. The situation is much changed today; for most people, the idea of the fragrance of rose is in no way related to incense-making traditions. Beautiful but aromatically impotent roses stuffed into plastic grocery store bins year-round aren't much help either. Today, synthesized ingredients like rose oxide, citronellol, or geraniol inform the average person's perception of how a rose smells; for those with expensive tastes, this perception may also be derived from a "natural" concentrate such as rose essential oil, wherein vast quantities of flowers are shoveled into a device and divested of volatile aromatic compounds via an industrial steam distillation process, which can result in [tiny yields, such as, for example: one part oil for every 3,000 parts roses](https://en.wikipedia.org/wiki/Rose_oil#adulteration).[^1]
In the incense making world, the siren song of these convenient ingredients is ever-present, with some even claiming that it's outright impossible to express the delicate fragrance of flower blossoms in combustible incense without them. While it is true that some fragrances cannot be expressed at all in this way, I do not believe that rose is among them, especially if we are willing to adjust our expectations and consider *what it means* to smell a rose. While there are many who would assert that the true fragrance of a material is to be found in its concentrated derivatives, given that a perfume might contain the strength of hundreds of roses while containing only a fraction of the many compounds that comprise the fragrance of a living rose, can it really be said that it effectively emulates what it is to smell a rose?
## Too much of a… thing
There have been many articles written on the field of "scent marketing," or "[sensory branding](https://en.wikipedia.org/wiki/Sensory_branding#Smell)," in which marketers manipulate the emotions of their customers through fragrance, with aim to bolster sales or steer brand perception through a medium that speaks to humankind on a most intimate and primal level. From perfumed love letters, to the occasional baker realizing that keeping something in the oven at all times certainly doesn't *hurt* sales, this is not a new phenomenon. What is new, however, is the ease with which shallow replicas of even the worlds scarcest aromatics can be whipped up with alacrity by a worker in a lab coat, and fragrance imbued into any material, any space, and any setting with little more than a few pumps of a spray bottle. This influences not only the way we think of aromatic ingredients and how their scents become known to us, but how we perceive fragrance itself: where once the acrid notes of burning wood were rendered transparent, now it is bright floral terpenes evocative of sunny spring mornings and bumblebees that fade into the periphery of our qualia; the fragrance of fresh citrus peel comes to evoke fluorescent lights and shiny tiled floors, that of vanilla becomes, well, *vanilla.*
Fragrance chemistry, the ability to synthesize compounds that speak directly to human emotion, must be among the most powerful of the cheat codes made available to us through the [Game Genie](https://en.wikipedia.org/wiki/Game_Genie#NES) of industrialization. While at first glance it seems too good to be true, you soon realize that the excitement of receiving a [P-Wing](https://www.mariowiki.com/P-Wing) is lost when you can simply spam the A-button to fly past a level; it's just not special any more—further, it loses its utility. Today there is no escape from fragrance. Your average American leaves the house with minty teeth, hair styled with wax scented with a synthetic approximation of eucalyptus and lime peel, wearing clothing washed with a "fresh laundry" fragranced detergent and dried with a lemon fabric softener; after bathing with sandalwood soap, they apply "sea salt and cedar" deodorant and a cologne featuring dozens of compounds, including a handful intending to approximate agarwood and bergamot (what the cologne adds here I struggle to imagine). In this veritable cacophony, most people fail to notice much of anything at all unless it's utterly redolent, and those who do are often those with sensory issues for whom fragrance is, more often than not, a special form of torture, inescapable so long as they wish to occupy a public space.
## Expecting redolence
In the noisily fragrant environment in which most of us live, it is interesting to consider those notes that do cause us to take notice: the humming of a cherry lip balm; the undulating tenor of a fresh bar of hand-soap; the [death metal pig-squealing](https://youtu.be/hCFBrQWYe3o?si=TWc0qzSkxNp_aOaw&t=50) of a Glade PlugIn®. In each case, our attention is arrested—violently seized and detained as hundreds of volatile organic compounds fight for access to our olfactory receptors like so many tired workers scrambling for a square foot of floor-space on the train during rush hour, only this time they compete in teams. Like music, fragrance has been demoted from something precious and closely associated with those things that we considered to be sacred—reduced to a dollar-store simulacrum stuffed into a mascot costume and made to flip a sign beside countless products that would otherwise fail to vacate store shelves on the merit of their performance alone. Certainly, some would point to the cheap ubiquity of fragrance as a sign that access has improved; after all, did the average medieval tradesman have a passing familiarity with the fragrance of sandalwood? I would rebut: do we?
In such a world, the fragrance of natural incense, incense free of unnaturally synthesized or concentrated aromatics, can be to our environment as the tune of a songbird is to the roar of passing traffic. In our homes, we can largely retreat from the soundtrack of daily life and create quiet, as far as noise is concerned. Creating quiet from fragrance, however, requires a greater degree of effort. Irrespective of our environment, much of the difficulty newcomers face in "listening to" natural incense stems from their expectations, warped by the ceaseless atonal chorus of fragrance around them. Chiefly, the hurdle that must be overcome is the idea of fragrance as a background element—a sort of olfactory elevator music; incense is, and deserves to be seen as, an activity in and of itself. When we adopt this mindset and listen with intention, it is remarkable what we are able to parse in even quite unsuited environments. Incense doesn't have to compete with the pumpkin-spice wax-melts of the world; these things serve different purposes.
## Fortissimo
Adding to their similarities, fragrance and music share a common loss: that of dynamics. The modulation of volume was historically an important piece of the emotional pull that music can have on its listeners; modern production largely omits this technique, barring a grand pause or two, in favor of a [loudness war](https://en.wikipedia.org/wiki/Loudness_war). As in classical music, classical fragrance employs this tool, creating one of the great points of pleasure of the incense format. Natural incense moves and changes, undulating in fragrance and strength, floating on the minute air currents of the room. Here, subtlety is as much an asset as is strength. I'm always disappointed to light a stick only to find that it spews a steady stream of oil-based fragrance into my living space, whether or not synthetics are involved. To be clear, I'm not inherently against the use of concentrates in incense, or even synthetics, which are often chemically identical to compounds found in natural materials. That said; for those seeking a sharp, cologne-like fragrance with unnatural clarity and strength, I believe incense is a poor choice.
While natural incense can indeed have plenty of fragrance, as an incense maker, I leave reaching for that 'beaten with a pillowcase of cinnamon sticks' projection to makers of scented candles and exfoliating bath soaps. If I intended to add to the cacophony, I'd reach for simpler means: a reed diffuser perhaps. Instead, what I aim to do is create an opportunity for respite, to create something beautiful that asks for attention rather than steals it. This approach respects the material realities of the ingredients that comprise incense, as well as the format itself. When one takes this approach, it's not long before one reaches the realization that rose petals carefully expressed in the smoke of a burning stick of incense do indeed smell of rose. So too do petals warming on a heater. So does rose oil, as well as burying your face in a fragrant blossom.
[^1]: To put this in more comprehensible terms, taking this ratio as gospel: if a quantity of rose petals equivalent to the weight of the average man living in the U.S.A. were to be distilled, the resulting essential oil would amount to *30 grams* of extremely concentrated oil.

View File

@ -0,0 +1,22 @@
---
permalink: /blogroll/nathanUpchurchBlogroll.opml
---
<?xml version="1.0" encoding="UTF-8"?>
<opml version="2.0">
<head>
<title>nathanUpchurchBlogroll.opml</title>
<ownerName>Nathan Upchurch</ownerName>
</head>
<body>{% for category in blogroll.categories %}
<outline id="{{ category.name }}" text="{{ category.name }}">{% for blog in category.blogs %}
<outline
text="{{ blog.title }}"
description="{{ blog.description }}"
htmlUrl="{{ blog.url }}"
title="{{ blog.title }}"
type="rss"
version="RSS2"
xmlUrl="{{ blog.feedUrl }}"/>{% endfor %}
</outline>{% endfor %}
</body>
</opml>

View File

@ -0,0 +1,29 @@
---
layout: layouts/base.njk
title: Nathan Upchurch | Blogroll
structuredData: none
---
<h1>Blogroll</h1>
<p class="nodropcap page-block">Here are some of the blogs I subscribe to. You can click the RSS icon next to each to subscribe using <a href="../about-feeds/">your newsreader</a>, or import all of them at once by downloading and importing this convenient <a href="./nathanUpchurchBlogroll.opml" download>.opml file</a>.</p>
{% for category in blogroll.categories %}
<section class="blogroll">
<h2>{{ category.name }}:</h2>
{% for blog in category.blogs %}
<div class="blogroll-category-group">
<a href="{{ blog.url }}"><h3>{{ blog.title }}</h3></a>
<a href="{{ blog.feedUrl }}">
<svg class="tag-feed-icon small" viewBox="0 0 155 155" width="153.349" height="152.909" version="1.0" xmlns="http://www.w3.org/2000/svg">
<title>RSS feed for {{ blog.url }}</title>
<g transform="translate(-427.323 -373.814)">
<ellipse style="opacity: 1; fill-opacity: 1; fill-rule: nonzero" transform="matrix(.86996 0 0 .86996 135.156 330.529)" cx="360.357" cy="200.643" rx="24.643" ry="23.929"></ellipse>
<path style="fill-opacity: 1; fill-rule: evenodd" d="m427.835 455.057-.073-30.273c64.706 3.375 100.619 49.673 101.5 101.94h-30.318c-.503-45.942-31.74-69.996-71.11-71.667z"></path>
<path style="fill-opacity: 1; fill-rule: evenodd" d="m428.201 404.571-.878-30.757C526.75 378.43 580 450.582 580.67 526.724l-31.197-.44c1.365-48.704-34.665-120.267-121.273-121.713Z"></path>
</g>
</svg>
</a>
<p>{{ blog.description | safe }}</p>
</div>
{% endfor %}
</section>
{% endfor %}

64
content/changelog.md Normal file
View File

@ -0,0 +1,64 @@
---
layout: layouts/base.njk
title: Nathan Upchurch | Changelog
structuredData: none
---
# Changelog
* 2025-03-28
* Updated header on [/tags/](/tags/).
* 2025-03-27
* Added [Adam Silver](https://adamsilver.io/) to the [blogroll](/blogroll).
* 2025-03-20
* Added a bunch of design blogs to the [blogroll](/blogroll).
* 2025-03-12
* Removed [Kevin Drum's blog](https://jabberwocking.com/) from the [blogroll](/blogroll) in light of [his passing](https://jabberwocking.com/health-update-100/) on the seventh of March, 2025. Rest in peace, Kevin.
* 2025-03-11
* Updated [/wish](/wish).
* 2025-02-21
* Updated [/wish](/wish) again as my mum bought me some incense sticks for my birthday.
* 2025-02-20
* Updated [/wish](/wish).
* 2025-02-17
* Added [Incense Apprentice](https://incenseapprentice.substack.com) to the [blogroll](/blogroll).
* 2025-02-11
* Add [Signal](https://signal.me/#eu/j-om4cfsGXtfKo0UX28EQfEL_Gd1KpJr8nQpI9Smhdsb-r98eT5F6obQ1BcYZCcW) to [/me](/me).
* Remove [Loops](https://loops.video/) from [/me](/me).
* 2025-02-06
* Add [Friendica profile](https://friendica.world/profile/nathan) to [/me](/me).
* Deprecate cowsay of the day.
* 2025-02-04
* Re-implement support for Open Graph and Twitter Card metadata because [I'm an idiot](https://github.com/mastodon/mastodon/issues/33812#issuecomment-2635441141) and didn't realize that you can't use the `<meta>` tag for images and there appears to be no officially supported way to do this except for appropriating the mechanism reserved for app icons and favicons.
* 2025-02-02
* Implement [quiz features](/quizzes/) and add [first quiz](/quizzes/how-much-of-a-linux-nerd-are-you/).
* 2025-02-01
* Remove support for Open Graph and Twitter Card metadata because A. bloat, and B. screw Musk and Zuck.
* Add "image" meta tag for all pages, using either the image specified for the page / post, or my smiling face as a default.
* Fix issue with metadata output on gallery image pages.
* Stopped bundling CSS and injecting it into pages as I was sick of 1,000 lines of CSS on *every single page* (My build times are now a third of what they were).
* 2025-01-31
* Update the copyright notice in the footer.
* 2025-1-29
* Add [The Contrarian](https://contrarian.substack.com/) to the [blogroll](/blogroll).
* 2025-1-24
* Add buttons / update [/now/](/now/).
* 2025-1-23 - Simplify, simplify, simplify
* Styling updates to text, figures, and post lists
* Removed Mastodon comment embedding in favor of a simple button.
* Removed "Read Next / Read Previous" cards beneath articles.
* Prettier date formatting throughout.
* 2025-1-13
* Added [Popular Information](https://popular.info/) to the [blogroll](/blogroll).
* 2024-12-16
* Update PeerTube instance on [/me](/me).
* 2024-12-15
* Added a link to site stats on the [privacy](/about/privacy) page.
* Added [Uncloseted Media](https://www.unclosetedmedia.com/) to the [blogroll](/blogroll).
* 2024-12-14
* Implemented [/wish](/ai) a la [taylor.town/wish-manifesto](https://taylor.town/wish-manifesto).
* Added [Dom Corriveau](https://blog.ctms.me/) to the [blogroll](/blogroll).
* 2024-12-11
* Removed [Inverse](https://www.inverse.com/) from the [blogroll](/blogroll) due to excessive and annoying Amazon affiliate link articles.
* Added [Aftermath](https://aftermath.site/) to the [blogroll](/blogroll).
* Implemented [/changelog](/changelog) 🎉.
* Implemented [/ai](/ai) a la [slashai.page](https://slashai.page/).

View File

@ -8,6 +8,8 @@ pagination:
- post
- posts
- tagList
- gallery
- galleryImages
addAllPagesToCollections: true
eleventyComputed:
title: “{{ tag }}”

24
content/galleries.njk Normal file
View File

@ -0,0 +1,24 @@
---
pagination:
data: galleries
size: 1
alias: gallery
layout: layouts/base.njk
tags: gallery
structuredData: none
eleventyComputed:
title: "{{ gallery.title }}"
permalink: "/gallery/{{ gallery.title | slugify }}/"
description: "{{ gallery.description }}"
---
<h1>{{ gallery.title }}</h1>
<p class="page-block nodropcap">{{ gallery.description }}</p>
<section class="gallery-images">
{% for picture in gallery.pictures %}
<a href="/gallery/{{ gallery.title | slugify }}/{{ picture.filename | slugify }}/">
<wc-card class="gallery-image-container">
<img alt="{{ gallery.thumbAltText }}" class="gallery-image" src="{{ gallery.url }}{{ picture.filename }}">
</wc-card>
</a>
{% endfor %}
</section>

View File

@ -0,0 +1,11 @@
---
layout: layouts/base.njk
eleventyNavigation:
key: Pics
order: 4
---
<h1>My image galleries.</h1>
<p class="page-block nodropcap">
Photography trips, memes, and other pictures I thought would be worth sharing.
</p>
{% include "gallerieslist.njk" %}

41
content/galleryImage.njk Normal file
View File

@ -0,0 +1,41 @@
---
pagination:
data: collections.galleryImages
size: 1
alias: picture
layout: layouts/base.njk
structuredData: none
eleventyComputed:
imageURL: "{{ picture.baseUrl }}/{{ picture.filename }}"
title: "Image: {{ picture.title }}"
permalink: "/gallery/{{ picture.containingGallery | slugify }}/{{ picture.filename | slugify }}/"
description: "{{ picture.title }} from gallery: {{ picture.containingGallery}}"
---
<article>
<h1>{{ picture.title }}</h1>
<div class="buttonContainer galleryButtons">
{% if picture.previousImage %}
<a href="../{{ picture.previousImage | slugify }}">
<button type="button">Previous</button>
</a>
{% endif %}
<a href="/gallery/{{ picture.containingGallery | slugify }}/">
<button type="button">Gallery</button>
</a>
{% if picture.nextImage %}
<a href="../{{ picture.nextImage | slugify }}">
<button type="button">Next</button>
</a>
{% endif %}
</div>
<figure>
<a href="{{ picture.baseUrl }}/{{ picture.filename }}">
<img src="{{ picture.baseUrl }}/{{ picture.filename }}" alt="{{ picture.altText }}">
</a>
{% if picture.caption %}
<figcaption>
{{ picture.caption }}
</figcaption>
{% endif %}
</figure>
</article>

View File

@ -3,36 +3,90 @@ layout: layouts/home.njk
eleventyNavigation:
key: Home
order: 1
numberOfLatestPostsToShow: 5
numberOfLatestPostsToShow: 3
numberOfNowPostsToShow: 1
numberOfGalleriesToShow: 1
numberOfQuizzesToShow: 1
hideGalleryDescriptions: 1
---
<div class="now">
<h2>What I've been up to:</h2>
{% set postsCount = collections.now | length %}
{% set latestPostsCount = postsCount | min(numberOfNowPostsToShow) %}
{% set postslist = collections.now | head(-1 * numberOfNowPostsToShow) %}
{% set postslistCounter = postsCount %}
{% set showPostListHeader = false %}
{% include "postslist.njk" %}
<a class="link-button" href="/now/">
<section class="indexFeature">
<h2>Latest gallery:</h2>
{% set postsCount = galleries | length %}
{% set latestPostsCount = postsCount | min(numberOfGalleriesToShow) %}
{% set postslist = galleries | head(-1 * numberOfGalleriesToShow) %}
{% set postslistCounter = postsCount %}
{% set showPostListHeader = false %}
{% include "gallerieslist.njk" %}
{% set morePosts = postsCount - numberOfGalleriesToShow %}
{% if morePosts > 0 %}
<a href="/galleries/">
<button type="button">
See more on the “now” page
See {{ morePosts }} more »
</button>
</a>
</div>
{% endif %}
</section>
{% set postsCount = collections.posts | length %}
{% set latestPostsCount = postsCount | min(numberOfLatestPostsToShow) %}
{% set postslist = collections.posts | head(-1 * numberOfLatestPostsToShow) %}
{% set postslistCounter = postsCount %}
{% set showPostListHeader = true %}
{% include "postslist.njk" %}
<section class="indexFeature">
<h2>Latest quiz:</h2>
{% set postsCount = collections.quiz | length %}
{% set latestPostsCount = postsCount | min(numberOfQuizzesToShow) %}
{% set postslist = collections.quiz | head(-1 * numberOfQuizzesToShow) %}
{% set postslistCounter = postsCount %}
{% set showPostListHeader = false %}
{% include "postslist.njk" %}
{% set morePosts = postsCount - numberOfLatestPostsToShow %}
{% if morePosts > 0 %}
<a class="link-button" href="/blog/">
<button type="button">
See {{ morePosts }} more post{% if morePosts != 1 %}s{% endif %} in the blog
</button>
</a>
{% endif %}
{% set morePosts = postsCount - numberOfQuizzesToShow %}
{% if morePosts > 0 %}
<a href="/quizzes/">
<button type="button">
See {{ morePosts }} more »
</button>
</a>
{% endif %}
</section>
<section class="indexFeature">
<div class="now">
<h2>Life updates:</h2>
{% set postsCount = collections.now | length %}
{% set latestPostsCount = postsCount | min(numberOfNowPostsToShow) %}
{% set postslist = collections.now | head(-1 * numberOfNowPostsToShow) %}
{% set postslistCounter = postsCount %}
{% set showPostListHeader = false %}
{% include "postslist.njk" %}
{% set morePosts = postsCount - numberOfNowPostsToShow %}
{% if morePosts > 0 %}
<a href="/now/">
<button type="button">
See {{ morePosts }} more »
</button>
</a>
{% endif %}
</div>
</section>
<section class="indexFeature">
{% set postsCount = collections.posts | length %}
{% set latestPostsCount = postsCount | min(numberOfLatestPostsToShow) %}
{% set postslist = collections.posts | head(-1 * numberOfLatestPostsToShow) %}
{% set postslistCounter = postsCount %}
{% set showPostListHeader = true %}
{% include "postslist.njk" %}
{% set morePosts = postsCount - numberOfLatestPostsToShow %}
{% if morePosts > 0 %}
<div class="buttonContainer">
<a href="/blog/">
<button type="button">
See {{ morePosts }} more »
</button>
</a>
{% endif %}
<a href="/tags/">
<button type="button">Topics »</button>
</a>
</div>
</section>

View File

@ -1,17 +1,29 @@
---
layout: layouts/base.njk
eleventyNavigation:
key: Now
order: 4
title: Nathan Upchurch | Now
structuredData: none
---
<article class="post">
<h1>Now: Whats Been Going on Lately?</h1>
<h1>Now: Life updates.</h1>
{% set now = collections.now | last %}
<h2>{{ now.data.title }}</h2>
<h2>{{ now.data.title }} • {{ now.date | niceDate }}</h2>
{{ now.content | safe }}
</article>
<p class="metadata">Updated: {{ now.date | readableDate }} |&nbsp;<a href="https://nownownow.com/about">What is a now page?</a></p>
<div class="buttonContainer">
<a class="link-button" href="/feeds/now.xml">
<button type="button">
<img src="/img/RSS.svg">
Subscribe to “Now” Posts
</button>
</a>
<a class="link-button" href="https://nownownow.com/about">
<button type="button">
What is a now page?
</button>
</a>
</div>
{% set postsCount = collections.now | removeMostRecent | length %}
{% if postsCount > 1 %}
<h2>Previous Entries:</h2>
@ -20,3 +32,4 @@ eleventyNavigation:
{% include "postslist.njk" %}
{% endif %}

View File

@ -0,0 +1,28 @@
---
title: Moving is Hard, Porches are the Best
description: Moving, sitting on the porch, washing dishes like my forebears, and caving to peer pressure.
synopsis: Moving, sitting on the porch, washing dishes like my forebears, and caving to peer pressure.
date: 2024-10-06
imageURL: /img/soap.webp
imageAlt: A close-up of a packaged block of soap, reading&#58; Marseille Soap, to cut, with olive oil.
---
About a month ago I moved just up the street, so to speak. The last time I moved, I had the cash to hire movers, but this September it was down to me and whatever poor saps I could cajole into helping in exchange for a warm fuzzy feeling. I will remain eternally grateful for my good friend and business partner Davey's help in making numerous van runs, as well as driving the U-Haul and schlepping numerous awkward and heavy containers and objects up a very tight flight of stairs, and I owe endless thanks to my partner Sol for helping me get everything arranged and organized. Oh, and in addition to being a first-rate moving helper, Davey also has a new album out; if you're in the market for a new punk record with album artwork designed by yours truly, you can [grab a copy here](https://daveydynamite.bandcamp.com/album/in-memory).
## What's this new place like, then?
I've realized that for the past few years, my lifestyle has been neck and neck with my means. Lord knows it's [hard enough for the average American tax-payer to put anything by for a rainy day](https://www.gobankingrates.com/banking/banks/how-much-money-do-americans-have-in-their-bank-accounts-in-2024/), but the ability to pay off debt and save money is of particular importance to me as my partner and I are desperate to move back to my home-country of Scotland, which has made it nigh-on impossible for anyone but the wealthy to bring a non-citizen spouse into the country due to UK immigration policy falling victim to the spittle-flecked anti-immigrant ravings of certain English politicians. All this to say, the new place is a bit of a downgrade.
The story of *why* this place is so affordable is more than I care to inflict on the public at large, but suffice it to say that I recently ordered one of those little scraper handles with a bundle of bright orange plastic razor-blades. Cleanup aside, I'm having to make some adjustments. In the U.S., people tend to look at you with horror when you tell them that you don't have a shower at home, but I've been rather enjoying the cast iron claw-foot tub that sits a few feet beneath the slope of the roof. Pouring a pitcher of water over my head to rinse off makes me feel like I'm in an ancient Greek bath-house.
Some kind souls close to me have lent me a couple of AC units to help me contend with the lack of central air, and I just bought a larger Black and Decker window unit with a remote control for the bedroom. Going without a dishwasher is the difference making the most impact on my day to day life at the moment, as I tend to cook a lot, but I'm finding that there's something meditative about washing dishes by hand like my forebears. I've even procured a nice big block of Marseille Soap for the dishes — a one-kilogram block, green as the olive oil that it's made from, that comes with a little wire to help you cut off slices of the block to use in different places around the house.
[![A close-up of a packaged block of soap, reading: Marseille Soap, to cut, with olive oil.](/img/soap.webp "No garish perfumes will taint **my** dishes!")](/img/soap.webp)
## So I'm a porch person now.
Besides the 33% reduction in rent, there are some distinct benefits to living where I now do. For a start, the downstairs neighbors are great people. My new street is much quieter owing to the lessened vehicle traffic, and it's a pretty street with lots of trees and some truly beautiful gardening work in places.
Living on a street where the outdoors is somewhere you want to be is, needless to say, a big improvement in terms of quality of life. It's a short walk to the river, which is a lovely place to eat lunch, and I do like to ensure that the local ducks eat their fill of frozen peas. Speaking of lunch, there's a cafe with at least one satisfying vegan option only a couple of doors down, and finally, there's a nice big porch at the front of the building, complete with ample furniture for sitting and observing the neighborhood. Dear reader, a month-in and I am already a fixture of the neighborhood alongside so many garden-gnomes and plastic flamingos. The porch is the perfect place to eat any meal, a great place to get to know your neighbors, and an easy way to spend plenty of time outdoors; the porch is where I want to be.
The apartment itself is not without its charms. There's a nice big room at the front that makes for a very comfortable study, with lots of space for working, playing my (muted) trombone, my bookcases and collection of aromatics, and even a solid wood high-top table that is now dedicated to incense-making. I have a large electric standing corner-desk that I raise and put my treadmill beneath to allow me to get some light exercise while I perform my day job; it was a trial fitting this all into the small room I had prior to the move. With everything in place the space feels cozy and well-appointed despite the features it lacks. All considered, I'm happy with the decision to move, even before reaping the benefits of a reduced monthly rent.
## Peer pressure
I finally caved to the fear of missing out and joined Instagram solely to participate in an incense makers' group where some friends from the incense community hang out and talk incense-making technicalities. A staunch anti-corporate-social-media fediverse user, I resent joining a platform that scrapes user content for AI training, let alone the flagrant data collection and privacy violations, but, hell, I figure I'll make an exception just this once and *only* use it for the group.

View File

@ -0,0 +1,23 @@
---
title: Welp, it's a New Year.
description: …and what a year it's been already.
synopsis: …and what a year it's been already.
date: 2025-01-23
imageURL: /img/IMG_20250122_172636_762_copy.webp
imageAlt: A closeup of a Braun wristwatch.
---
[Trump has been inaugurated](https://thehill.com/homenews/administration/5097933-trump-ymca-dance-inaugural-ball/); Elon Musk is [performing Nazi salutes](https://www.politico.eu/article/elon-musk-salute-sparks-fury-from-europe-left-wing/) in public, the U.S. is [withdrawing from the Paris Agreement](https://www.npr.org/2025/01/21/nx-s1-5266207/trump-paris-agreement-biden-climate-change), the White House Spanish-language pages have been [shut down](https://www.pbs.org/newshour/politics/trump-adminstration-shuts-down-white-house-spanish-language-page-and-social-media), [whitehouse.gov](https://www.whitehouse.gov/) now features some sort of [onanistic hyper-nationalist movie trailer](https://www.wired.com/story/white-house-website-marvel-movie-trailer-helicopters-bald-eagle/), the federal government is [officially hostile](https://19thnews.org/2025/01/trump-transgender-executive-order/) to [transgender people](https://19thnews.org/2025/01/trump-executive-order-transgender-military-ban/), the Trump administration has [ended birthright citizenship](https://19thnews.org/2025/01/birthright-citizenship-lawsuit-pregnant-women/), immigrants are [hiding in their homes](https://www.chicagotribune.com/2025/01/21/immigrants-skip-work-amid-ice-fears/) for fear of arrest and deportation, an official government website has a god-damn [Shiba Inu meme](https://abcnews.go.com/Politics/wireStory/trump-made-doge-part-government-117981045) on it (along with an ASCII version in the page source), more than half of U.S. citizens [read below a sixth-grade level](https://www.snopes.com/news/2022/08/02/us-literacy-rate/) (that's the level expected of a twelve-year-old), capitalism is still steamrolling ahead just about everywhere, people are still eating cute, fluffy animals even though beans exist, you're now officially, explicitly, [allowed to call LGBTQ+ people mentally ill](https://www.axios.com/2025/01/09/meta-moderation-transgender-women-hate) on Facebook, Threads, and Instagram, and the planet is burning.
Anyway, the *now* section of my website is supposed to be a bit less existential, so here's what I've been up to:
I spent much of the end of the year working four-day workweeks, which, my friends, is the way to go. I miss those short weeks already. After that, I had a Christmas celebration with Sol's folks, which, despite a minor medical emergency was a nice time. I am happy to say that the person affected is recovering well. I gave some hand-made incense for presents, and I got some very useful things from my [wishlist](/wish/), including a Braun wall-clock so that I can tell the time when I'm doing dishes or otherwise can't access, or don't want to be distracted by, my phone.
One thing I'm trying to focus on in this new year is being less salty. I'm trying to accept people as they come, and regain the calm that I used to be able to retain in the face of great stupidity. Goodness knows there are people in this world who offer me this grace, so I intend to get some practice in offering it to others.
I've started [a forum](https://incensemakers.org/) for the fine folks of the incense-makers Instagram group. I'm very much hoping it takes off, because not only will it be a better, safer, and more useful way to catalog our shared knowledge, but it might mean that I can once again leave Instagram as the group is literally the only reason I'm on the platform. I'm also hoping that I don't wind up having to do much troubleshooting; we will see.
I am also working towards the [Google data analytics professional certificate](https://www.coursera.org/professional-certificates/google-data-analytics) because it seems like it ought to be fun, especially learning SQL (which I refuse to pronounce *sequel*) and R. If it turns out to be useful career-wise, great, but that's not why I'm doing it.
[^1]: And no, I don't mean give a portion to charity. The fact that you are rich should not mean that you get an outsized say in what issues get addressed. Get over yourself.

14
content/quizzes.njk Normal file
View File

@ -0,0 +1,14 @@
---
layout: layouts/base.njk
title: Nathan Upchurch | Quizzes
structuredData: none
description: "Bored? Take a fun quiz to while away the time!"
---
<h1>Quizzes</h1>
<p>Test your knowledge, learn about yourself, and waste your precious time, right here, right now, with a quiz!</p>
{% set postsCount = collections.quiz | length %}
<h2>Available Quizzes:</h2>
{% set postslist = collections.quiz %}
{% set showPostListHeader = false %}
{% include "postslist.njk" %}

View File

@ -0,0 +1,302 @@
---
title: "How Much of a Linux Nerd are You?"
description: "A quiz to find out how much of a Linux (or should I say GNU/Linux) nerd you are."
date: 2025-02-02
imageURL: "/img/Tux.svg"
imageAlt: "Tux the penguin."
consequences:
- title: "Why are you here?"
points: 0
spiel: "Look, I don't know how you found yourself here, but I think your time might be better spent elsewhere!"
image: "/img/lost.gif"
imageAlt: "An animated GIF of Cookie Monster looking around in a confused manner and scratching his head."
- title: "You're a beginner"
points: 30
spiel: "You know a couple things, but you're still just getting started on your Linux journey."
image: "/img/noob.gif"
imageAlt: "An animated GIF calling you a noob."
- title: "Linux user detected"
points: 60
spiel: "You are a bona fide Linux user."
image: "/img/tuxfall.gif"
imageAlt: "An animated GIF of a gelatinous Tux falling from the sky and landing with a jiggle."
- title: "You're a Linux pro"
points: 90
spiel: "You ain't scared of the terminal."
image: "/img/matrix.gif"
imageAlt: "An animated GIF of letters falling on a black screen, matrix style."
- title: "Certified Linux nerd"
points: 120
spiel: "Fire up some tendies in celebration, because you are a certified Linux nerd. Frankly, I'm surprised you turned on JavaScript in your browser to complete this quiz!"
image: "/img/tendies.gif"
imageAlt: "An animated GIF of Post Malone eating tendies."
- title: "Linus… is that you?"
points: 150
spiel: "Either you looked at the source code for this page, or you are a GNU/Linux god."
image: "/img/linus.gif"
imageAlt: "An animated GIF of Linus Torvalds speaking and flipping off the camera."
questions:
- title: "What is a kernel?"
image:
imageAlt:
imageCaption:
answers:
- name: "Some sort of seed or pit."
points: 0
- name: "The part of an operating system that bridges software and hardware."
points: 5
- name: "A piece of software that controls the desktop environment."
points: 0
- name: "…another free component of a fully functioning GNU system…"
points: 10
- title: "Which desktop environment is known for its unique workflow and consistent appearance?"
image:
imageAlt:
imageCaption:
answers:
- name: "GNOME"
points: 5
- name: "KDE"
points: 0
- name: "Cinnamon"
points: 0
- name: "Xfce"
points: 0
- title: "Which distro might someone use, BTW?"
image:
imageAlt:
imageCaption:
answers:
- name: "Debian"
points: 0
- name: "openSUSE"
points: 0
- name: "Fedora"
points: 0
- name: "Arch"
points: 5
- title: "Which utensil does :(){ :|:& };: bring to mind?"
image:
imageAlt:
imageCaption:
answers:
- name: "A Chopstick"
points: 0
- name: "A Fork"
points: 5
- name: "A Spoon"
points: 0
- name: "A Knife"
points: 0
- title: "Which of the following distros accidentally launched a DDOS attack on an upstream repo?"
image:
imageAlt:
imageCaption:
answers:
- name: "Garuda"
points: 0
- name: "Nix"
points: 0
- name: "Vanilla OS"
points: 0
- name: "Manjaro"
points: 5
- title: "Complete the sequence: sudo rm -rf"
image:
imageAlt:
imageCaption:
answers:
- name: "/"
points: 5
- name: "*.jpg"
points: 0
- name: "/dev/sda"
points: 0
- name: "--no-preserve-root /"
points: 10
- name: "*/."
points: 0
- title: "What is your favorite package format?"
image:
imageAlt:
imageCaption:
answers:
- name: "Bubble wrap"
points: 0
- name: "Snap"
points: -5
- name: "Flatpak"
points: 5
- name: "Native Packages"
points: 10
- name: "AppImage"
points: 5
- name: "Piping install scripts from GitHub to bash"
points: 0
- title: "Desktop environment or window manager?"
image:
imageAlt:
imageCaption:
answers:
- name: "Desktop environment"
points: 0
- name: "Window manager"
points: 5
- name: "Both are bloat"
points: 10
- title: "From memory, use the tar command to create a compressed tarball. Did you succeed?"
image:
imageAlt:
imageCaption:
answers:
- name: "Yes"
points: 5
- name: "No"
points: 0
- title: "Which command will make a train roll across your terminal?"
image:
imageAlt:
imageCaption:
answers:
- name: "sudo rm -rf /*"
points: 0
- name: "dd if=/dev/zero bs=10G count=10000 | bzip2 -c > train.bz2"
points: 0
- name: ":(){ :|:& };:"
points: 0
- name: "sl"
points: 5
- title: "Which of the following commands will successfully exit Vim?"
image:
imageAlt:
imageCaption:
answers:
- name: "ctrl+q"
points: 0
- name: "exit"
points: 0
- name: ":wq!"
points: 5
- name: ":qv"
points: 0
- title: "SystemD is…"
image:
imageAlt:
imageCaption:
answers:
- name: "A suite of basic building blocks for a Linux system"
points: 5
- name: "A backup in case your Windows dual-boot eats your Linux install."
points: 0
- name: "A utility to mount external drives."
points: 0
- name: "Bloat"
points: 10
- title: "Choose your favorite musical instrument:"
image:
imageAlt:
imageCaption:
answers:
- name: "🎸"
points: 0
- name: "🎷"
points: 0
- name: "GRUB"
points: 10
- name: "🎻"
points: 0
- title: "…won't be big and professional like…?"
image:
imageAlt:
imageCaption:
answers:
- name: "GNU"
points: 5
- name: "Unix"
points: 0
- name: "Windows Vista"
points: 0
- name: "TempleOS"
points: 0
- title: "Which would NOT be a fun surprise for Richard Stallman?"
image:
imageAlt:
imageCaption:
answers:
- name: "Buying a parrot"
points: 5
- name: "A room temperature of 71℉"
points: 0
- name: "Helping him cross the street"
points: 5
- name: "A nice dinner with less than four people total"
points: 0
- title: "What did Microsoft CEO Steve Ballmer call GNU/Linux?"
image:
imageAlt:
imageCaption:
answers:
- name: "A cancer"
points: 5
- name: "An amateur effort"
points: 0
- name: "Delightful"
points: 0
- name: "Bloat"
points: 0
- title: "What is your favorite animal?"
image:
imageAlt:
imageCaption:
answers:
- name: "🦊"
points: 10
- name: "🐧"
points: 5
- name: "🐢"
points: 0
- name: "🪱"
points: 0
- title: "Which distro is named after a husband and wife?"
image:
imageAlt:
imageCaption:
answers:
- name: "Trisquel"
points: 0
- name: "Manjaro"
points: 0
- name: "Ubuntu"
points: 0
- name: "Debian"
points: 5
- title: "Best package to install on a fresh Linux installation?"
image:
imageAlt:
imageCaption:
answers:
- name: "XZ 5.6.0"
points: 20
- name: "Inkscape"
points: 5
- name: "Timeshift"
points: 10
- name: "Photoshop"
points: -5
- title: "Which game console had an official Linux distro that users could buy and install?"
image:
imageAlt:
imageCaption:
answers:
- name: "PlayStation 2"
points: 5
- name: "Nintendo 64"
points: 0
- name: "Nintendo Wii"
points: 0
- name: "Xbox 360"
points: 0
---
Are you *k*onfident in your KDE knowledge? Have you joined us now, shared the software, and spread the good *gn*ews about your newfound freedom? Do you find it *awk*ward when people use proprietary software? No more *Stall*ing; it's time to *find* out whether you're a true GNU/Linux nerd.
*Note: Please do not type any of the commands on this page into your terminal without first looking them up. And even then, probably still don't.*

View File

@ -0,0 +1,4 @@
export default {
tags: ["quiz"],
layout: "layouts/quizzes.njk",
};

30
content/sitemap/index.njk Normal file
View File

@ -0,0 +1,30 @@
---
layout: layouts/base.njk
title: Nathan Upchurch | Sitemap
structuredData: none
---
<section class="sitemap">
<h1>Sitemap</h1>
<ul>
<li><a href="/">Home</a></li>
<li>
<a href="/about">About</a>
<ul>
<li><a href="/about/colophon">Colophon</a></li>
<li><a href="/about/privacy">Privacy</a></li>
</ul>
</li>
<li><a href="/ai">AI</a></li>
<li><a href="/blog">Blog</a></li>
<li><a href="/blogroll">Blogroll</a></li>
<li><a href="/changelog">Changelog</a></li>
<li><a href="/me">Contact</a></li>
<li><a href="/feed/feed.xml">Feed</a></li>
<li><a href="/galleries">Galleries</a></li>
<li><a href="/now">Now</a></li>
<li><a href="/tags">Tags</a></li>
<li><a href="/wish">Wishes</a></li>
<li><a href="/quizzes">Quizzes</a></li>
</ul>
</section>

View File

@ -1,11 +1,13 @@
---
permalink: /tags/
layout: layouts/base.njk
title: Nathan Upchurch | Tags
structuredData: none
---
<h1>Here are some things I like to talk about.</h1>
<h1>Tags / Topics</h1>
<p class="page-block nodropcap">
Click on a tag to see all posts on the topic.
Click on a tag to see all posts on the topic; you can also subscribe to an RSS feed of any individual topic on the topic page.
</p>
<ul class="taglist">

View File

@ -10,9 +10,11 @@ pagination:
- tagList
addAllPagesToCollections: true
layout: layouts/base.njk
structuredData: none
eleventyComputed:
title: Tagged “{{ tag }}”
permalink: "/tags/{{ tag | slugify }}/"
title: Posts tagged “{{ tag }}”
permalink: "/tags/{{ tag | slugify }}/"
description: A list of every post I've written tagged “{{ tag }}.”
---
<h1>More posts tagged “{{ tag }}.”
<a href="/feeds/{{ tag | slugify }}.xml">
@ -37,7 +39,7 @@ permalink: "/tags/{{ tag | slugify }}/"
</svg>
</a>
</h1>
<p class="page-block nodropcap">Heres everything Ive posted with the tag “{{ tag }}:”</p>
<p class="page-block nodropcap">Heres everything Ive posted tagged “{{ tag }}.” Want to be notified when I post on this topic? <a href="/feeds/{{ tag | slugify }}.xml">Subscribe to “{{ tag }}.”</a></p>
{% set postslist = collections[ tag ] %}
{% include "postslist.njk" %}

81
content/wish.md Normal file
View File

@ -0,0 +1,81 @@
---
layout: layouts/base.njk
title: Nathan Upchurch | Wish
structuredData: none
---
# My Wishlist
## What is this?
This page is a list of wishes, a la [taylor.town/wish-manifesto](https://taylor.town/wish-manifesto), both tangible and intangible.
## On gifts
If you're here looking for a gift idea for me, while I am always grateful that someone is thinking of me, when I look about me I get the impression that I don't really need more objects in the house to store, clean, and look after. When I decide to buy something myself, I do my best to be very intentional in choosing something that I feel will meet my needs perfectly, and will last as long as possible. Not only is this better for the environment, it helps me keep my life as simple and sustainable as possible, and frees me from the sense of obligation to return in kind, which I probably cannot afford to do.
If, however, *not* getting me a gift seems unconscionable, as best as I can determine, the non-consumable material items below all meet a need exactly and will last long into the future, making them perfect gifts.
If, like my mother, the non-consumable items below seem too boring to you to satisfy the gift-giving itch, I'd always be delighted to receive anything from the [tea](#Tea), [edible](#Edible), or [incense](#Incense) sections.
## ADHD proofing / accessibility
* [A door organizer](https://www.amazon.com/Delamu-Organizers-Organization-Essentials-D5xW18xH50/dp/B0C4LPSQP3?th=1)
* [A lid organizer for food containers](https://www.amazon.com/dp/B07FNRXFTD/?psc=1)
* [Drawer organizing containers](https://www.amazon.com/dp/B07F7K5DP1/?th=1)
## Charities
* [Black Lives Matter](https://blacklivesmatter.com/)
* [Howard Brown](https://howardbrown.org/) - Howard Brown provides free and sliding scale general health, sexual health and reproductive care, and counseling and support services in Chicago, with focus on care for the LGBTQ+ community.
* [Northwest Side Solidarity Network](https://www.northwestsidesolidarity.com/) - A Chicago organization: "We work in solidarity with mutual aid groups throughout the city to ensure that all our neighbors have access to the resources that they need. Our work focuses on the Northwest side of the city, where we host a monthly free food-pop up with fresh produce, dairy, dried and canned goods."
* [Palestine Children's Relief Fund](https://www.pcrf.net/) - Provides free medical care to thousands of injured and ill children yearly who lack local access to care within the local health care system.
* [Transactual](https://transactual.org.uk/) - A trans-led UK based organization working towards a world where trans people can live safely, in dignity and with access to the healthcare they need.
## Edible
* Vegan haggis - I just miss haggis, and I remember vegan / vegetarian haggis being quite good. I did make a batch of my own once with TVP and it was nice, but it took ages to make.
* Vegan mooncakes from [Little Moon Bakehouse](https://littlemoonbakehouse.com/)
## Incense
* [Baieido Tokusen Kobunboku](https://kikohincense.com/collections/baieido-incense/products/tokusen-kobunboku)
* [Inca Aromas White Breu](https://tarotarts.com/products/inca-aromas-all-natural-fair-trade-incense-white-breu-for-clarity-and-spirituality?variant=39838738251860)
* [Minorien Kyara Fu-In](https://kikohincense.com/collections/minorien-incense-kikoh/products/minorien-kyara-fu-in-incense)
* [Kunmeido Reiryokoh](https://kikohincense.com/products/kunmeido-reiryokoh-incense)
* [Shoyeido Horin Assortment](https://shoyeido.com/products/horin-incense-assortment-sampler)
* [Shoyeido Kohbai Pressed Incense](https://shoyeido.com/products/kohbai-red-plum-blossoms?variant=41714738921590)
* [Shoyeido Premium Incense Sampler](https://shoyeido.com/products/premium-incense-assortment-sampler)
* [Tennendo Cedar Waterwheel](https://www.japanincense.com/tn-0060.html)
* [Tennendo Hana no Byakudan](https://www.japanincense.com/tn-0051.html)
## Incense making
* [Oak moss](https://www.amazon.com/Oak-Moss-Herb-Natural-Prunastri/dp/B0B4KL6WSJ)
* [Powdered ruffle lichen / dagad phool](https://www.amazon.com/dp/B0BYB8XVPZ/?psc=1)
## Life
* To advance my knowledge of mathematics.
* To be able to direct and sustain my focus.
* To be better able to listen and trust when people describe their challenges.
* To become a *great* programmer.
* To be more patient.
* To find a form of exercise that fits neatly into my life, and is fun and engaging enough that it doesn't feel like drudgery.
* To have control over my own time, rather have to cede it to an employer for survival.
* To learn C++ so I can contribute to KDE projects and Scribus.
* To learn German.
* To learn Rust.
* To learn Spanish *well*.
* To live in a house in the Scottish countryside, where I can spend my ample free time cooking, playing the trombone, messing about with computers, and making incense.
* To no longer have to worry about money.
* Warm hands and feet at all times.
## Society
* Anyone who declares a war fights on the front lines.
* Common ownership of public utilities and production facilities.
* Equitable access to spaces and resources for everyone.
* For people to have the humility to be able to change their beliefs when faced with evidence to the contrary.
* For people to listen and trust when others describe their challenges.
* For people to recognize that systemic violence *is violence*.
* For people to stop worrying about things that don't affect them and instead focus on issues that materially impact their daily lives.
* For religion and any form of magical thinking to disappear in favor of basing beliefs on evidence and logic.
* Healthcare, education, housing, and any resource necessary to sustain life to be free for all.
## Tea
* A malty black tea from either [Spirit Tea](https://spirittea.co/) or [Yunnan Sourcing](https://yunnansourcing.com/).
* A peachy white tea from either [Spirit Tea](https://spirittea.co/) or [Yunnan Sourcing](https://yunnansourcing.com/).
* A savory oolong from from either [Spirit Tea](https://spirittea.co/) or [Yunnan Sourcing](https://yunnansourcing.com/).

View File

@ -1,34 +1,62 @@
import { DateTime } from "luxon";
import { eleventyImageTransformPlugin } from "@11ty/eleventy-img";
import markdownIt from "markdown-it";
import markdownItFootnote from "markdown-it-footnote";
import markdownItAnchor from "markdown-it-anchor";
import mdfigcaption from 'markdown-it-image-figures';
import mdfigcaption from "markdown-it-image-figures";
import pluginRss from "@11ty/eleventy-plugin-rss";
import pluginSyntaxHighlight from "@11ty/eleventy-plugin-syntaxhighlight";
import pluginBundle from "@11ty/eleventy-plugin-bundle";
import pluginNavigation from "@11ty/eleventy-navigation";
import prettier from "prettier";
import { EleventyHtmlBasePlugin } from "@11ty/eleventy";
import {dateSuffixAdder, monthMap, timeFormatter} from "./public/js/modules/mastodonDateTools.js";
import {
dateSuffixAdder,
monthMap,
timeFormatter,
} from "./public/js/modules/dateTools.js";
const figoptions = {
figcaption: true
figcaption: true,
};
export default async function(eleventyConfig) {
export default async function (eleventyConfig) {
// Helper Functions
const multiReplace = (text, replacementTable) => {
let newText = text;
replacementTable.forEach(x => { newText = newText.replace(x[0], x[1]) });
replacementTable.forEach((x) => {
newText = newText.replace(x[0], x[1]);
});
return newText;
};
// Collections
eleventyConfig.addCollection("galleryImages", (collection) => {
const galleries = collection.getAll()[0].data.galleries;
let galleryImages = [];
galleries.forEach((gallery) => {
gallery.pictures.forEach((picture, i, arr) => {
picture.containingGallery = `${gallery.title}`;
picture.baseUrl = `${gallery.url}`;
i ? (picture.previousImage = arr[i - 1].filename) : null;
i + 1 != arr.length ? (picture.nextImage = arr[i + 1].filename) : null;
galleryImages.push(picture);
});
});
return galleryImages;
});
// Transforms
eleventyConfig.addTransform("prettier", function (content, outputPath) {
if (outputPath && outputPath.endsWith(".html")) {
return prettier.format(content, {parser: "html", bracketSameLine: true, vueIndentScriptAndStyle: true, singleAttributePerLine: true, htmlWhitespaceSensitivity: "ignore"});
return prettier.format(content, {
parser: "html",
bracketSameLine: true,
vueIndentScriptAndStyle: true,
singleAttributePerLine: true,
htmlWhitespaceSensitivity: "css",
});
} else {
return content;
}
@ -37,59 +65,54 @@ export default async function(eleventyConfig) {
eleventyConfig.addWatchTarget("content/**/*.{svg,webp,png,jpeg}");
// Official plugins
/*
eleventyConfig.addPlugin(eleventyImageTransformPlugin, {
extensions: "html",
formats: ["webp"],
widths: [270,540,810,1080],
defaultAttributes: {
loading: "lazy",
decoding: "async",
},
urlPath: "/img/",
});*/
eleventyConfig.addPlugin(pluginRss);
eleventyConfig.addPlugin(pluginSyntaxHighlight, {
preAttributes: { tabindex: 0 }
preAttributes: { tabindex: 0 },
});
eleventyConfig.addPlugin(pluginNavigation);
eleventyConfig.addPlugin(EleventyHtmlBasePlugin);
eleventyConfig.addPlugin(pluginBundle);
// Filters
eleventyConfig.addFilter("readableDate", (dateObj, format, zone) => {
// Formatting tokens for Luxon: https://moment.github.io/luxon/#/formatting?id=table-of-tokens
return DateTime.fromJSDate(dateObj, { zone: zone || "utc" }).toFormat(format || "dd LLLL yyyy");
eleventyConfig.addFilter("niceDate", (date) => {
var day = new Date(date).getUTCDate();
var monthIndex = new Date(date).getUTCMonth();
var year = new Date(date).getUTCFullYear();
return `${day}${dateSuffixAdder(day)} of ${monthMap[monthIndex]}, ${year}`;
});
eleventyConfig.addFilter('htmlDateString', (dateObj) => {
eleventyConfig.addFilter("htmlDateString", (dateObj) => {
// dateObj input: https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-date-string
return DateTime.fromJSDate(dateObj, { zone: 'utc' }).toFormat('yyyy-LL-dd');
return DateTime.fromJSDate(dateObj, { zone: "utc" }).toFormat("yyyy-LL-dd");
});
eleventyConfig.addFilter("removeMostRecent", arr => {
return arr.slice(0, arr.length-1);
eleventyConfig.addFilter("removeMostRecent", (arr) => {
return arr.slice(0, arr.length - 1);
});
// Shortcodes
// Cowsay
eleventyConfig.addNunjucksFilter("cowsay", cowText => {
eleventyConfig.addFilter("cowsay", (cowText) => {
const cowCaptionReplacementTable = [
[`
[
`
o ^__^
o (oo)\\_______
(__)\\ )\\/\\
||----w |
|| ||`, ''],
[/\(\s+/g, ''],
[/\s+\(/g, ''],
[/_{3,}/g, ''],
[/-{3,}/g, ''],
[/\s\)/g, ''],
[/\n/g, ''],
[/\s{2,}/g, ' '],
[/^ /, '']
|| ||`,
"",
],
[/\(\s+/g, ""],
[/\s+\(/g, ""],
[/_{3,}/g, ""],
[/-{3,}/g, ""],
[/\s\)/g, ""],
[/\n/g, ""],
[/\s{2,}/g, " "],
[/^ /, ""],
];
return `
@ -104,10 +127,8 @@ export default async function(eleventyConfig) {
});
// Embed a toot
eleventyConfig.addAsyncShortcode("toot", async function(instance, ID) {
const tootData = await fetch(
`https://${instance}/api/v1/statuses/${ID}`
);
eleventyConfig.addAsyncShortcode("toot", async function (instance, ID) {
const tootData = await fetch(`https://${instance}/api/v1/statuses/${ID}`);
const toot = await tootData.json();
@ -126,19 +147,29 @@ export default async function(eleventyConfig) {
publish_date="${dateTime}"
sharp_corner="">
</wc-toot>
`
`;
});
// Embed audio
eleventyConfig.addShortcode(
"audio",
function (title, artist, media_url, cover_url) {
return `
<wc-card>
<wc-mplayer
title="${title}"
artist="${artist}"
media_url="${media_url}"
cover_url="${cover_url}"
/>
</wc-card>
`;
},
);
// Passthrough
eleventyConfig.addPassthroughCopy({ 'public/xsl/*': "/xsl/" });
eleventyConfig.addPassthroughCopy({ 'public/img/*': "/img/" });
eleventyConfig.addPassthroughCopy({ 'public/robots.txt': "/" });
eleventyConfig.addPassthroughCopy({ 'public/js/*': "/js/" });
eleventyConfig.addPassthroughCopy({ 'public/js/webComponents/*': "/js/webComponents" });
eleventyConfig.addPassthroughCopy({ 'public/js/modules/*': "/js/modules" });
// Copying so that basic.xsl can use it
eleventyConfig.addPassthroughCopy({ 'public/css/index.css': "/css/index.css" });
eleventyConfig.addPassthroughCopy({ 'public/css/webfonts/*': "/css/webfonts/" });
eleventyConfig.addPassthroughCopy({ "./public/": "/" });
// Get the first `n` elements of a collection.
eleventyConfig.addFilter("head", (array, n) => {
@ -158,62 +189,60 @@ export default async function(eleventyConfig) {
});
// Return all the tags used in a collection
eleventyConfig.addFilter("getAllTags", collection => {
eleventyConfig.addFilter("getAllTags", (collection) => {
let tagSet = new Set();
for (let item of collection) {
(item.data.tags || []).forEach(tag => tagSet.add(tag));
(item.data.tags || []).forEach((tag) => tagSet.add(tag));
}
return Array.from(tagSet);
});
eleventyConfig.addFilter("filterTagList", function filterTagList(tags) {
return (tags || []).filter(tag => ["all", "nav", "post", "posts"].indexOf(tag) === -1);
return (tags || []).filter(
(tag) =>
["all", "nav", "post", "posts", "gallery", "quiz"].indexOf(tag) === -1,
);
});
// Customize Markdown library settings:
let markdownItOptions = {
html: true,
typographer: true
typographer: true,
};
let mdLib = markdownIt(markdownItOptions);
eleventyConfig.amendLibrary("md", mdLib => {
eleventyConfig.amendLibrary("md", (mdLib) => {
mdLib
.use(markdownItAnchor, {
permalink: markdownItAnchor.permalink.ariaHidden({
placement: "after",
class: "header-anchor",
symbol: "#",
ariaHidden: false
}),
level: [1, 2, 3, 4],
slugify: eleventyConfig.getFilter("slugify")
})
.use(markdownItFootnote)
.use(mdfigcaption, figoptions);
.use(markdownItAnchor, {
permalink: markdownItAnchor.permalink.ariaHidden({
placement: "after",
class: "header-anchor",
symbol: "#",
ariaHidden: false,
}),
level: [1, 2, 3, 4],
slugify: eleventyConfig.getFilter("slugify"),
})
.use(markdownItFootnote)
.use(mdfigcaption, figoptions);
});
eleventyConfig.setLibrary("md", mdLib);
return {
templateFormats: [
"md",
"njk",
"html",
"liquid",
],
templateFormats: ["md", "njk", "html", "liquid"],
markdownTemplateEngine: "njk",
htmlTemplateEngine: "njk",
dir: {
input: "content", // default: "."
includes: "../_includes", // default: "_includes"
data: "../_data", // default: "_data"
output: "_site"
input: "content", // default: "."
includes: "../_includes", // default: "_includes"
data: "../_data", // default: "_data"
output: "_site",
},
pathPrefix: "/",
};
};
}

View File

@ -1,24 +0,0 @@
[build]
publish = "_site"
command = "npm run build"
[[plugins]]
# Opt-in to the Netlify Lighthouse plugin (choose one):
# 1. Go to your site on https://app.netlify.com and navigate to the Integrations tab, search for the `Lighthouse` plugin
# 2. Or via `npm install -D @netlify/plugin-lighthouse`
# Read more: https://github.com/netlify/netlify-plugin-lighthouse
package = "@netlify/plugin-lighthouse"
# optional, fails build when a category is below a threshold
[plugins.inputs.thresholds]
performance = 1.0
accessibility = 1.0
best-practices = 1.0
seo = 1.0
[plugins.inputs]
output_path = "reports/lighthouse/index.html"

BIN
public/audio/ballin.mp3 Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,10 @@
.links-container {
grid-column: 1 / span 12;
padding: 0 var(--space-3xl);
.socialLinks {
max-width: calc(var(--space-3xl) * 3);
margin: auto;
}
}
.socialLinks a button {

View File

@ -1,16 +1,19 @@
@font-face {
font-display: swap;
font-family: Manrope;
font-style: normal;
font-weight: 200 900;
src: url(/css/webfonts/Manrope[wght].woff2) format("woff2");
}
@font-face {
font-display: swap;
font-family: Fraunces;
font-style: normal;
font-weight: 100 900;
src: url(/css/webfonts/Fraunces[SOFT,WONK,opsz,wght].woff2) format("woff2");
}
@font-face {
font-display: swap;
font-family: Fraunces;
font-style: italic;
font-weight: 100 900;

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

@ -0,0 +1 @@
<svg fill="none" height="160" viewBox="0 0 160 160" width="160" xmlns="http://www.w3.org/2000/svg"><g fill="#fff"><path d="m80 0c4.1505 0 8.2271.31607 12.2072.925452l-1.1444 7.413248c-3.6069-.55226-7.3014-.8387-11.0628-.8387-3.7612 0-7.4555.28641-11.0623.83862l-1.1444-7.413245c3.9799-.609332 8.0564-.925375 12.2067-.925375z"/><path d="m98.9849 2.26619-1.7798 7.28755c7.3099 1.77896 14.1849 4.66606 20.4389 8.47306l3.895-6.411c-6.901-4.20091-14.488-7.38658-22.5541-9.34961z"/><path d="m127.279 15.4591-4.432 6.0507c5.977 4.3861 11.257 9.6664 15.643 15.6437l6.051-4.4324c-4.84-6.5957-10.666-12.4222-17.262-17.262z"/><path d="m148.384 38.4618-6.411 3.8942c3.807 6.2541 6.694 13.1299 8.473 20.4395l7.288-1.7798c-1.963-8.0657-5.149-15.6528-9.35-22.5539z"/><path d="m159.075 67.7934-7.414 1.1444c.553 3.6067.839 7.301.839 11.0622 0 3.7614-.286 7.4559-.839 11.0628l7.414 1.1444c.609-3.9801.925-8.0567.925-12.2072 0-4.1503-.316-8.2267-.925-12.2066z"/><path d="m141.973 117.645c3.807-6.255 6.694-13.13 8.473-20.44l7.288 1.7798c-1.963 8.0662-5.149 15.6532-9.35 22.5542z"/><path d="m138.49 122.847 6.051 4.432c-4.84 6.596-10.666 12.422-17.262 17.262l-4.433-6.051c5.978-4.386 11.258-9.666 15.644-15.643z"/><path d="m117.644 141.973 3.894 6.411c-6.901 4.201-14.488 7.387-22.5537 9.35l-1.7798-7.288c7.3095-1.779 14.1855-4.666 20.4395-8.473z"/><path d="m91.0622 151.661 1.1445 7.414c-3.9799.609-8.0564.925-12.2067.925-4.1505 0-8.2272-.316-12.2073-.925l1.1442-7.413c3.6054.552 7.2997.838 11.0631.838 3.7612 0 7.4555-.286 11.0622-.839z"/><path d="m62.7945 150.448-1.7794 7.286c-6.0589-1.475-11.8477-3.639-17.2785-6.406l-7.5927 1.772-1.7042-7.304 10.2604-2.394 2.4408 1.243c4.9187 2.506 10.1623 4.467 15.6536 5.803z"/><path d="m28.1097 147.273 1.7042 7.304-13.0145 3.036c-8.66079 2.021-16.433718-5.752-14.41286-14.412l3.03673-13.015 7.30383 1.704-3.03675 13.015c-.75782 3.248 2.15705 6.162 5.40485 5.405z"/><path d="m14.2041 125.56-7.30383-1.704 1.77163-7.593c-2.76664-5.431-4.93123-11.22-6.40585-17.2787l7.28586-1.7794c1.33599 5.4911 3.29709 10.7351 5.80279 15.6541l1.2435 2.441z"/><path d="m8.33759 91.0624-7.412228 1.1442c-.609324-3.9799-.925362-8.0563-.925362-12.2066 0-4.1505.316067-8.2271.925446-12.2072l7.413244 1.1444c-.55225 3.607-.83869 7.3014-.83869 11.0628 0 3.7631.28613 7.4572.83759 11.0624z"/><path d="m9.55373 62.795-7.28755-1.7798c1.96302-8.0657 5.1487-15.6528 9.34962-22.5539l6.411 3.8942c-3.807 6.2541-6.6941 13.1299-8.47307 20.4395z"/><path d="m21.5098 37.1531-6.0507-4.4324c4.8398-6.5957 10.6663-12.4221 17.262-17.2619l4.4324 6.0507c-5.9773 4.3861-11.2576 9.6663-15.6437 15.6436z"/><path d="m42.356 18.0266-3.8943-6.4111c6.9011-4.20082 14.4882-7.38645 22.554-9.34944l1.7798 7.28755c-7.3096 1.77899-14.1854 4.66589-20.4395 8.47299z"/><path d="m145 80c0 35.899-29.101 65-65 65-11.3866 0-22.0893-2.928-31.3965-8.072-.8961-.495-1.9417-.658-2.9389-.426l-28.9134 6.747 6.7465-28.914c.2326-.997.0692-2.043-.426-2.939-5.1439-9.307-8.0717-20.0095-8.0717-31.396 0-35.8985 29.1015-65 65-65 35.899 0 65 29.1015 65 65z"/></g></svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

1591
public/img/Tux.svg Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 71 KiB

BIN
public/img/black_metal.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Some files were not shown because too many files have changed in this diff Show More