Blog

  • Why NFTs Last Longer on Ethereum ERC-721

    godsfavoriteart QOLluTt 2mE unsplash scaled

    The world of NFTs changes really fast. One year, a certain blockchain or marketplace is the hot new thing. The next year, people move on and leave it behind.

    A good example is Rarible. For a while, it supported NFTs on Polygon. Then one day, it dropped support. This left many creators and collectors stuck with NFTs that felt forgotten.

    This shows one big problem: if you rely on other platforms to choose the blockchain for you, your work could lose support at any time.

    Blockchains Lose Hype

    Right now, Base is very popular. Lots of new projects are starting there. But being popular today doesn’t mean it will last forever.

    We saw this happen with Polygon. It had tons of projects and energy at first. But when its token price slowed down, platforms stopped caring.

    So even if a blockchain is strong on the technical side, it can still be ignored. That’s the risk of building on hype.

    Why Ethereum Is Different

    If you want your NFTs to last, the best choice is not the chain everyone is talking about this month. The best choice is Ethereum.

    Here’s why:

    • It is the most secure blockchain.
    • Almost every other chain connects or bridges to Ethereum.
    • It has the biggest group of collectors and the most active marketplace.
    • Ethereum NFTs have already proven they can last, starting all the way back in 2017.

    Why ERC-721 Matters

    Some creators use many blockchains or mix in different NFT types like ERC-1155. But this makes ownership more confusing.

    ERC-721 solves that. It’s simple. One token equals one NFT. Each NFT is unique and can be owned by only one person at a time.

    Collectors understand this right away, which helps your NFT hold its value over time.

    Play the Long Game

    Cheaper blockchains might save money or give you a short-term boost. But if you want your NFTs to have true staying power, whether it’s art, music, or collectibles, Ethereum and ERC-721 are the way to go.

    Every other choice comes with the risk of your work losing support later. Just like we saw with Rarible and Polygon.

    So if your goal is for your NFTs to outlive hype cycles, the answer is simple: build them on Ethereum, and stick with ERC-721.

  • How to Build a Gatsby-Style 3×4 Card Grid Blog Layout in Hugo

    graficon stuff NdpksRKVEnQ unsplash scaled

    Ever wanted your Hugo site’s blog list to look like those beautiful Gatsby blogs—displaying 12 cards per page in a three-column grid, each card showing a featured image, tags (as links), an excerpt, author, read time, publish date, and last modified date? That’s exactly what I set out to do—here’s my practical walkthrough with code, tips, and gotchas!


    1. Final Layout Goals

    Home page (index.html):

    • Three columns, four rows (12 cards/page)
    • Each card shows:
      • Featured image (from front matter)
      • Linked tags
      • Title
      • Meta info: author / publish date / last modified / read time
      • Excerpt
      • “Read more” link

    2. Modify index.html for Card Grid Layout

    Define a .blog-grid container for your grid, and loop over paginated blog posts.

    text{{ define "main" }}
    <div class="container" role="main">
      {{ $pages := where .Site.RegularPages "Draft" false }}
      {{ $paginator := .Paginate (sort $pages "Lastmod" "desc") 12 }}
      <div class="blog-grid">
        {{ range $page := $paginator.Pages }}
          <article class="blog-card">
            <!-- Featured image -->
            {{ with resources.Get (printf "images/%s" $page.Params.image) }}
              {{ with .Resize (printf "%dx%d webp" .Width .Height) }}
                <img src="{{ .RelPermalink }}" alt="{{ $page.Title }}" class="u-photo blog-card-image" style="width:100%;height:170px;object-fit:cover;">
              {{ end }}
            {{ end }}
    
            <!-- Tag links (see below for correct “/tags/” path!) -->
            {{ if $page.Params.tags }}
              <div class="blog-card-tags">
                {{ range $page.Params.tags }}
                  <a href="{{ (print "/tags/" (. | urlize) "/") | relLangURL }}" class="tag p-category">{{ . }}</a>
                {{ end }}
              </div>
            {{ end }}
    
            <!-- Title -->
            <h2 class="blog-card-title">
              <a href="{{ $page.Permalink }}">{{ $page.Title }}</a>
            </h2>
    
            <!-- Meta info (see section 4) -->
            <div class="blog-card-meta">
              {{ partial "post_meta.html" $page }}
            </div>
    
            <!-- Excerpt -->
            <div class="blog-card-excerpt">
              {{ if $page.Params.excerpt }}
                {{ $page.Params.excerpt | plainify | truncate 80 }}
              {{ else }}
                {{ $page.Summary | plainify | truncate 80 }}
              {{ end }}
            </div>
    
            <!-- Read more -->
            <a href="{{ $page.Permalink }}" class="blog-card-readmore">Read more &rarr;</a>
          </article>
        {{ end }}
      </div>
      <!-- ...pagination, profile box, etc, as needed -->
    </div>
    {{ end }}
    

    3. Responsive Grid CSS & Dark Mode

    Add this CSS (as a file or inline):

    css.blog-grid {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 2em;
    }
    @media (max-width: 900px) { .blog-grid { grid-template-columns: 1fr 1fr; } }
    @media (max-width: 600px) { .blog-grid { grid-template-columns: 1fr; } }
    .blog-card {
      background: #fff;
      box-shadow: 0 2px 8px rgba(0,0,0,.05);
      border-radius: 10px;
      padding: 1em;
      color: #222;
      display: flex;
      flex-direction: column;
    }
    .blog-card-image img { object-fit: cover; width: 100%; height: 170px; border-radius: 8px 8px 0 0; }
    .blog-card-tags a.tag { background: #f3f3f3; border-radius: 12px; font-size: 0.9em; margin-right: 0.4em; padding: 1px 0.8em; text-decoration: none; color: #555; }
    .blog-card-title { font-size: 1.22em; margin: 0.2em 0 0.12em 0; }
    .blog-card-excerpt { margin-bottom: auto; margin-top: 0.7em; }
    .blog-card-readmore { color: #ff8300; font-weight: bold; text-decoration: none; }
    /* Dark mode */
    @media (prefers-color-scheme: dark), body.night-mode {
      .blog-card { background: #1a1a1a; color: #f9f9f9; }
      .blog-card-title a { color: #ffa134; }
      .blog-card-tags a.tag { background: #292929; color: #ffa134; }
    }
    

    4. Displaying Publish Date, Last Modified, Author, and Read Time

    Centralize your meta display using a Hugo partial, e.g. post_meta.html:

    text<span class="post-meta">
      <!-- Publish date -->
      <time class="dt-published" datetime="{{ .Date.Format "2006-01-02T15:04:05Z07:00" }}">{{ .Date.Format "2006-01-02" }}</time>
      {{ $lastmodstr := .Lastmod.Format "2006-01-02" }}
      {{ $datestr := .Date.Format "2006-01-02" }}
      {{ if ne $datestr $lastmodstr }}
        &nbsp;| Last updated {{ $lastmodstr }}
      {{ end }}
      <!-- Reading time (auto, in minutes) -->
      &nbsp;|&nbsp;<i class="fas fa-clock"></i>&nbsp;{{ .ReadingTime }} min
      <!-- Author (from front matter or global config) -->
      {{ if .Params.author }}
        &nbsp;|&nbsp;<i class="fas fa-user"></i>&nbsp;<span class="p-author h-card">{{ .Params.author | safeHTML }}</span>
      {{ else }}
        &nbsp;|&nbsp;<i class="fas fa-user"></i>&nbsp;<span class="p-author h-card">{{ .Site.Params.author.name | safeHTML }}</span>
      {{ end }}
    </span>
    

    And in your card:

    text<div class="blog-card-meta">
      {{ partial "post_meta.html" $page }}
    </div>
    
    • Per-post author? Add author = "Your Name" to the post’s front matter.
    • Site-wide author? Use [params.author] name = "Your Name" in config.toml.
    • Reading time: Hugo auto-calculates .ReadingTime as estimated minutes.

    5. Pro Tips

    • Works with Bootstrap themes; ignore default .row/.col- and use your own grid for full control.
    • Use Hugo’s resources.Get and .Resize for images—no change needed from your original.
    • Centralize meta rendering (post_meta.html) and call it from both list and single templates.
    • For dark mode, don’t hard-code white—add CSS overrides using prefers-color-scheme or a body class.
    • Internationalize labels/dates using Hugo i18n if needed.

    Example: front matter and config

    content/blog/my-post.md:

    texttitle = "My Hugo Gatsby-Style Cards Example"
    date = 2025-09-07T19:00:00+09:00
    lastmod = 2025-09-08T09:00:00+09:00
    tags = ["Japanese beat selling site", "AI music"]
    author = "Genx"
    excerpt = "How to build Gatsby-style card layouts in Hugo, step by step, including pitfalls and professional tweaks."
    image = "sample-thumb.jpg"
    

    config.toml:

    text[params.author]
    name = "Genx"
    

    Conclusion

    By customizing your Hugo index.html with a CSS Grid, improving card structure, using Hugo’s natural .ReadingTime and partial-powered meta display, and being careful with tag URLs, you can perfectly mimic those modern Gatsby/Next.js blog UIs—in Hugo, your way!

    These methods work for multilingual Hugo sites, are flexible with any base theme, and let you easily achieve that highly-polished card grid you see everywhere.

  • How to Get Started with the IndieWeb Webring on Hugo

    erry s nugroho HMhG9RgADN8 unsplash scaled

    Joining the IndieWeb Webring is a great way to connect your personal Hugo site to the broader IndieWeb community. Here’s how to get started:

    1. Visit the IndieWeb Webring

    2. Set Up Authentication: IndieAuth or RelMeAuth

    • The Webring site uses IndieAuth and/or RelMeAuth for sign-in. Since Hugo sites are static, you’ll generally use RelMeAuth.

    What is RelMeAuth?

    • RelMeAuth is an authentication method based on linking your personal website to established profiles (like GitHub or Mastodon) using rel=”me” links.
    • This lets you use your social profiles to authenticate as “you”, using your site’s identity.

    Steps for Setting Up RelMeAuth

    Add rel=”me” Links

    In your Hugo site’s layouts (usually in the head partial template), add links to your existing verified social profiles with rel=”me”. For example:

    <a href="https://github.com/yourusername" rel="me">GitHub</a> <a href="https://mastodon.social/@yourusername" rel="me">Mastodon</a>

    Make sure your social profiles link back to your website as well (for bidirectional verification).

    Sign In on the Webring Site

    Click the “Sign in” button at https://xn--sr8hvo.ws/.

    Enter your personal website URL. The service will look for your social rel=”me” links and use those to authenticate you through RelMeAuth.

    Complete the authentication process by authorizing through your social profile (usually GitHub or Mastodon).

    3. Add Webring Navigation Links to Hugo

    Once authenticated and added to the webring, you’ll be instructed (or allowed) to add navigation links to your website.

    Edit your Hugo footer partial ( commonly layouts/partials/footer.html ).

    Add the following HTML snippet for the navigation links:

    <a href="https://xn--sr8hvo.ws/previous">←</a> An <a href="https://xn--sr8hvo.ws">IndieWeb Webring</a> 🕸💍 <a href="https://xn--sr8hvo.ws/next">→</a>

    This enables seamless navigation to the previous and next sites in the ring.

    4. Double-check Your Site Links (Recommended)

    • Validate that your rel=”me” links are correctly formatted. You can use indielogin.com/setup or indiewebify.me to check for errors.
    • Ensure your social profiles link back to your website (bidirectional linking is required for verification).
    • If you use domain aliases or non-www/www inconsistencies, ensure your social profiles match your canonical website URL.

    5. All Set. You’re in the Webring!

    • After your site is approved, the webring links will automatically display the correct previous/next sites based on updates at xn--sr8hvo.ws.
    • From now on, when someone visits your site, they can use the webring links to discover other IndieWeb sites.

    Optional Enhancements

    • Consider customizing the placement or style of the webring links to match your site’s theme.
    • Document any IndieWeb or Webmention features you support—many IndieWebbers like sharing how their sites interact with others.

    That’s it.
    You’re now part of a decentralized community-powered webring, using web standards and your own web identity.

  • A Practical Guide to Properly Theming Hugo Glossary Sections (and Avoiding Template Duplication Hell)

    puzzle creative KL689xrb ds unsplash scaled

    If you want your Hugo-powered glossary (用語集) section to have its own navigation bar or layout while keeping your codebase lean, read on! Here’s what really matters, and the “aha!” moments you need to know.


    Step 1: Creating a Glossary Section

    Just put your glossary Markdown files under content/en/glossary/ and content/ja/glossary/.
    You don’t need anything extra for Hugo to treat them as a unique section.

    Directory example:

    content/
      en/
        glossary/
          apple.md
          bitcoin.md
      ja/
        glossary/
          apple.md
          bitcoin.md

    Step 2: Making a Separate Glossary Navigation Partial

    Want your glossary pages to have a custom menu? Just create:

    layouts/partials/glossary/nav.html

    Put your glossary-specific navigation HTML here.
    This can be a glossary term list, an index, or whatever special menu you want.


    Step 3: Using a Custom baseof.html for the Glossary

    Here’s a Hugo superpower: you can use a “base template” just for the glossary section (with its own nav, etc.) by making:

    layouts/glossary/baseof.html

    Example:

    <!DOCTYPE html>
    <html lang="{{ .Lang }}">
      <head>
        {{ partial "head.html" . }}
      </head>
      <body>
        {{ partial "glossary/nav.html" . }}
        {{ block "main" . }}{{ end }}
        {{ partial "footer.html" . }}
      </body>
    </html>
    

    This ensures every glossary page uses your specific glossary nav and layout!


    Step 4: No Need to Duplicate single.html

    At first, you might think you need to copy single.html into layouts/glossary/single.html to get the layout working.
    But you often don’t!
    As long as your glossary content files have the correct front matter, Hugo will use your layouts/glossary/baseof.html.

    Pro-tip: The main thing Hugo cares about is the “type” or the folder

    • If you leave type unset, Hugo uses the section (here, “glossary”) as the type.
    • So, all .md files under content/en/glossary with either:
      • No type at all
      • Or type = “glossary”
        will automatically use layouts/glossary/baseof.html.

    The Real Key: Check Your .md File Front Matter

    If your glossary .md files have

    type = "post"

    Hugo will never use your glossary layouts, even if you made layouts/glossary/baseof.html!

    Solution:
    For each .md file in your glossary folders:

    • Remove type (recommended for most)
    • Or set type = “glossary”

    That’s it! Once you do this, Hugo will apply your section-specific layouts and partials—no need to duplicate single.html or fight with conditionals.


    Example Directory Structure

    layouts/
      glossary/
        baseof.html         # Glossary exclusive base layout!
      partials/
        nav.html            # General nav
        glossary/
          nav.html          # Glossary-exclusive nav bar!
      _default/
        baseof.html         # Fallback for other sections
    

    Summary

    • Just putting Markdown files under content/en/glossary makes Hugo treat them separately—no extra config needed.
    • Create layouts/partials/glossary/nav.html and layouts/glossary/baseof.html for custom nav/layout.
    • No need to duplicate single.html!
    • Always check the front matter:
      Ensure glossary items do not have type = “post”. Use no type or type = “glossary”.

    Remember:
    Controlling Hugo’s template application is about content organization and front matter—not copying template files or writing complex conditionals!


    This workflow will keep your Hugo theme simple, DRY, and powerful.
    No more struggling with broken layouts or unnecessary template duplication for your custom sections. Happy Hugo theming! 🎉