Compare commits

..

6 Commits

Author SHA1 Message Date
82f47093a7 Settings refactor / add birb 2026-05-13 12:30:45 -05:00
e728ddac2c Content updates 2026-05-13 12:30:06 -05:00
0d40f6fb54 Content updates 2026-05-13 12:29:45 -05:00
93a3ae7bf0 Improve compatability with pocket bird extension 2026-04-27 10:08:26 -05:00
a45890d660 Fix margin on form input 2026-04-27 10:08:05 -05:00
58b04186ed content updates 2026-04-27 10:07:44 -05:00
33 changed files with 761 additions and 77 deletions

View File

@@ -350,7 +350,7 @@ export default {
name: "Incense, Fragrance, and Perfumery", name: "Incense, Fragrance, and Perfumery",
blogs: [ blogs: [
{ {
title: "Apothecary's Garden Blog", title: "Apothecarys Garden Blog",
feedUrl: "https://apothecarysgarden.com/blogs/blog.atom", feedUrl: "https://apothecarysgarden.com/blogs/blog.atom",
url: "https://apothecarysgarden.com/blogs/blog", url: "https://apothecarysgarden.com/blogs/blog",
description: description:

17
_includes/birb.njk Normal file
View File

@@ -0,0 +1,17 @@
<!-- Birb -->
<script>
const showBirb = () => {
script = document.createElement('script');
script.setAttribute("src", "https://cdn.jsdelivr.net/gh/IdreesInc/Pocket-Bird@main/dist/web/birb.embed.js");
document.body.appendChild(script);
};
const hideBirb = () => {
window.location.reload();
};
const noBirb = () => {
console.info("Settings: Not showing birb :[");
}
</script>
<!-- /Birb -->

View File

@@ -17,6 +17,6 @@
<a href="https://notbyai.fyi/"> <a href="https://notbyai.fyi/">
<img src="/img/written-by-human-not-by-ai-white.svg" alt="Written by humans, not by AI."> <img src="/img/written-by-human-not-by-ai-white.svg" alt="Written by humans, not by AI.">
</a> </a>
{% include "siteSettings.njk" %} {% include "settings/siteSettings.njk" %}
</div> </div>
</footer> </footer>

View File

@@ -52,6 +52,7 @@
<link rel="stylesheet" href="/pagefind/pagefind-ui.css"> <link rel="stylesheet" href="/pagefind/pagefind-ui.css">
<link rel="stylesheet" type="text/css" href="/css/search.css" /> <link rel="stylesheet" type="text/css" href="/css/search.css" />
{% endif %} {% endif %}
<script src="/js/main.js"></script>
<!-- Mochi webmentions --> <!-- Mochi webmentions -->
<link rel="webmention" href="https://mochi-webmentions.meadow.cafe/webmention/mochi@upchur.ch/1/receive" /> <link rel="webmention" href="https://mochi-webmentions.meadow.cafe/webmention/mochi@upchur.ch/1/receive" />
<!-- Indieweb profile links --> <!-- Indieweb profile links -->
@@ -85,8 +86,10 @@
</section> </section>
{% endif %} {% endif %}
</main> </main>
{% include "birb.njk" %}
{% include "footer.njk" %} {% include "footer.njk" %}
{% include "weather.njk" %} {% include "weather.njk" %}
{% include "wooMode.njk" %} {% include "wooMode.njk" %}
{% include "settings/settingsConfig.njk" %}
</body> </body>
</html> </html>

View File

@@ -4,7 +4,7 @@ layout: layouts/linksPage.njk
<div class="links-container h-card" data-pagefind-body> <div class="links-container h-card" data-pagefind-body>
<img class="profilePic u-photo" src="{{ metadata.author.profilePic }}"> <img class="profilePic u-photo" src="{{ metadata.author.profilePic }}">
<h1 class="socialTitle p-name">Nathan Upchurch</h1> <h1 class="socialTitle p-name">Nathan Upchurch</h1>
<p class="page-block nodropcap">Beside what I do to earn a crust, among other things, Im an incense maker and enthusiast, a classical trombonist, vegan cook, writer, mediocre photographer, and a fan of, advocate for, and occasional contributor to free and open source software. Heres where you can find me on the internet:</p> <p class="page-block nodropcap">Heres where you can find me on the internet:</p>
<div class="socialLinks"> <div class="socialLinks">
{% for link in metadata.socialLinks %} {% for link in metadata.socialLinks %}
<a class="link-button u-url" {% if link.customAttribute %} {{ link.customAttribute | safe }} {% endif %} href="{{ link.linkURL }}"> <a class="link-button u-url" {% if link.customAttribute %} {{ link.customAttribute | safe }} {% endif %} href="{{ link.linkURL }}">

View File

@@ -0,0 +1,4 @@
<form class="siteSettingsToggle" id="birbController">
<input type="checkbox" id="birbToggle" {% if metadata.weatherOnByDefault %}checked{% endif %} />
<label for="birbToggle">Pet bird (Will refresh page when turned off)</label>
</form>

View File

@@ -1,4 +1,4 @@
<form class="siteSettingsToggle" id="weatherController"> <form class="siteSettingsToggle" id="weatherController">
<input type="checkbox" id="weatherToggle" {% if metadata.weatherOnByDefault %}checked{% endif %} /> <input type="checkbox" id="weatherToggle" {% if metadata.weatherOnByDefault %}checked{% endif %} />
<label for="weatherToggle">Show weather?</label> <label for="weatherToggle">Weather</label>
</form> </form>

View File

@@ -1,4 +1,4 @@
<form class="siteSettingsToggle" id="wooModeController"> <form class="siteSettingsToggle" id="wooModeController">
<input type="checkbox" id="wooToggle" {% if metadata.wooModeOnByDefault %}checked{% endif %} /> <input type="checkbox" id="wooToggle" {% if metadata.wooModeOnByDefault %}checked{% endif %} />
<label for="wooToggle">Woo mode?</label> <label for="wooToggle">Woo mode</label>
</form> </form>

View File

@@ -0,0 +1,37 @@
<!-- Site Settings -->
<script>
const weatherSettings = {
handleOnToggle: turnOnWeather,
handleOnDefault: turnOnWeather,
handleOffToggle: turnOffWeather,
handleOffDefault: turnOffWeather,
settingToggle: "weatherToggle",
preferenceName: "weather",
defaultSetting: {{ metadata.weatherOnByDefault }},
forcedOn: false,
};
const wooModeSettings = {
handleOnToggle: deployWoo,
handleOnDefault: wooSensibleDefault,
handleOffToggle: withdrawWoo,
handleOffDefault: withdrawWoo,
settingToggle: "wooToggle",
preferenceName: "wooMode",
defaultSetting: {% if forcedWoo %}true{% else %}false{% endif %},
forcedOn: {% if forcedWoo %}true{% else %}false{% endif %},
};
const petBirbSettings = {
handleOnToggle: showBirb,
handleOnDefault: showBirb,
handleOffToggle: hideBirb,
handleOffDefault: noBirb,
settingToggle: "birbToggle",
preferenceName: "petBirb",
defaultSetting: false,
forcedOn: false,
};
settingHandler(weatherSettings);
settingHandler(wooModeSettings);
settingHandler(petBirbSettings);
</script>
<!-- /Site Settings -->

View File

@@ -2,8 +2,9 @@
<button onclick="siteSettings.showModal();">Site Settings</button> <button onclick="siteSettings.showModal();">Site Settings</button>
<dialog id="siteSettings"> <dialog id="siteSettings">
<h2>Site Settings</h2> <h2>Site Settings</h2>
{% include "weatherController.njk" %} {% include "settings/controllers/birbController.njk" %}
{% include "wooModeController.njk" %} {% include "settings/controllers/weatherController.njk" %}
{% include "settings/controllers/wooModeController.njk" %}
<button id="settingsDone" onclick="siteSettings.close();">Done</button> <button id="settingsDone" onclick="siteSettings.close();">Done</button>
</dialog> </dialog>
</div> </div>

View File

@@ -1,7 +1,7 @@
<!-- weather --> <!-- weather -->
<!-- Based on https://codepen.io/codeconvey/pen/xRzQay --> <!-- Based on https://codepen.io/codeconvey/pen/xRzQay -->
{# This include causes a symbol (text, emoji, et cetera; from metadata.weatherSymbol) to fall from the top of the viewport like snow. #} {# This include causes a symbol (text, emoji, et cetera; from metadata.weatherSymbol) to fall from the top of the viewport like snow. #}
<div class="fallingObjects" id="weather" aria-hidden="true"> <div class="fallingObjects hidden" id="weather" aria-hidden="true">
<div class="fallingObject"> <div class="fallingObject">
<div>{{ metadata.weatherSymbol }}</div> <div>{{ metadata.weatherSymbol }}</div>
</div> </div>
@@ -35,28 +35,14 @@
</div> </div>
<script> <script>
const weather = document.getElementById("weather"); const turnOnWeather = (containerId) => {
const weatherToggle = document.getElementById("weatherToggle"); const container = document.getElementById(containerId);
const weatherPreference = localStorage.getItem("weather");
// Initial weather preference check on page load
if ({% if metadata.weatherOnByDefault == false %}!weatherPreference || {% endif %}weatherPreference == 0) {
weather.classList.add("hidden");
weatherToggle.checked = false;
} else {
weather.classList.remove("hidden"); weather.classList.remove("hidden");
weatherToggle.checked = true; }
};
// Handle weather setting toggle const turnOffWeather = (containerId) => {
weatherToggle.addEventListener('change', function() { const container = document.getElementById(containerId);
if (this.checked) {
localStorage.setItem("weather", 1);
weather.classList.remove("hidden");
} else {
localStorage.setItem("weather", 0);
weather.classList.add("hidden"); weather.classList.add("hidden");
}; }
});
</script> </script>
<!-- /weather --> <!-- /weather -->

View File

@@ -2,7 +2,7 @@
<!-- Based on https://codepen.io/tommyho/pen/JjgoZLK --> <!-- Based on https://codepen.io/tommyho/pen/JjgoZLK -->
{# This include replaces the page background with a crazy rainbow animated shader #} {# This include replaces the page background with a crazy rainbow animated shader #}
<canvas id="shaderCanvas"></canvas> <canvas class="hidden" id="shaderCanvas"></canvas>
<script src="/js/three.min.js"></script> <script src="/js/three.min.js"></script>
<script> <script>
let scene, camera, renderer, uniforms, material, mesh; let scene, camera, renderer, uniforms, material, mesh;
@@ -171,30 +171,11 @@
uniforms.time.value = timestamp * 0.001; uniforms.time.value = timestamp * 0.001;
renderer.render(scene, camera); renderer.render(scene, camera);
} }
</script>
<script>
const wooCanvas = document.getElementById("shaderCanvas"); const wooCanvas = document.getElementById("shaderCanvas");
const wooToggle = document.getElementById("wooToggle");
const wooPreference = localStorage.getItem("wooMode");
let forcedWoo = false;
// Initial preference check on page load
if ({% if metadata.wooModeOnByDefault == false %}!wooPreference || {% endif %}wooPreference == 0) {
forcedWoo ? null : wooCanvas.classList.add("hidden");
wooToggle.checked = false;
} else {
wooCanvas.classList.remove("hidden");
wooToggle.checked = true;
initWoo();
animate(0);
};
// Handle setting toggle
wooToggle.addEventListener('change', function() {
if (this.checked) {
localStorage.setItem("wooMode", 1);
// Function for when wooMode is toggled on
const deployWoo = () => {
let wooAudio = new Audio("/audio/30995__unclesigmund__woo-2.mp3"); let wooAudio = new Audio("/audio/30995__unclesigmund__woo-2.mp3");
wooAudio.volume = 0.4; wooAudio.volume = 0.4;
wooAudio.play(); wooAudio.play();
@@ -202,21 +183,19 @@
wooCanvas.classList.remove("hidden"); wooCanvas.classList.remove("hidden");
initWoo(); initWoo();
animate(0); animate(0);
} else { }
localStorage.setItem("wooMode", 0);
forcedWoo ? null : wooCanvas.classList.add("hidden");
};
});
{% if forcedWoo %} // Function for when wooMode is enabled by default
// Handle forced woo const wooSensibleDefault = () => {
forcedWoo = true;
console.log("Forcing woo mode: woo!");
wooCanvas.classList.remove("hidden"); wooCanvas.classList.remove("hidden");
initWoo(); initWoo();
animate(0); animate(0);
{% endif %} }
// Function for when wooMode is toggled off
const withdrawWoo = () => {
wooCanvas.classList.add("hidden");
}
</script> </script>
<!-- /weather --> <!-- /Woo Mode -->

View File

@@ -10,6 +10,9 @@ imageAlt: "What appears to be a pack of cigarettes labeled 11:11. There is also
synopsis: "Taking a look at Boy Vienna's viral cigarette incense sticks." synopsis: "Taking a look at Boy Vienna's viral cigarette incense sticks."
mastodon_id: "114462578542598320" mastodon_id: "114462578542598320"
--- ---
::: info
Update: Boy Vienna's 11:11 sticks have since also been reviewed on [rauchfahne.de](https://blog.rauchfahne.de/en/2025/11/29/boy-vienna-1111-en/).
:::
[Boy Vienna](https://boyvienna.com/) is a brand from fashion designer and multi-media artist [Afaf Fi Seyam](https://www.instagram.com/zeopatra) that has been receiving attention on [TikTok](https://www.tiktok.com/@boyvienna/video/7366977382508514603) and [Instagram](https://www.instagram.com/zeopatra/reel/DAyIy2Lv0RQ/) for its incense cigarettes. As opposed to the tobacco variety, these "cigarettes" are designed to be lit and allowed to burn like an incense-stick; they are not to be inhaled. I knew I was going to have to try these sticks the minute they found their way onto my screen—it would seem that [everyone else felt the same way](https://www.instagram.com/zeopatra/p/DJHP0a3NnlI/), as when I made my way to the web store most of Boy Vienna's incense varieties were sold out. For 35 {{ "USD" | abbr("United States Dollars") | safe }}, I was able to snag a box of the 11:11 variety, listed as containing a blend of sage, lavender, and rosemary. [Boy Vienna](https://boyvienna.com/) is a brand from fashion designer and multi-media artist [Afaf Fi Seyam](https://www.instagram.com/zeopatra) that has been receiving attention on [TikTok](https://www.tiktok.com/@boyvienna/video/7366977382508514603) and [Instagram](https://www.instagram.com/zeopatra/reel/DAyIy2Lv0RQ/) for its incense cigarettes. As opposed to the tobacco variety, these "cigarettes" are designed to be lit and allowed to burn like an incense-stick; they are not to be inhaled. I knew I was going to have to try these sticks the minute they found their way onto my screen—it would seem that [everyone else felt the same way](https://www.instagram.com/zeopatra/p/DJHP0a3NnlI/), as when I made my way to the web store most of Boy Vienna's incense varieties were sold out. For 35 {{ "USD" | abbr("United States Dollars") | safe }}, I was able to snag a box of the 11:11 variety, listed as containing a blend of sage, lavender, and rosemary.
[![What appears to be a pack of cigarettes labeled 11:11. There is also a card featuring the brand name Boy Vienna and a temporary tattoo featuring an image of a lipstick-print and the brand name.](/img/boy_vienna_11_11/boy_vienna_11_11_incense_cigarette_sticks_2.webp "The pack also came with a wee temporary tattoo. Fun!")](/img/boy_vienna_11_11/boy_vienna_11_11_incense_cigarette_sticks_2.webp) [![What appears to be a pack of cigarettes labeled 11:11. There is also a card featuring the brand name Boy Vienna and a temporary tattoo featuring an image of a lipstick-print and the brand name.](/img/boy_vienna_11_11/boy_vienna_11_11_incense_cigarette_sticks_2.webp "The pack also came with a wee temporary tattoo. Fun!")](/img/boy_vienna_11_11/boy_vienna_11_11_incense_cigarette_sticks_2.webp)

View File

@@ -0,0 +1,133 @@
---
title: "Incense Review: Hippy Hug, Lavender Française, and White Sage Mage by The World Makes Scents"
description: "Reviewing Hippy Hug, Lavender Française, and White Sage Mage from The World Makes Scents"
date: 2026-04-26
tags:
- Incense
- Incense Review
synopsis: "Reviewing Hippy Hug, Lavender Française, and White Sage Mage from The World Makes Scents."
imageURL: /img/TWMS2026/the-world-makes-scents-incense.webp
imageAlt: "A closeup of The World Makes Scents' new incense packaging with a few loose cones."
mastodon_id: "116474428801255815"
---
In the interest of transparency: as readers may recall, I
[paid Dave a visit](/blog/visiting-chicago-incense-maker-dave-of-the-world-makes-scents/)
at the company's workshop in 2024. Since then, I've been back several times and
we remain friends, trading ingredients, incense, and knowledge. I also received
this incense for free. Despite this, as always, I will do my best to be
objective.
[![A closeup of The World Makes Scents' new incense packaging with a few loose cones.](/img/TWMS2026/the-world-makes-scents-incense.webp "The new packaging is fun, don't you think?")](/img/TWMS2026/the-world-makes-scents-incense.webp)
## Hippy Hug Sticks
First of all I'd like to point out that TWMS has updated their packaging. It's
vibrant, colorful, and fun. The illustration on the *Hippy Hug* packaging is,
however, clearly AI generated, which [I have some feelings about](ai/), but the
overall effect is playful and creative, which I find refreshing.
The 12 thick sticks are wrapped in colorful paper inside TWMS' trademark
jewelry box—an improvement on the synthetic batting material which would
sometimes cling to the sticks. I'm struck right away, as I was with each
variety in today's selection, by the strength of fragrance from the unlit
incense. With *Hippy Hug*, I get a lovely hit of clove and patchouli. The sticks
are about 4mm in diameter, and dark brown, with a rather coarse texture.
They're also solid, with little give and no crumbling or breakage in the
package.
On lighting smoky, patchouli, and sweet vanillic notes emerge. Clove follows as
the initial burst of smoke recedes into a surprisingly gentle stream from the
large stick. If you're familiar with sweet patchoui fragrances, such as
*Patchouli* from Shoyeido's *Overtones* collection, *Hippy* *Hug* doesn't quite
match this profile. While the sweetness is clear, this stick somehow leans dry,
leaving room for the clove to mingle with what I assume is a wood binder
(binders no longer appear to be listed on the ingredients) to make a
spicy/smoky effect.
The patchouli seems to have been used judiciously: just enough to make the
composition work. There is undoubtedly a 'campfire' aspect to this stick,
but it comes across as more woodsmoke than that riproaring, herbaceous
burning-vegetation note that you get when you overdose anything leafy. In
addition to patchouli, sandalwood, benzoin, and clove, the ingredients also
note the inclusion of frankincense. When I look for it, I think I may be able
to identify something of a resin-note in the fragrance, but it's certainly not
jumping out at me. The sandalwood is also a background player here.
I'd really been looking forward to trying this latest take on patchouli from
TWMS since I learned that the team was revising and upgrading some of their old
single-note formulas. I wasn't disappointed. As perhaps reflected by the name
change, while still a patchouli fragrance, the new iteration has evolved from a
single-note stick into an honest-to-god composition, and I'm here for it.
## Lavender Française
The fragrance of the unlit cones is lovely; a juicy lavender note with a hint
of Australian sandalwood. This is a markedly less complex fragrance than *Hippy
Hug,* but what it lacks in complexity is makes up for in clarity. It's
impressively lavender-forward while somehow avoiding much of the harshness that can
come from lavender flowers. A pleasant benzoin sweetness underscores the floral
note. I don't notice much of a sandalwood fragrance in the burn.
Like any wood-based cone, you won't want to sit right next to this incense, but
then again you don't need to. Even in my large office, with relatively little
airflow, the fragrance traverses the distance from the incense table to the
computer desk with little trouble. Giving this cone some room to breathe nets a
relatively clean, room-filling fragrance. There does seem to be a wood binder
note that somewhat muddies the waters, but it's not terribly obtrusive.
The fragrance naturally becomes a little rough around the edges as the diameter
increases near the base of the cone, and the formerly modest smoke production
ramps up quite seriously. That said, the formula seems to handle the change in
diameter well. As the ember travels down the cone, the lavender begins to
exchange its juicy, fruity character for a more herbal, camphoraceous scent.
The fragrance also becomes more smoky, as is to be expected. In contrast to
some of the cheap wood-and-synthetic-fragrance based cones I've tried, the
effect here is more that of an evolving fragrance than a devolving one. I think
I'd still prefer a stick, but I'd be lying if I said that I didn't enjoy this
experience.
## White Sage Mage
The fragrance of the unlit cones is a pleasant sage note. I don't get any
sandalwood this time for whatever reason. The fragrance immediately after
lighting is sage forward, herbaceous, and a touch smoky, although significantly
less so than burning a sage bundle. I never could understand why people insist
on burning sage bundles for fragrance. The result of such a large amount of
herbs burning at once is, for me, overwhelmingly rough and unpleasant. I much
prefer this format: carefully processed sage included in a combustible incense
as part of a well considered formula. It's cleaner, and as sage happens to be a
very potent herb, it still offers more than enough of a sage fragrance. In
fact, like *Lavender Française*, the star botanical almost entirely comprises
the fragrance here.
The inclusion of a little lavender in these cones is a nice addition—the floral
note lifts the fragrance from poultry-seasoning territory (always a risk with
sage). The ingredients also note the inclusion of frankincense, but I couldn't
pick it out; I suspect it may have been included to regulate the burn
temperature somewhat. Again, the fragrance has no trouble filling the room.
This cone is also subject to the pitfalls of the format, but it handles them
fairly well.
## Conclusion
After experiencing this selection, I remain impressed at the quality of
fragrance that The World Makes Scents is able to produce with carefully
processed whole botanicals. As one of the very few incense brands on the market
that you can be sure uses no synthetics or concentrates, it remains my go-to
recommendation for people seeking an entirely natural combustible incense in
the U.S.A.
While the brand's cones are, in my opinion, some of the better examples of the
format, I still do recommend that people nab a
[censer](https://shoyeido.com/products/incense-holder-bowl), some
[ash](https://shoyeido.com/products/accessory-miyakohai-ash), and buy sticks
where possible.[^1]
[^1]: Unfortunately, when I made my order almost all of the sticks
were out of stock on the [website](https://theworldmakesscents.com/), and I am
trying to wean myself off of Amazon
[for](https://en.wikipedia.org/wiki/Criticism_of_Amazon)
[ethical](https://www.ethicalconsumer.org/retailers/ten-reasons-avoid-amazon)
[reasons](https://socialjusticebooks.org/about/why-boycott-amazon/).

View File

@@ -0,0 +1,42 @@
---
title: "Revisiting Sweet Agarwood, and a Bonus Quiz"
description: "Another attempt at making a sweet-agarwood style incense stick using agarwood skins."
date: 2026-04-26
tags:
- Incense
- Incense Making
- Incense Builds (Recipes)
synopsis: "Another attempt at making a sweet-agarwood style incense stick using agarwood skins."
imageURL: /img/incense-recipe-an-attempt-at-a-sweet-agarwood-incense-stick/agarwood-skins.webp
imageAlt: "Small flat slivers, or skins, of agarwood showing darker resinated wood streaked with white unresinated wood."
mastodon_id: "116474435778369320"
---
My [last attempt](/blog/incense-recipe-an-attempt-at-a-sweet-agarwood-incense-stick/#fn2) at a sweet agarwood stick was okay but, as I noted, there was room for improvement. My goals with the original build were to create a decent amount of agarwood fragrance, while mitigating the harsh note that comes with cheaper wood. Following my notes from the old build, my new objectives are to increase the amount of agarwood fragrance, reduce sweetness, and add complexity.
### The Build
|Ingredient |Grams|% of Build|
|------------------------|-----|----------|
|Agarwood |3 |24.90% |
|Benzoin Siam |0.4 |3.32% |
|Borneol Camphor |0.7 |5.81% |
|Cassia |1.0 |8.30% |
|Clove |1.2 |9.96% |
|Guar Gum |0.35 |2.90% |
|Musk Root |0.4 |3.32% |
|Santalum album |4.0 |33.20% |
|Santalum spicatum |1.0 |8.30% |
First of all, I included S. album *and* S. spicatum this time. I was curious to try Indian sandalwood in this version, but I also wanted to use at least a little of my superfine Australian sandalwood powder because of how it helps to make a smooth, easily extruded dough.
### Results
Rather than extruding sticks right away, I decided to burn the powder as an incense-seal to trial it. Once again, the incense is very sweet. Adding a heaping helping of S. album surely didn't help this, but I think it may be time to consider forgoing the benzoin altogether. I'm not sure I like musk root with benzoin either.
The spices are there but, as everything is muddied by the excessive sweetness, it's hard to form an opinion on the spice levels. That said, this attempt is definitely missing something. I think I may include anise in a future iteration.
I like the level of camphor; the coolness is close to something like Yamadamatsu's *Suifu*, although I will have to wait and see how I like it without the benzoin. One thing I do miss from *Suifu* is that rich, sort of dried-fruit note. My guess is that this comes from using a better quality agarwood.
I am happier with the quantity of agarwood this time. There is still a harshness to the agarwood fragrance when the incense is burning nearby, but with a little distance everything mellows out significantly. The agarwood is pretty distinctly sour, which I'm not the biggest fan of, but I don't think there's much I can do about that as it seems to be a characteristic of the wood I'm using. So although I'm not a great fan of this particular wood in combustible incense, it's showing up and doing what it's supposed to, and I'm just going to have to be content with that.
## Bonus: take the incense ingredient quiz!
After building [the quiz feature](/quizzes/) something like a year ago, I have finally gotten around to making another quiz! This time, it's a test of your whole-botanical incense ingredient knowledge. So if you think you know your lavender from your labdanum, why not test your mettle and [give it a shot](/quizzes/incense-ingredient-quiz/)?

View File

@@ -6,7 +6,18 @@ h1: Changelog
includeTOC: true includeTOC: true
--- ---
## 2026 ## 2026
### May
* 2026-05-12
* Implement pet bird in settings.
* Refactor settings implementation. As a result:
* Weather now no longer active by default for users with JavaScript disabled.
* Settings check-boxes are disabled when the site has a hard setting default which ignores user preferences (such as in the case of the [Woo-Woo Incense Description Generator](/special/woo-woo-incense-description-generator/) page, which should always have woo-mode enabled).
* 2026-05-03
* Updated [/incense](/incense).
### April ### April
* 2026-04-27
* Improved the appearance of the site settings modal and backdrop, including a nice fade-in effect.
* 2026-04-26 * 2026-04-26
* Updated [/incense](/incense). * Updated [/incense](/incense).
* Updated weather to cherry blossoms for spring. * Updated weather to cherry blossoms for spring.

View File

@@ -104,6 +104,7 @@ Incense making is hard. While parts of the world with strong incense cultures en
* [Tame the Spirit Herbs (USA)](https://tamethespiritherbs.com/)—Herbs, Resins, Woods * [Tame the Spirit Herbs (USA)](https://tamethespiritherbs.com/)—Herbs, Resins, Woods
* [The Incense Dragon (USA)](https://www.theincensedragon.com/supplies)—Herbs, Resins, Woods * [The Incense Dragon (USA)](https://www.theincensedragon.com/supplies)—Herbs, Resins, Woods
* [The World Makes Scents (USA)](https://theworldmakesscents.com/)—Herbs, Resins, Woods * [The World Makes Scents (USA)](https://theworldmakesscents.com/)—Herbs, Resins, Woods
* [Youherbit (Greece)](https://www.youherbit.com/)—Herbs, Resins, Woods
## Studies on Incense and Related Topics ## Studies on Incense and Related Topics

View File

@@ -0,0 +1,7 @@
---
title: Suzaku
manufacturer: Gyokushodo
date: 2026-04-27 10:18:00
time: 10:18 AM
---

View File

@@ -0,0 +1,7 @@
---
title: "Kin-Kaku (Golden Pavilion)"
manufacturer: Shoyeido
date: 2026-04-29 09:37:00
time: 9:37 AM
---
It took me a while to warm up to these sticks. No idea why—they're lovely.

View File

@@ -0,0 +1,7 @@
---
title: Butterfly Spring Incense
manufacturer: Lijiali
date: 2026-04-29 11:11:00
time: 11:11 AM
---

View File

@@ -0,0 +1,7 @@
---
title: "Moss Garden (Nokiba)"
manufacturer: Shoyeido
date: 2026-05-01 13:18:00
time: 1:18 PM
---

View File

@@ -0,0 +1,7 @@
---
title: Boswellia Carterii
manufacturer: Scents of Earth
date: 2026-05-01 19:57:00
time: 7:57 PM
---
Lovely notes of cold cantaloupe and honey.

View File

@@ -0,0 +1,7 @@
---
title: Sarasoju
manufacturer: Shunkohdo
date: 2026-05-04 10:00:00
time: 10:00 AM
---
Killer daily sandalwood stick.

View File

@@ -0,0 +1,7 @@
---
title: Suzaku
manufacturer: Gyokushodo
date: 2026-05-05 9:11:00
time: 9:11 AM
---

View File

@@ -0,0 +1,7 @@
---
title: Menthamericana
manufacturer: Xinú
date: 2026-05-05 11:44:00
time: 11:44 PM
---

View File

@@ -0,0 +1,7 @@
---
title: Frankincense Oman
manufacturer: Tennendo
date: 2026-05-09 14:52:00
time: 2:52 PM
---
Only three sticks left! :[

View File

@@ -0,0 +1,7 @@
---
title: "Excellentia (Shira-giku)"
manufacturer: Shoyeido
date: 2026-05-11 9:51:00
time: 9:51 AM
---
Some days you just find yourself in the mood for nine hours of continuous fragrance.

View File

@@ -0,0 +1,300 @@
---
title: "Incense Ingredient Quiz"
description: "How well do you know your incense ingredients?"
date: 2026-04-26
imageURL: "/img/quizzes/incense/incense-ingredient-quiz.webp"
imageAlt: "A very serene photo of a burning cone of incense."
consequences:
- title: "What happened buddy?"
points: 0
spiel: "Damn, this didnt go so well, did it? Im sure with some time and effort youll do better!"
image: "/img/quizzes/incense/results/incense-quiz-0.gif"
imageAlt: "An animated GIF of Homer Simpson being hit by a thurible. The caption reads: Perfumed by some unseen censer, Doh! Stupid censer."
- title: "Youve got a lot to learn!"
points: 20
spiel: "You got a handful right, but its time to hit the books!"
image: "/img/quizzes/incense/results/incense-quiz-20.gif"
imageAlt: "An animated GIF of Spongebob Squarepants reading a checklist of Mermaid Man and Barnacle Boy merchandise items as the camera pans across a room containing them. The items are: thermometer, ukulele, throw pillow, screensaver, incense, snail cozy, headgear."
- title: "Not too bad."
points: 40
spiel: "Youve got a way to go, but there's no doubt you know a thing or two about incense!"
image: "/img/quizzes/incense/results/incense-quiz-40.gif"
imageAlt: "An animated GIF of a chunk of frankincense smoking on top of a charcoal disk."
- title: "Youve got a mind for incense!"
points: 60
spiel: "You got over half of the questions right. This is some obscure knowledge—I hope youre proud of yourself!"
image: "/img/quizzes/incense/results/incense-quiz-60.gif"
imageAlt: "An animated GIF of Principal Skinner dressed as one of the biblical three kings offering frankincense."
- title: "Youre good at this!"
points: 80
spiel: "You really know your incense ingredients! Well done!"
image: "/img/quizzes/incense/results/incense-quiz-80.gif"
imageAlt: "An animated GIF of a women with strings of jewels around her head blowing out the flame of a stick of incense."
- title: "Perfect score!"
points: 100
spiel: "Either you checked the source code, or you really know your stuff! Congratulations!"
image: "/img/quizzes/incense/results/incense-quiz-100.gif"
imageAlt: "An animated GIF of smoke rising from a stick of incense."
questions:
- title: "Which of these ingredients is associated with hippies?"
image:
imageAlt:
imageCaption:
answers:
- name: "Styrax tonkinensis"
points: 0
- name: "Pogostemon cablin"
points: 5
- name: "Cinnamomum camphora"
points: 0
- name: "Ferula moschata"
points: 0
- title: "This ingredient is known for its peachy fragrance."
image:
imageAlt:
imageCaption:
answers:
- name: "Osmanthus"
points: 5
- name: "Mastic"
points: 0
- name: "Acacia gum"
points: 0
- name: "Opoponax"
points: 0
- title: "Which of these is a type of frankincense?"
image:
imageAlt:
imageCaption:
answers:
- name: "Bursera fagaroides"
points: 0
- name: "Eriodictyon californicum"
points: 0
- name: "Commiphora wightii"
points: 0
- name: "Boswellia neglecta"
points: 5
- title: "Which is a type of myrrh?"
image:
imageAlt:
imageCaption:
answers:
- name: "Bursera fagaroides"
points: 0
- name: "Eriodictyon californicum"
points: 0
- name: "Commiphora wightii"
points: 5
- name: "Boswellia neglecta"
points: 0
- title: "Your incense sticks are having trouble burning. Which of these ingredients might you add to fix the problem?"
image:
imageAlt:
imageCaption:
answers:
- name: "Acacia gum"
points: 0
- name: "Charcoal"
points: 5
- name: "Clove"
points: 5
- name: "Myrrh"
points: 0
- title: "Your incense sticks are having trouble burning. Which of these ingredients is a likely culprit?"
image:
imageAlt:
imageCaption:
answers:
- name: "Myrrh"
points: 5
- name: "Cinnamon"
points: 0
- name: "Charcoal"
points: 0
- name: "Guar gum"
points: 5
- title: "Which of these food items is not commonly used in incense?"
image:
imageAlt:
imageCaption:
answers:
- name: "Plums"
points: 0
- name: "Wheat gluten"
points: 5
- name: "Corn starch"
points: 0
- name: "Pears"
points: 0
- title: "Which incense ingredient is not mentioned in the Song of Solomon?"
image:
imageAlt:
imageCaption:
answers:
- name: "Sandalwood"
points: 5
- name: "Cedar"
points: 0
- name: "Frankincense"
points: 0
- name: "Calamus"
points: 0
- title: "This ingredient comes from the island of Chios, Greece."
image:
imageAlt:
imageCaption:
answers:
- name: "Spikenard"
points: 0
- name: "Mastic"
points: 5
- name: "Benzoin"
points: 0
- name: "Osmanthus"
points: 0
- title: "This ingredient can sometimes be harvested by combing the beards of goats."
image:
imageAlt:
imageCaption:
answers:
- name: "Galbanum"
points: 0
- name: "Almond tree gum"
points: 0
- name: "Colophony resin"
points: 0
- name: "Labdanum"
points: 5
- title: "This ingredient is banned for use in food in the USA because of its high levels of coumarin."
image:
imageAlt:
imageCaption:
answers:
- name: "Tonka beans"
points: 5
- name: "Ambrette seeds"
points: 0
- name: "Guggul"
points: 0
- name: "Valerian"
points: 0
- title: "Which resin is typically the squishiest?"
image:
imageAlt:
imageCaption:
answers:
- name: "Guggul"
points: 0
- name: "Elemi"
points: 5
- name: "Dragons blood"
points: 0
- name: "Palo santo"
points: 0
- title: "This wood needs to lay dead for a few years before it develops its characteristic fragrance."
image:
imageAlt:
imageCaption:
answers:
- name: "Agarwood"
points: 0
- name: "Juniper"
points: 0
- name: "Sandalwood"
points: 0
- name: "Palo santo"
points: 5
- title: "This wood develops its fragrance when attacked by insects or fungus."
image:
imageAlt:
imageCaption:
answers:
- name: "Sandalwood"
points: 0
- name: "Cedar"
points: 0
- name: "Agarwood"
points: 5
- name: "Rosewood"
points: 0
- title: "Which of these gums is the weakest binder?"
image:
imageAlt:
imageCaption:
answers:
- name: "Guar"
points: 0
- name: "Acacia"
points: 5
- name: "Xanthan"
points: 0
- name: "Tragacanth"
points: 0
- title: "Which of these is not the name of a binder?"
image:
imageAlt:
imageCaption:
answers:
- name: "Laha"
points: 0
- name: "Jigat"
points: 0
- name: "Nanmu"
points: 0
- name: "Slippery pine"
points: 5
- title: "Which of these animal parts or secretions is not likely to be found in an incense formula?"
image:
imageAlt:
imageCaption:
answers:
- name: "Dung"
points: 0
- name: "Fur"
points: 5
- name: "Opercula"
points: 0
- name: "Bezoars"
points: 0
- title: "Which is not endangered?"
image:
imageAlt:
imageCaption:
answers:
- name: "Bursera graveolens"
points: 5
- name: "Nardostachys jatamansi"
points: 0
- name: "Aquilaria crassna"
points: 0
- name: "Bulnesia sarmientoi"
points: 0
- title: "This ingredient is associated with a cluster of love poems by Walt Whitman."
image:
imageAlt:
imageCaption:
answers:
- name: "Calamus"
points: 5
- name: "Camphor"
points: 0
- name: "Colophony"
points: 0
- name: "Costus"
points: 0
- title: "Which ingredient is not a root?"
image:
imageAlt:
imageCaption:
answers:
- name: "Rhubarb"
points: 0
- name: "Calamus"
points: 0
- name: "Sumbul"
points: 0
- name: "Styrax"
points: 5
---
Do you know your lavender from your labdanum? Test your knowledge on a range of whole-plant incense ingredients.

View File

@@ -0,0 +1,5 @@
---
date: 2026-04-28 10:15:00
emoji: 🌿
comment: Shoyeido's Overtones Patchouli is a banger. It really should come in a box of 450 5.25 inch sticks; I'd buy one in a heartbeat.
---

View File

@@ -42,6 +42,7 @@ h4.isso-thread-heading {
p.isso-input-wrapper { p.isso-input-wrapper {
display: block !important; display: block !important;
margin: 0 !important;
max-width: 100% !important; max-width: 100% !important;
& > label, & > label,
& > input { & > input {

View File

@@ -23,7 +23,8 @@
--color-gray-90: #333333; --color-gray-90: #333333;
--card-color: rgba(250, 250, 250, 1); --card-color: rgba(250, 250, 250, 1);
--contrast-color: #027860; --contrast-color: rgb(2, 120, 96);
--contrast-color-translucent: rgba(2, 120, 96, 0.5);
--background-color: #faf5f5; --background-color: #faf5f5;
--rss-orange: rgb(255, 152, 0); --rss-orange: rgb(255, 152, 0);
--text-color: var(--color-gray-90); --text-color: var(--color-gray-90);
@@ -98,7 +99,7 @@
--border-radius: 0.3rem; --border-radius: 0.3rem;
/* Transitions */ /* Transitions */
--transition-normal: all 0.3s; --transition-normal: all 0.3s allow-discrete;
/* Links */ /* Links */
--link-decoration-thickness: 0.06rem; --link-decoration-thickness: 0.06rem;
@@ -119,7 +120,8 @@
--color-gray-20: #253848; --color-gray-20: #253848;
--color-gray-90: #dad8d8; --color-gray-90: #dad8d8;
--card-color: #333333; --card-color: #333333;
--contrast-color: #04c49e; --contrast-color: rgb(4, 196, 158);
--contrast-color-translucent: rgba(4, 196, 158, 0.5);
/* --text-color is assigned to --color-gray-_ above */ /* --text-color is assigned to --color-gray-_ above */
--text-color-link: var(--text-color); --text-color-link: var(--text-color);
@@ -576,6 +578,31 @@ sup {
} }
/* Site Settings */ /* Site Settings */
#siteSettings {
border: 1.5px solid var(--color-gray-20);
border-radius: var(--border-radius);
background-color: var(--card-color);
transition: var(--transition-normal);
&::backdrop {
backdrop-filter: blur(3px);
background-color: var(--contrast-color-translucent);
transition: var(--transition-normal);
}
&[open] {
opacity: 1;
transition: var(--transition-normal);
@starting-style {
opacity: 0;
}
}
&[open]::backdrop {
opacity: 1;
@starting-style {
opacity: 0;
}
}
} /* TODO: figure out why exit animation doesn't work */
#siteSettingsContainer { #siteSettingsContainer {
& button:not(#settingsDone) { & button:not(#settingsDone) {
margin-top: 0; margin-top: 0;
@@ -666,5 +693,5 @@ h2 + .header-anchor {
grid-template-columns: repeat(var(--grid-columns), 1fr); grid-template-columns: repeat(var(--grid-columns), 1fr);
} }
.hidden { .hidden {
display: none; display: none !important;
} }

View File

@@ -1,7 +1,7 @@
body { body {
background: none; background: none;
} }
canvas { canvas#shaderCanvas {
display: block; display: block;
opacity: 0.35; opacity: 0.35;
pointer-events: none; pointer-events: none;

64
public/js/main.js Normal file
View File

@@ -0,0 +1,64 @@
/*
* Function to handle settings toggles and the effects they control
* handleOnToggle: Function to be called if user turns the setting on
* handleOnDefault: Function to be called if the setting is on by default
* handleOffToggle: Function to be called if user turns the setting off
* handleOffDefault: Function to be called if the setting is off by default
* settingToggle: String - ID of the user-facing toggle element to control the effect
* preferenceName: String - Name to be used to record the user's setting preference in local storage'
* defaultSetting: Boolean
* forcedOn: Boolean - whether to ignore the user preference if defaultSetting = true
*/
const settingHandler = (settingsObject) => {
const toggle = document.getElementById(settingsObject.settingToggle);
const preference = localStorage.getItem(settingsObject.preferenceName);
// Report settings
console.info(
`
Settings: ${settingsObject.preferenceName}
----------
Default: ${settingsObject.defaultSetting}
Forced on: ${settingsObject.forcedOn}
User preference: ${preference}
`,
);
// User preference is positive
if (preference === "1") {
toggle.checked = true;
settingsObject.forcedOn ? (toggle.disabled = true) : null;
settingsObject.handleOnDefault();
} else if (settingsObject.defaultSetting && settingsObject.forcedOn) {
// Default on, user preference ignored
toggle.checked = true;
toggle.disabled = true;
settingsObject.handleOnDefault();
} else if (settingsObject.defaultSetting && !preference) {
// Default on, no user preference
toggle.checked = true;
settingsObject.forcedOn ? (toggle.disabled = true) : null;
settingsObject.handleOnDefault();
} else {
toggle.checked = false;
settingsObject.handleOffDefault();
}
// Handle setting toggle
toggle.addEventListener("change", function () {
if (this.checked) {
console.info(
`Settings: User turned on ${settingsObject.preferenceName}.`,
);
localStorage.setItem(settingsObject.preferenceName, 1);
settingsObject.handleOnToggle();
} else {
console.info(
`Settings: User turned off ${settingsObject.preferenceName}.`,
);
localStorage.setItem(settingsObject.preferenceName, 0);
settingsObject.handleOffToggle();
}
});
};