📰 newsreader

hackernews score 1.07 好み 0.12 en

Fancy Curl Sites

curlansi escape codesterminalstatic site generatorgemroffnginxgophergemini
原文 ↗

日本語訳

# Fancy Curl Sites

Fancy Curl Sites

2026年3月18日(更新:2026年10月14日)

しばらく前に、ターミナルでの閲覧を目的とした、私のサイトの「おしゃれなcurl版」を追加しました。ぜひ、以下のコマンドを試してみてください!

`curl nytpu.com/gemlog/2026-03-18` (または `curl nytpu.com`)

(Windowsユーザーの方、ごめんなさい。cmd.exe で ANSI エスケープシーケンスがデフォルトで無効になっているのは私のせいではありません。また、PowerShell で `curl` の代わりに `curl.exe` を使わなければならないのも、PowerShell が不可解にも `curl` を `Invoke-WebRequest` にエイリアス設定しているせいであり、私のせいではありません。)

Fediverse で少し触れましたが、それ以外はあまり詳しく説明しませんでした。なぜなら、説明不要なものだと思ったからです。しかし、何人かの方から「どうやって作ったのか」と聞かれたので、実際に記事を書く価値があるかもしれないと思いました(……7ヶ月も遅れてしまいましたが)。

なお、このアイデアは trinkey 氏(curl trinkey.com )と strongsand 氏(curl proot.party )のcurlサイトから着想を得たもので、私が思いついたわけではありません。彼らとはかなり異なるアプローチを取りましたが、この素晴らしいアイデアの功績はすべて彼らにあります。(更新:残念ながら、2026年10月14日現在、彼らのcurl版はどちらも機能していません。)

まず、より興味深い部分である、クライアントに送信するためのANSIマークアップされたファイルを実際に生成する方法についてです。インデックスページとAboutページは、すべて私が手書きしました。

trinkey 氏や strongsand 氏は、ratatui ライブラリ(あるいはそれに類するもの)を使ってオンザフライで生成していると思いますが、そちらの方が便利でしょう。私にとっては、手書きする方が手っ取り早いと感じました。

私は、必要な時に簡単に貼り付けられるよう、主要なエスケープコードである `ESC[`(つまり `\x1b[`)を Vim のレジスタに一つ入れておき、特定のコードを参照するために Wikipedia のグラフィックスコードのページを開いておきました。ええ、それだけです。自分好みの統一感のあるスタイリングを決めるために試行錯誤し、マークアップされたcurl用ページを作成する際は、私のページの Gopher 版を参考にしました。

さて、私のバージョンの特筆すべき点は、1、2ページだけでなく、ブログの全ページにcurl版を用意していることです。これは、ある便利な偶然によるものです。4年以上前、ブログで使用している独自のマークアップ言語「Gemroff」に、ANSIマークアップされたプレーンテキストを出力する機能を実装していました。元々は、執筆中にターミナルで下書きを便利にプレビューするためだけのものでしたが、静的サイトジェネレーター(SSG)に組み込むのは非常に簡単だったので、すぐにcurl版を生成できるようになりました。

ブログ記事用のラッパーテンプレートと、記事一覧のインデックスページ用のテンプレートは手動で作成しましたが、それとSSGに数行追加するだけで、仕組みを構築できました。

これこそが、「簡単だとは言い切れない」理由です!

私にとって簡単だったのは、独自のマークアップ言語とSSGを使っており、かつ数年前に適切な設計を選択していたという幸運があったからです。例えば、私のSSGは、他のSSGのようにHTML専用ではなく、複数のモジュール化された出力形式をサポートしていました。というのも、私はサイトを HTTP、Gemini、Gopher の3つでホストしているからです。

とはいえ、単なる面白いギミックであり、数分間ブラウジングする以上の用途はまずないでしょうから、楽しむために数ページを手書きして提供するだけでも、このようなサイトを作る方法としては十分に受け入れられるものです。

最後に、最後のステップは、`curl` を含むユーザーエージェントに対して、実際にサイトのcurl版を提示することです。私の場合、これは Nginx の設定を数箇所変更するだけで済みましたし、他のサーバーでも同様に簡単だと思われます。私が求めた主な機能は、オーバーライドヘッダー(`X-Original: true`)を用意することでした。これにより、curlをカジュアルに実行している人が望むであろう、未加工のHTTPレスポンスも引き続き取得できるからです。また、すべてを静的に配信し続けたいとも考えました。

……これで、本当に終わりです! 最初はかなり自明なことだと思っていましたが、WebサーバーやANSIエスケープシーケンスの一般的な使い方とはかなり毛色が異なるため、なぜ皆さんが好奇心や困惑を抱いたのかは理解できます。こうした仕掛けを取り入れたサイトがもっと増えたら素敵ですね!

エムダッシュ(—)! AI生成か!

あ、いや、言わせてもらえば、私のマークアップ言語には2022年11月から明示的なエムダッシュのマークアップ要素が存在しています。そして、信じられないかもしれませんが、LLMは実際の著者が書いたものを(学習データとして)コピーしたものから学習しているのです。ですから、人間が書いた著作物ですでにエムダッシュが使われていなければ、LLMがエムダッシュを使うこともありません。それに、1つの段落に20個も括弧()を入れて、表現に変化をつけるためにエムダッシュを使いたいという私の欲求を、どうやって避けろと言うのですか? そんなことは考えられません! ↩︎

原文(英語)を表示

Fancy Curl Sites

March 18, 2026 (Updated: October 14, 2026)

So a good while ago I added a fun curl version

of my site, meant for viewing in the terminal. Try running these commands!

curl nytpu.com/gemlog/2026-03-18 # or curl nytpu.com

(sorry Windows users, not my fault that ANSI escape codes are disabled-by-default in cmd.exe

. And not my fault that in Powershell you have to use curl.exe

instead of curl

because Powershell inexplicably aliases that to Invoke-WebRequest

.)

I posted about it a bit on the Fediverse, but otherwise didn't elaborate much on it becuase I figured it was fairly self-explanatory. But I've had a handful of people ask me how I did it, so I decided it might actually be worth it to write a post about how I did it (…like seven months late).

I should note this idea came from trinkey's (curl trinkey.com

) and strongsand's (curl proot.party

) curl sites, I didn't come up with it myself. Even though I did go about it quite a bit differently from them, all credit for the very cool idea goes to them. (UPDATE: unfortunately neither of their curl versions are functional anymore as of 2026-10-14.)

First, since it's the more interesting part, actually generating the ANSI-marked-up files to send to the clients. I entirely hand-wrote the index page and about page.

Note that I believe trinkey and strongsand generate theirs on-the-fly with the ratatui library (or similar), which is probably more convenient; hand-writing it seemed more expedient to me though.

I had the main escape code—ESC[

, i.e. \x1b[

—1 in a Vim register to easily paste when needed, and then the Wikipedia page for the main graphics codes open to reference the specific escape codes. And, yeah, that's about it. I experimented to decide on consistent styling I liked, and just referenced the Gopher version of my pages when crafting the marked-up curl pages.

Now, the notable thing about my version is that I have curl versions of the entirety of my blog, rather than just one or two pages being available. This is entirely due to a convenient coincidence: over four years ago I implemented outputting ANSI-marked-up plaintext in my custom markup language I use for my blog, Gemroff. Originally it was just to allow convenient previewing of drafts in the terminal while writing; but it was trivial to plug into my static site generator to immediately get Curl versions generated.

I did manually write a wrapper template for blog posts, as well as a template for the index page listing posts, but that plus a few extra lines in my static site generator was all that was needed to wire it up.

This is the main thing that makes it hard to say it's easy!

since it was only easy for me because I use an entirely custom markup language and static site generator and I happened to make the right design choices years ago—e.g. my SSG also happened to already have support for multiple, modular output formats instead of solely HTML like other SSGs, since I tri-host my site on HTTP, Gemini, and Gopher.

However, offering nothing but a few hand-written pages for fun is a completely acceptable way to set up a site like this anyways, since it's just a neat gimmick and no one's likely to actually use it more than a few minutes of browsing.

Finally, the last step is actually presenting the Curl version of your site to any user agent containing curl

, which for me was just a few changes to my Nginx config, with other servers it'd presumably be equivalently simple. The main feature I wanted was an override header (X-Original: true

) so you could still get an unmodified HTTP response like someone casually running Curl likely wanted, and I wanted everything to be served statically still.

And… that's really it! As I said, when I first set it up it seemed fairly self-explanatory to me, but it is very non-orthogonal to what people normally do with either web servers or ANSI escape codes so I can see where people's curiosity/confusion came from. It would be neat to see more sites doing this trick around!

EMDASH! AI-GENERATED!

acksually I'll have you know that my markup language has had an explicit markup element for emdashes since November 2022. And believe it nor not: LLMs are trained on shit copied from actual authors, so LLMs wouldn't be using emdashes if they weren't already used in human-written works.And what, am I supposed to avoid having twenty parentheticals a paragraph, to where I feel the need to use emdashes to vary it up? Unthinkable! ↩︎

← 一覧に戻る