Welcome to Hugo TUI. Type /help for commands, or /blog to browse posts.
Recent posts:
Hugo is one of the most popular open-source static site generators. With its amazing speed and flexibility, Hugo makes building websites fun again. Unlike traditional CMS platforms like WordPress, Hugo generates pure HTML files that can be served from anywhere — a CDN, a simple web server, or even opened directly from your file system.
The key advantage of Hugo is its build speed. With Hugo, you get instant feedback as you develop. Building thousands of pages takes only a fraction of a second, and that speed never diminishes regardless of the size of your site.
Getting started with Hugo is straightforward. On macOS, you can use Homebrew:
brew install hugo
On Windows, the easiest way is through Chocolatey:
choco install hugo-extended
For Linux, download the binary from the official GitHub releases page and add it to your PATH.
Once Hugo is installed, creating a new site is as simple as running:
hugo new site my-blog
cd my-blog
git init
This creates a clean directory structure with all the folders you need. Hugo uses a convention-based approach — content goes in content/, layouts in layouts/, and static assets in static/.
Hugo uses Markdown for content authoring. Create a new file in the content/posts/ directory:
hugo new posts/my-first-post.md
This generates a file with front matter — a YAML block at the top that contains metadata about the post. You can set the title, date, tags, and other custom fields there.
To preview your site locally:
hugo server -D
The -D flag includes draft posts. Hugo starts a development server with live reload — changes to your content or templates are reflected instantly in the browser.
To build for production:
hugo --minify
The output goes to the public/ directory, ready to deploy anywhere.
Hugo has a rich ecosystem of themes. You can browse them at themes.gohugo.io. Installing a theme is usually just a git submodule away:
git submodule add https://github.com/theme-author/theme-name.git themes/theme-name
Then set it in your hugo.toml:
theme = 'theme-name'
Hugo sites can be deployed to virtually any hosting platform. Popular options include GitHub Pages, Netlify, Vercel, Cloudflare Pages, and traditional web servers. The beauty of static sites is that there is no server-side runtime to maintain — just upload the files and you are done.
Hugo is an excellent choice for blogs, documentation sites, portfolios, and more. Its speed, flexibility, and large ecosystem make it a joy to work with. If you have been considering moving away from a heavy CMS, Hugo is well worth the investment.
There is something deeply satisfying about terminal interfaces. They are minimal, keyboard-driven, and free from the visual noise that plagues modern web design. I wanted to bring that experience to a blog — a place where you type commands to navigate, read, and explore content.
The result is a single-page application that looks and feels like a terminal emulator, built entirely with Hugo and vanilla JavaScript.
The core architecture is simple but effective. Hugo generates two things at build time:
<script type="application/json"> tag<template> elementsThis means the entire blog — metadata and full content — lives in a single HTML file. No API calls, no network requests, no loading spinners. Everything is available instantly.
The command bar at the bottom of the screen accepts slash commands:
/blog — list all posts with keyboard navigation/archive — posts grouped by year/tags — browse by tag/random — open a random post/about — read the about page/help — show all available commands/clear — return to the welcome screenEach command is registered in a central command registry, making it easy to add new ones.
One of the defining features of a TUI is keyboard-driven interaction. The implementation handles:
The key handler follows a priority chain: Ctrl shortcuts take precedence, then option list navigation, then article scrolling.
The terminal supports multiple color themes through CSS custom properties. Each theme defines a palette of colors — background, foreground, accent, muted, error, and success. Themes are stored in the Hugo configuration and applied at build time via a CSS variables stylesheet.
Users can switch themes at runtime, and the selection persists in localStorage. Available themes include Claude (warm orange on dark), Matrix (green on black), Gruvbox (retro warm), and Mono (pure grayscale).
The biggest challenge was handling Chinese text. Hugo’s built-in .Summary function uses word-boundary splitting, which breaks on CJK characters that have no spaces between words. The solution was to use plainify combined with truncate for a character-count-based summary instead.
Another tricky aspect was file:// compatibility. Hugo generates absolute paths starting with /, but when opening the HTML file directly from the filesystem, these paths break. A toRelative() utility strips the leading slash to make everything work without a server.
Since all content is embedded at build time, the initial page load is the only network request. The total size depends on the number and length of posts, but for a typical blog with 10-20 posts, the HTML file stays well under 500KB. Subsequent navigation is instant — no round trips, no rendering delays.
The keyboard handler is designed to be as responsive as possible. Event listeners are attached once at the document level, and the handler checks the current state to determine what action to take. This avoids the overhead of adding and removing listeners as views change.
Building a TUI in the browser taught me a lot about state management without frameworks, keyboard accessibility, and the power of Hugo’s build-time data embedding. It is a reminder that you do not always need React or Vue to build an interactive experience — sometimes vanilla JavaScript is all you need.
The project lives on as a template for future Hugo blogs. If you enjoy keyboard-driven interfaces and minimal design, give it a try.
Every 100 milliseconds of load time costs you conversions. Studies consistently show that users abandon sites that take more than a few seconds to load. Google uses page speed as a ranking factor, and Core Web Vitals now directly impact SEO.
Performance is not just a technical concern — it is a user experience imperative.
Google defines three core metrics that every site should optimize:
LCP measures when the largest content element becomes visible. The target is under 2.5 seconds. Common culprits for poor LCP include slow server response times, render-blocking resources, and large unoptimized images.
INP measures the latency of all interactions throughout the page lifecycle. The target is under 200 milliseconds. Long tasks on the main thread are the primary enemy of good INP.
CLS measures visual stability — how much the page layout shifts during loading. The target is under 0.1. Unexpected layout shifts are one of the most frustrating experiences for users.
JavaScript is the most expensive resource because it blocks rendering and parsing. Use code splitting to load only what is needed, tree-shake unused code, and defer non-critical scripts.
<script src="app.js" defer></script>
The defer attribute ensures the script does not block HTML parsing.
Images typically account for the largest portion of page weight. Use modern formats like WebP or AVIF, implement responsive images with srcset, and always specify width and height to prevent layout shifts.
<img
src="photo.webp"
width="800"
height="600"
loading="lazy"
alt="Description"
/>
Set appropriate cache headers for static assets. Use content hashes in filenames to enable long cache lifetimes while still busting cache when content changes.
Cache-Control: public, max-age=31536000, immutable
Aim for Time to First Byte (TTFB) under 200ms. Use a CDN, optimize database queries, and consider static generation where possible — which is exactly what Hugo does.
The best tool for measuring real-world performance is the Chrome User Experience Report (CrUX), which provides field data from actual users. For lab testing, use Lighthouse in Chrome DevTools or the Web Vitals extension.
Remember: lab data is useful for debugging, but field data tells you what your users actually experience.
A performance budget sets limits on metrics that affect user experience. For example:
Enforce these budgets in your CI pipeline to prevent regressions.
Web performance is a continuous practice, not a one-time fix. Measure regularly, optimize methodically, and always keep the user experience in mind. The fastest sites are the ones that respect their users’ time.
Go was created at Google in 2007 by Robert Griesemer, Rob Pike, and Ken Thompson. It was designed to address the challenges of building large-scale software systems — slow compilation times, complex dependency management, and the overhead of object-oriented patterns.
Go is simple by design. It has a small keyword set, a clean syntax, and a standard library that covers most common use cases. There is no inheritance, no generics (until recently), and no complex type hierarchies. This simplicity is a feature, not a limitation.
Go’s headline feature is its concurrency model. Goroutines are lightweight threads managed by the Go runtime, and channels provide a safe way to communicate between them:
func main() {
ch := make(chan string)
go func() {
ch <- fetchUser("alice")
}()
go func() {
ch <- fetchUser("bob")
}()
user1 := <-ch
user2 := <-ch
fmt.Println(user1, user2)
}
This model makes it straightforward to write concurrent programs without the complexity of traditional threading. Goroutines start with just a few kilobytes of stack, so you can run millions of them simultaneously.
Go’s approach to error handling is explicit — functions return error values that callers must check:
result, err := doSomething()
if err != nil {
return fmt.Errorf("something failed: %w", err)
}
This pattern is verbose compared to exceptions, but it makes error paths visible and forces developers to think about failure modes. After using Go for a while, many developers come to appreciate this explicitness.
Go ships with excellent tooling:
go build — compile with fast incremental buildsgo test — built-in testing framework with benchmarkinggo vet — static analysis for common mistakesgo fmt — automatic code formatting (no more style debates)go mod — dependency management built into the languageThe formatting tool is particularly notable — every Go codebase looks the same because gofmt enforces a single canonical style.
Go excels in several domains:
CLI tools — Fast startup, small binaries, and cross-compilation make Go ideal for command-line applications. Tools like docker, kubernetes, and terraform are all written in Go.
Web services — The standard library’s net/http package is production-ready, and frameworks like Gin and Echo add convenience without sacrificing performance.
Infrastructure — Docker, Kubernetes, Prometheus, and many other cloud-native tools are built in Go, making it the de facto language of cloud infrastructure.
Data pipelines — Go’s concurrency model and efficient memory usage make it well-suited for building data processing pipelines.
The official Go tour at tour.golang.org is the best starting point. It covers the language basics interactively in your browser. After that, the Go by Example website provides practical code snippets for common patterns.
The Go community is welcoming and active. The Gophers Slack, the Go Forum, and Reddit’s r/golang are all great places to ask questions and share knowledge.
Go is not the most expressive or elegant language, but it is one of the most practical. It makes it easy to write correct, maintainable, and performant software. If you are building infrastructure, services, or tools, Go deserves a place in your toolkit.
ASCII art predates the World Wide Web by decades. In the 1960s and 70s, when graphical displays were rare and expensive, creative programmers used the characters available on text terminals to draw pictures, diagrams, and even portraits.
The term “ASCII art” refers to any visual art created using the 95 printable characters defined by the ASCII standard. From simple emoticons to complex landscapes rendered in characters, the medium has always been about creating visual richness within severe constraints.
The basic idea is simple: each character occupies a fixed-width cell, and by choosing characters with different visual densities, you can create the illusion of shading and form.
For example:
░▒▓█▓▒░
These block characters range from light (░) to dark (█), allowing you to create gradients. Similarly, characters like ., :, ;, =, +, *, #, and @ provide increasing visual density.
While ASCII art might seem like a relic, it continues to find new applications:
Many command-line tools display ASCII art banners on startup. Tools like figlet and toilet can convert text into large decorative ASCII representations:
_ _ _ _
| | | | | | |
| |_| | ___| | | ___
| _ |/ _ \ | |/ _ \
| | | | __/ | | (_) |
\_| |_/\___|_|_|\___/
Developers frequently use ASCII diagrams in code comments to explain architecture, data flow, or algorithm behavior. These diagrams are version-control friendly and render perfectly in any text editor.
Tools like git log --graph use ASCII characters to visualize branch and merge history:
* Merge branch 'feature' into main
|\
| * Add new parser
| * Refactor tokenizer
* | Fix edge case in lexer
|/
* Initial commit
Some artists push the boundaries of what is possible with text characters, creating detailed illustrations that look like photographs when viewed from a distance or with squinted eyes.
The traditional approach involves manual placement of characters, but modern tools can convert images to ASCII automatically. Online converters and command-line tools like jp2a (for JPEG) and libcaca (for video) can generate ASCII representations of any visual media.
For programmatic generation, the process typically involves:
The character mapping is crucial — getting it right requires understanding how different characters appear at a given font size and weight.
There is a unique aesthetic quality to ASCII art that transcends its technical limitations. The constraint of a fixed character grid forces a kind of abstraction that can be surprisingly expressive. Each piece carries a retro charm that connects modern computing to its text-based roots.
In an age of high-resolution displays and rich media, ASCII art reminds us that creativity thrives under constraints. The characters are the same ones we use every day in code — but arranged differently, they become something entirely new.
Static sites are having a moment. After years of CMS-dominated web development, developers are rediscovering the benefits of pre-rendered HTML: blazing fast load times, minimal server requirements, excellent security, and simple deployment.
The key to modern static sites is the static site generator (SSG) — a tool that takes your content (usually Markdown) and templates, and produces a complete HTML website ready to deploy.
Hugo is written in Go and is renowned for its speed. Building a site with thousands of pages takes milliseconds. Hugo uses Go templates, which have a steeper learning curve but offer powerful data manipulation.
Strengths:
Weaknesses:
Jekyll is the original modern SSG, written in Ruby and GitHub Pages’ default generator. It has the largest community and the most plugins.
Strengths:
Weaknesses:
_config.yml can become unwieldyEleventy is a simpler, more flexible alternative written in JavaScript. It supports multiple template languages and has a gentle learning curve.
Strengths:
Weaknesses:
Astro is the newest contender, taking a different approach with its “island architecture.” It lets you use React, Vue, Svelte, and other frameworks on a per-component basis while shipping zero JavaScript by default.
Strengths:
Weaknesses:
The best SSG depends on your priorities:
For a typical blog with 100 posts:
| Generator | Build Time | Output Size | JS Bundle |
|---|---|---|---|
| Hugo | ~50ms | ~200KB | 0KB |
| Jekyll | ~3s | ~250KB | 0KB |
| Eleventy | ~1.5s | ~220KB | 0KB |
| Astro | ~2s | ~180KB | ~10KB |
These numbers vary by configuration and content, but the relative performance characteristics are consistent.
Every SSG has its place. Hugo is the performance champion, Jekyll has the ecosystem, Eleventy offers flexibility, and Astro brings modern component architecture to static sites. The best choice is the one that fits your team’s skills and project’s needs.
Markdown is a lightweight markup language created by John Gruber in 2004. Its goal is to allow people to write using plain text formatting that can be converted to structurally valid HTML. The syntax is designed to be readable as-is, without looking like it has been marked up with tags.
Today, Markdown is everywhere — GitHub readmes, documentation sites, note-taking apps, forums, and even email clients support it.
Use hash symbols for headings:
# Heading 1
## Heading 2
### Heading 3
*italic* or _italic_
**bold** or __bold__
***bold italic***
- Unordered item
- Another item
- Nested item
1. Ordered item
2. Another item
[Link text](https://example.com)

Inline code uses backticks: code
Code blocks use triple backticks with an optional language identifier:
function greet(name) {
return `Hello, ${name}!`;
}
> This is a blockquote.
> It can span multiple lines.
---
***
___
Most Markdown renderers support additional syntax beyond the basics.
| Name | Language | Year |
|----------|----------|------|
| Hugo | Go | 2013 |
| Jekyll | Ruby | 2008 |
| Eleventy | JS | 2018 |
- [x] Completed task
- [ ] Pending task
- [ ] Another pending task
This has a footnote[^1].
[^1]: Here is the footnote content.
Term
: Definition of the term
ATX-style headings (# Heading) are preferred over Setext-style (underlined) because they are more explicit and work better with outline-based editors.
While Markdown treats single newlines as spaces, keeping lines under 80 characters makes the raw text more readable and easier to review in version control.
Always use fenced code blocks (triple backticks) with a language identifier instead of indented code blocks. The language hint enables syntax highlighting in most renderers.
Pick either asterisks or underscores for emphasis and stick with it throughout your document. Asterisks are more common in practice.
Place blank lines before and after headings, lists, and code blocks. This improves readability of the raw text and prevents rendering issues in some parsers.
Markdown is the de facto standard for technical documentation. Tools like MkDocs, Docusaurus, and GitBook all use Markdown as their primary authoring format.
Every well-maintained project on GitHub starts with a Markdown README. A good README includes a project description, installation instructions, usage examples, and contributing guidelines.
Apps like Obsidian, Typora, and VS Code’s built-in preview make Markdown a powerful format for personal note-taking. The plain text format ensures your notes remain readable and searchable for years.
Some email clients and newsletter tools support Markdown, letting you write beautifully formatted emails without touching a WYSIWYG editor.
Markdown strikes the perfect balance between simplicity and capability. It is easy enough for a quick note yet powerful enough for a complete book. Mastering Markdown is a small investment that pays dividends across countless tools and platforms.
This is a terminal-style blog built with Hugo and vanilla JavaScript. No frameworks, no dependencies, no loading spinners.
Everything runs in a single HTML file — content and metadata are embedded at build time, and navigation happens through keyboard-driven commands.
Type /help to see all available commands, or use the toolbar buttons at the bottom of the screen.
Switch themes with /theme <name>. Available presets: claude, matrix, gruvbox, mono.
Built with Hugo. Theme inspired by Claude Code’s terminal interface.