About

This is the about page. Replace this content with information about yourself or your site.

Japanese Text Support

This site automatically detects Japanese text and marks it for screen readers. For example, this sentence contains 日本語 which gets wrapped in a lang="ja" attribute.

Mixed text works naturally: English and 日本語 can appear in the same paragraph without any special markup.

Ruby/Furigana

Use {kanji|reading} syntax for furigana: かん renders as ruby text.

Mixed ruby and plain CJK: ほんを勉強する

Single character: The word means “spirit” or “energy”.

Syntax:

{漢|かん}{字|じ}
{日|に}{本|ほん}{語|ご}を勉強する
The word {気|き} means "spirit".

Game Text

For in-game text that needs preserved spacing and special styling, use the .game class:

1337!!!?    おはよ  

Trailing space test (text ends with four fullwidth spaces):

トレーリングスペーステスト    

The underline should extend through the trailing spaces.

Syntax:

[1337!!!?    おはよ  ]{.game}
[トレーリングスペーステスト    ]{.game}

Widget Demos

Card Notice

Inserts an explanatory banner for posts that use card previews:

🖛 This post contains ✨on-hover card images✨, indicated by the hanafuda symbol, 🎴, like so: 🎴Thalia, Guardian of ThrabenThalia, Guardian of Thraben {1}{W} - Legendary Creature — Human Soldier - First strike Noncreature spells cost {1} more to cast. - 2/1 🖚

Alt text contains card data for screen readers.

Syntax:

::: cards
:::

Admonitions

Syntax:

::: note
Content here.
:::

::: warning
Content here.
:::

:::: {.tip title="Custom Title"}
Custom title requires attribute syntax with extra colons.
::::

Card Previews

Pokemon: 🎴CharizardCharizard - 120 HP - Fire - Energy Burn: As often as you like during your turn (before your attack), you may turn all Energy attached to Charizard into Fire Energy for the rest of the turn. This power can't be used if Charizard is Asleep, Confused, or Paralyzed. - Fire Spin [FireFireFireFire] 100: Discard 2 Energy cards attached to Charizard in order to use this attack. - Weakness: Water ×2 and 🎴MewtwoMewtwo - 60 HP - Psychic - Psychic [PsychicColorless] 10+: Does 10 damage plus 10 more damage for each Energy card attached to the Defending Pokémon. - Barrier [PsychicPsychic]: Discard 1 Psychic Energy card attached to Mewtwo in order to prevent all effects of attacks, including damage, done to Mewtwo during your opponent's next turn. - Weakness: Psychic ×2

Pokemon with set disambiguation: 🎴MewtwoMewtwo - 70 HP - Psychic - Energy Absorption [Psychic]: Choose up to 2 Energy cards from your discard pile and attach them to Mewtwo. - Psyburn [PsychicPsychicColorless] 40 - Weakness: Psychic ×2

Yu-Gi-Oh: 🎴Blue-Eyes White DragonBlue-Eyes White Dragon - Normal Monster (Dragon) [LIGHT] - Level 8 - ATK 3000 / DEF 2500 - This legendary dragon is a powerful engine of destruction. Virtually invincible, very few have faced this awesome creature and lived to tell the tale. and 🎴Dark MagicianDark Magician - Normal Monster (Spellcaster) [DARK] - Level 7 - ATK 2500 / DEF 2100 - ''The ultimate wizard in terms of attack and defense.''

MTG: 🎴Lightning AxeLightning Axe {R} - Instant - As an additional cost to cast this spell, discard a card or pay {5}. Lightning Axe deals 5 damage to target creature. and 🎴Arclight PhoenixArclight Phoenix {3}{R} - Creature — Phoenix - Flying, haste At the beginning of combat on your turn, if you've cast three or more instant and sorcery spells this turn, return this card from your graveyard to the battlefield. - 3/2

Name collision handling: Both Yu-Gi-Oh and MTG have a card called “Mountain”:

  • Default (last loaded): 🎴MountainMountain - Basic Land — Mountain - ({T}: Add {R}.)
  • Explicit Yu-Gi-Oh: 🎴MountainMountain - Spell Card (Field) - All Dragon, Winged Beast, and Thunder monsters on the field gain 200 ATK/DEF.
  • Explicit MTG: 🎴MountainMountain - Basic Land — Mountain - ({T}: Add {R}.)

Syntax:

[Charizard]{.card}
[Mewtwo]{.card set="basep"}          <!-- Pokemon set disambiguation -->
[Mountain]{.card}                    <!-- defaults to last-loaded franchise -->
[Mountain]{.card source="yugioh"}    <!-- Yu-Gi-Oh field spell -->
[Mountain]{.card source="mtg"}       <!-- MTG basic land -->

Greentext

implying this is actually green

Syntax:

[implying this is actually green]{.greentext}

Keyboard Keys

Press Ctrl+C to copy and Ctrl+V to paste.

Syntax:

Press <kbd>Ctrl</kbd>+<kbd>C</kbd> to copy

Blockquotes

This is a blockquote with decorative quotation marks. It should have large " marks positioned at the corners.

Syntax:

> This is a blockquote. Standard markdown.

Chat Bubbles

Alice
Alice Hey, have you seen the new site redesign?
Claude
Claude Yeah! The widget system is really clean now.
Alice
Alice The markdown syntax is so much simpler.

Syntax:

::: chat
@DisplayName[avatar-key]: Message text here.
@Alice[avatar-cool-user]: Hey!
@Claude[avatar-chatbot]: Hello!
:::

Forum Posts

This is what a forum post looks like. It has a sidebar with author information and a main content area.

The styling is inspired by old.reddit.com’s clean layout.

This is a reply! It’s indented and has a different border style to show the conversation threading.

Syntax:

::: {.forum-post name="Username" avatar="avatar-key" title="Title" posts="123"}
Post content here.
:::

::: {.forum-reply name="Replier" avatar="avatar-key" title="Title" posts="456"}
Reply content here.
:::

Heading Anchors

All headings on this page have a § symbol that appears on hover. Clicking the heading copies/links to its anchor. This is automatic for all headings.

Code Blocks

Syntax highlighting is handled by Pandoc at build time (no client-side JS). Line numbers always display.

-- | A simple example
main :: IO ()
main = do
  let greeting = "Hello, World!"
  putStrLn greeting
# Python example
def fibonacci(n: int) -> int:
    if n <= 1:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

Custom starting line number:

int main(void) {
    printf("Hello from line 42!\n");
    return 0;
}

Syntax:

```haskell
main :: IO ()
main = putStrLn "Hello"
```

```{.c startFrom="42"}
// Line numbers start at 42
int x = 1;
```

Widget Nesting

Widgets can be nested. Use more colons :::: for outer containers:

Syntax:

::::: note
Outer note content.

:::: warning
Inner warning.
::::

:::::

Build System

This site uses a multi-stage preprocessing pipeline before Hakyll generates the final HTML.

Font Subsetting

Fonts are subsetted to include only characters actually used in content:

  • Latin fonts (Cormorant Garamond): 627KB → ~80KB per weight
  • Japanese font (Toppan Bunkyu): 1.5MB → ~8KB
  • Emoji font (Blobmoji): 11MB → ~15KB (only used emoji)

The subsetter scans all markdown files, extracts unique characters per Unicode range, and generates minimal .woff2 files. Smart quotes and punctuation that Pandoc generates (like ’ → ’) are included automatically.

Card Cache

Card data (Pokemon, Yu-Gi-Oh, MTG) lives in config/*/ directories. Before building:

  1. card-cache.py scans content for [Name]{.card} references
  2. Builds a JSON index with alt text (card name, type, abilities, stats)
  3. Copies only referenced card images to static/images/cards/

This means 3000+ cards in config but only ~10 images ship if you reference 10 cards.

Emoji Font

The emoji font is built from scratch using nanoemoji:

  1. Scan content for emoji characters
  2. Build a COLR font containing only those glyphs
  3. Cache based on content hash (rebuilds only when emoji set changes)

Pandoc Transforms

Markdown → HTML conversion includes custom AST transforms:

  • Japanese: Wraps CJK text in lang="ja", expands {漢|かん} to <ruby>
  • Cards: Converts [Name]{.card} to hover-preview with cached alt text
  • Admonitions: Converts ::: note to styled callout boxes
  • Chat/Forum: Converts fenced divs to styled message layouts
  • Figures: Converts ![alt](img "caption") to <figure>/<figcaption>
  • Anchors: Adds clickable § links to all headings

All transforms run at build time. Zero client-side JavaScript.