<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-CN">
  
  <title>ledge.log</title>
  <subtitle>终端动画、字符画和小工具的笔记。</subtitle>
  <link href="https://blog.beiwater.org/feed/feed.xml" rel="self" />
  <link href="https://blog.beiwater.org/" />
  <updated>2026-10-11T00:00:00Z</updated>
  <id>https://blog.beiwater.org/</id>
  <author>
    <name>beiwater</name>
  </author>
  <entry>
    <title>把狐狸搬进 ascii.rest</title>
    <link href="https://blog.beiwater.org/blog/fox-into-ascii-rest/" />
    <updated>2026-10-11T00:00:00Z</updated>
    <id>https://blog.beiwater.org/blog/fox-into-ascii-rest/</id>
    <content type="html">&lt;p&gt;fox-girl-loader 原本只在终端里播放。这次我把同一段动画做成 ascii.rest 的独立作品，提交为 PR #57。画布是 80×60，8 fps，循环 10 秒，用 8 档灰度，没有外部资源，运行时也不依赖原来的加载器。&lt;/p&gt;
&lt;p&gt;它放在 &lt;code&gt;scenes&lt;/code&gt; 分类里。文本分类最大是 80×32，而这套阴影要完整的 60 行才看得清，所以我借用了 scenes 的尺寸。&lt;/p&gt;
&lt;p&gt;审查里指出了一个问题：&lt;code&gt;cell: 1&lt;/code&gt; 走的是场景渲染器，它的 INK 表里没有部分象限字符，四分之一和四分之三填充都落到默认权重 0.5，层次就丢了。审查建议为这条路径补上象限字符的覆盖权重。&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>256×192 的灰度帧怎么变成字符</title>
    <link href="https://blog.beiwater.org/blog/gray-frames-to-glyphs/" />
    <updated>2026-10-09T00:00:00Z</updated>
    <id>https://blog.beiwater.org/blog/gray-frames-to-glyphs/</id>
    <content type="html">&lt;p&gt;源帧是 256×192 的灰度图。先按面积加权缩到字符网格，每个格子取重叠面积的平均值，边缘不会抖。细线条经过平均会发灰，所以缩放后把对比度拉高 1.45 倍，亮度 246 以上直接当作纸色。&lt;/p&gt;
&lt;p&gt;每个字符格再切成 2×2 个子像素。取四个子像素亮度的中点，高于中点的点亮，得到 0 到 15 的掩码，对应下面这 16 个象限字符。前景色取亮的那组均值，背景色取暗的那组。四个子像素差别小于 8 的格子视为平地，直接涂一个底色。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; ▘▝▀▖▌▞▛▗▚▐▜▄▙▟█
&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  <entry>
    <title>在 Ghostty 里用六分块</title>
    <link href="https://blog.beiwater.org/blog/sextants-in-ghostty/" />
    <updated>2026-10-06T00:00:00Z</updated>
    <id>https://blog.beiwater.org/blog/sextants-in-ghostty/</id>
    <content type="html">&lt;p&gt;象限字符一格只有 2×2 个点。六分块（sextant，U+1FB00 起）是 2×3，纵向多切一行，细节更多。fox-girl-loader 检测到 Ghostty、WezTerm 或 kitty 就换成六分块，因为这几个终端自己绘制这些字符，不依赖字体。其他终端仍然用象限字符。&lt;/p&gt;
&lt;p&gt;六分块一共有 64 种组合，其中空白、左半、右半和整块四种已经存在于别的 Unicode 区块，所以 U+1FB00 起只编码了其余 60 种。查表时要跳过这四个位置。&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>加载动画不该抢走你的输出</title>
    <link href="https://blog.beiwater.org/blog/loaders-should-not-eat-output/" />
    <updated>2026-10-03T00:00:00Z</updated>
    <id>https://blog.beiwater.org/blog/loaders-should-not-eat-output/</id>
    <content type="html">&lt;p&gt;动画占用整个终端，你的代码同时在后台运行。这段时间里写到 stdout 和 stderr 的内容会先扣下，动画结束后再原样显示。如果 stdout 不是终端，比如在 CI 或管道里，就什么也不画。&lt;/p&gt;
&lt;p&gt;正常离开 &lt;code&gt;with&lt;/code&gt; 块显示 ✓ Done，抛出异常显示 ✗ Failed，异常照常往外传。&lt;code&gt;run()&lt;/code&gt; 返回 &lt;code&gt;CompletedProcess&lt;/code&gt;，命令失败时会把输出打印出来，方便看原因。&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>7.4 MB 压成 1 MB</title>
    <link href="https://blog.beiwater.org/blog/7-4-mb-to-1-mb/" />
    <updated>2026-09-29T00:00:00Z</updated>
    <id>https://blog.beiwater.org/blog/7-4-mb-to-1-mb/</id>
    <content type="html">&lt;p&gt;150 帧、每帧 256×192 的灰度图，原始大小是 7,372,800 字节。先把灰阶对齐到 64 档，压缩率能再好一倍。Node 版用 Brotli 打成 &lt;code&gt;frames.br&lt;/code&gt;，约 1.0 MB。Python 版用 LZMA 压缩再转 base64，直接写进单个文件，所以两个包都没有运行时依赖。&lt;/p&gt;
&lt;p&gt;重建脚本是 &lt;code&gt;tools/build-frames.py&lt;/code&gt;，需要 ffmpeg 和 node，只在换动画时才用得上。&lt;/p&gt;
</content>
  </entry>
</feed>