<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Sansui's blog</title>
        <link>https://sansui233.com</link>
        <description>记录学习和生活的个人博客</description>
        <lastBuildDate>Sun, 07 Jun 2026 17:31:04 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>zh-CN</language>
        <copyright>All rights reserved 2022, Sansui</copyright>
        <atom:link href="https://sansui233.com/rss" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[个人阅读 RSS 的最佳实践]]></title>
            <link>https://sansui233.com/posts/2026-06-02-personal-rss-reading-best-practice</link>
            <guid isPermaLink="false">https://sansui233.com/posts/2026-06-02-personal-rss-reading-best-practice</guid>
            <pubDate>Tue, 02 Jun 2026 12:50:00 GMT</pubDate>
            <description><![CDATA[省流：新标签页小组件]]></description>
            <content:encoded><![CDATA[<p>我有订阅 RSS 的习惯。在十年前，我觉得做 RSS 阅读的思路就是自定义杂志，放到一个 App 里读很自然。但是时间长了后，逐渐意识到问题所在。 RSS 不存在什么成瘾性，忙的时候很难想起来，忙之后闲下来时也想不起来。只有“啊我想看看大家都在写什么”的时候，才想得起来还可以看看 RSS。</p>
<p>最近换了 Vivaldi 浏览器，有一段时间了，突然我发现我再也没有漏过 RSS。原因是浏览器的新标签页组件。</p>
<p><img src="https://img-cf.sansui233.com/imgs/2026/06/202606031844401.webp" alt="Vivaldi 新标签页"></p>
<p>在打开新网站时，我一直使用 <code>ctrl +T</code> 新建标签页。在这之前，我有尝试过 Chrome 的订阅类插件。最开始使用的掘金插件，当时掘金初创不久，内容还不错。但实际使用发现，在我新建标签页时，是要准备切换工作了，这时掘金的订阅铺满了一整屏，就不会想阅读这么多的信息。即便换到了其他的插件，也依然存在着信息过载的问题。</p>
<p>后来我开始使用订阅服务，几经转换后使用的是 Innoreader。Innoreader 有 Chrome 插件，红点显示未读数。但是，我依然不会点，如果有红点强迫症，来一篇就点一篇很烦。如果没有红点强迫症，就更不会点了。</p>
<p>Innoreader 还会发邮件提醒什么文章没有读。但是打开邮箱时，通常也需要处理事件（指接收验证码）。我不会摸鱼摸到邮箱里去。</p>
<p><img src="https://img-cf.sansui233.com/imgs/2026/06/202606022054681.webp" alt="innoreader 邮件"></p>
<p>Vivaldi 新标签页组件就很好地解决了这个问题。首先，组件面积不大，信息量保持在人可接收的最佳范围（4篇）。至于为什么是4，参考 <a href="https://www.bilibili.com/video/BV12hz2Y1E3B">【毕导】你有一种连你自己都没意识到的超能力</a>。</p>
<p>其次，组件内默认点击是进入的原始网页，给人感觉是我去别人家的装修的房子里做客，还能看看评论。这也是因为我本来就在使用浏览器，并不会在 App 之间跳来跳去。相比于 all in one 的方便，在个人阅读的场景下，浏览器原始网页能给人更强的满足感。</p>
<p>这样一来，我新建标签页时，如果很忙就直接进行原本的事情，RSS 不会打扰到我。如果不忙，我就会看一眼大家都发了什么，有没有什么有兴趣看的内容。</p>
<p>我认为个人维持阅读 RSS 习惯便应该这样，以少量精简的消息，嵌入到日常一定会使用的软件里，同时不会贴脸打扰到人工作，也不会使用角标进行烦人的提醒。</p>
<p>这样的软件其实不多了，大部分的工作软件打开后全程工作区，很少有浏览器新标签页这样每天都会用的非工作区场景。而社媒平台的推荐给你绑得死死的。我之前还用过即刻的 RSS 机器人，完全符合刷社媒时顺便刷到自己的订阅，非常好用，但很快因为监管问题下架了。要么就是推特了。但是写博客的人，又不一定会发推特。不如说，除了阮一峰，我没有再找到每篇博客都发推特的个人博主了。</p>]]></content:encoded>
            <category domain="https://sansui233.com/categories/Diary">Diary</category>
        </item>
        <item>
            <title><![CDATA[每日见闻 - 说说]]></title>
            <link>https://sansui233.com/memos</link>
            <guid isPermaLink="false">https://sansui233.com/memos?id=2026-06-02T12:08:06.000Z</guid>
            <pubDate>Tue, 02 Jun 2026 12:08:06 GMT</pubDate>
            <content:encoded><![CDATA[<h2>2026-06-08 01:08:59</h2>
<p>看到<a href="https://superlxh02.github.io/rust-study/%E5%AF%B9%E4%BA%8Erust%E8%AF%AD%E8%A8%80%E7%9A%84%E6%80%BB%E7%BB%93%E5%92%8C%E6%80%9D%E8%80%83.html">一个学 Rust 的 C++ 程序员的思考</a>说，对于非 GC 语言的程序员，好像很少考虑一个变量的生命周期的问题。</p>
<p>现在我觉得确实如此，在 vibe ServerPing 这个应用时，前期没管这的那的，逻辑正确就行。但后面排查 CPU 占用就会开始考虑到这些情况。 CPU 占用基本在 Memory Allocation  和 GC 上，想到 CPU 几乎无占用，得考虑到所有对象的创建与销毁时期，有多少能复用。</p>
<p>实在是很难想象 vibe coding 时代一堆人不知道代码实际在做什么只看是否符合需求的软件质量……</p>
<hr/>
<h2>2026-06-06 11:48:43</h2>
<p>嗯，感觉现在博客架构方向是对的， 当手工配置的地方越多，构建性能就越好。最明显的感觉是 Next.js export 要画很多时间在路由分析上，rr-7 因为需要手写 export 的路由，明显比较快……当然还是没法和传统的静态博客系统比，毕竟那是真正的增量构建 html 不是全量的 bundler。但无所谓，哈哈，不要搞这么性能焦虑。</p>
<hr/>
<h2>2026-06-03 05:37:13</h2>
<p>#分享 技术</p>
<ul>
<li>斯坦福新的AI课程： <a href="https://cs336.stanford.edu">CS336: Language Modeling from Scratch</a></li>
</ul>
<p>一共19节，差不多一学期的强度。又出现了，研究生真正的导师。</p>
<hr/>
<h2>2026-06-02 00:01:45</h2>
<p>最近设计偏好有更新。一是因为字体，好像把系统换成更纱黑体后，粗字重实在太粗了，我不确定有多少默认字体有这么粗。二是近两年又在流行弱对比轻盈感，信息密度也比前两年偏高了。我看博客也是开始觉得不忍直视了。draw.io 的预设也全部给变细了一遍。</p>
<p>又因为 claude 流行的关系，现在全是衬线细字的黄底学术风大家也能接受了。</p>
<p>但是中文还是那个问题，衬线体表现不统一，又不能给网页引入网络字体。所以只能在无衬线的方向上走。有时间我又要搞装修。笑死，根本没修完，还在装修 AO3 。</p>
<p>AO3 算是地狱级别，原生 DOM 太简单，选择器 Scope 过大相互影响，CSS 的特性支持停留在10年前的水平。给 AO3 写主题是目前的 AI 绝对搞不定的东西。</p>
<hr/>
<h2>2026-05-20 18:48:05</h2>
<p>#分享 引用 <a href="https://daily.xlab.app/d/20260518/">透明日报</a> 的文章：</p>
<blockquote>
<p>人工智能并没有制造新的教育问题，而是让旧问题变得不容忽视。早在第一个语言模型训练出来之前，我们的教育机构就已经存在着奖励表现而非理解、奖励流利而非深度、奖励形式而非真正投入的习惯。人工智能只不过是将这些习惯工业化并加速化，直到它们的空洞本质变得无可辩驳<br/>
这或许是它最出人意料的馈赠。如果这场变革迫使我们回归教育的本质——培养能够提出真正问题、谨慎判断并对真理负责的人才——那么，人工智能时代或许会出人意料地成为教育革新的时代</p>
</blockquote>
<ul>
<li><a href="https://www.ncregister.com/commentaries/schnell-repairing-the-ruins">Repairing the Ruins: Why AI Can’t Replace Education</a></li>
</ul>
<p>嗯，好精准……</p>
<hr/>
<h2>2026-05-14 20:49:09</h2>
<p>说一下这一段时间干什么吧，因为我自己也记不住，自打我爸来过两次，睡眠就彻底被打乱了。之前好歹是缓慢偏移，现在的感觉是每天都在倒时差，对着手表上零星小睡、无睡眠、清醒多次的长睡眠发呆。</p>
<p>昨天又购入了个垃圾服务器，说是有 ipv6 家宽，结果一看 ipv6 支持性好差。把初始化运维的脚本大改了。</p>
<p>……写了几句微信消息来了，不知道是公司的还是导师的。</p>
<p>前几天……忘了，感觉就是在路上，很热，极度的困，很重的书包，不知道在改什么，趴着睡，无法停止的灾难化思维，厕所。正常人很难理解知道不等于做到这件事，我指的是对于相当重大的事件。我是很难理解有人对于任何事都能马上做到，不想做的也能。有人是通过想到做什么就去做的训练强制跳过判断过程。我试过，这要求我必须要持续想着“任何事情立马去做不判断任何环境变量”这件事。一旦停止想这条规则，或者有什么事忽略了这条规则，就做不到。</p>
<p>把 Obsidian 编辑模式的样式改了，改得和渲染模式有几乎相同的排版了。感觉这么多年，主题都是交给第三方了。但第三方没有这种编辑模式下距离也比较宽松的渲染。</p>
<p>Obsidian 同步也换到自己的服务器上了，用的 livesync。GPT 说这个插件是面向技术用户。可能“面向技术用户”是交互做不好的高情商说法……</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[draw.io 与 Word 转 PDF 打印时的清晰度问题]]></title>
            <link>https://sansui233.com/posts/2026-05-25-draw-io-svg-to-word-pdf-print</link>
            <guid isPermaLink="false">https://sansui233.com/posts/2026-05-25-draw-io-svg-to-word-pdf-print</guid>
            <pubDate>Mon, 25 May 2026 09:36:00 GMT</pubDate>
            <description><![CDATA[Word 的图打出来超糊的说]]></description>
            <content:encoded><![CDATA[<p><strong>最近打印论文发现一个问题</strong>，我的超高清流程图 PNG，打印出来非常糊。</p>
<p>然后检查了一下 PDF，确实是导出时糊成一坨。</p>
<p><img src="https://img-cf.sansui233.com/imgs/2026/05/202605252012853.webp" alt="1_padded_padded"></p>
<p>我用后期画图用的都是 draw.io，之前也写过 <a href="/posts/2024-11-12-%E6%8A%8Adrawio%E8%A3%85%E4%BF%AE%E4%B8%BA%E7%AE%80%E5%8D%95%E7%BE%8E%E8%A7%82%E7%9A%84%E7%99%BD%E6%9D%BF%E5%BA%94%E7%94%A8">draw.io 相关设置的文章</a>，研究了一下，大概分为两种情况。</p>
<h2>使用像素图（PNG）</h2>
<p>如果使用 PNG 之类的像素图，首先要<strong>确保原图像素足够大</strong>，在 draw.io 中我会导出为 400% 大小。然后在 Word 选项 -> 高级中：</p>
<p><img src="https://img-cf.sansui233.com/imgs/2026/05/202605252012855.webp" alt="2_padded_padded"></p>
<p>可以选择以下两种任意其一</p>
<ul>
<li>不压缩文件中的图像</li>
<li>默认分辨率设置为「高保真」</li>
</ul>
<p>之后把糊图全部替换一遍，这样至少设置后图像不会被压缩。</p>
<p><strong>检查方式</strong>：放大 Word 界面到 250% 后看看图像的清晰度是否可接受。</p>
<p>但是导出 PDF 或者打印时，像素图始终是以图像像素打印的，带有抗锯齿，没有矢量文字那么清晰。而且<strong>流程图用矢量图无疑是更好的</strong>。</p>
<h2>使用矢量图（SVG）</h2>
<p>在使用 draw.io 的 SVG 导出矢量图后，在 Word 中显示不糊了，但是导出为 PDF 发现还是会糊的。</p>
<p><img src="https://img-cf.sansui233.com/imgs/2026/05/202605252012856.webp" alt="3_padded_padded"></p>
<p>PDF 中明显依然是把 SVG 转换为了像素图。并且，「dobj」 的上框线也被截断了一半，因为 bounding box 是从线条中间算的，导出时 SVG 必须加点边距来避免这个情况。</p>
<p>如果想要 Word 能完全按照矢量图处理 SVG，draw.io 导出时需要取消勾选「嵌入字体」和「嵌入图形」。</p>
<p><img src="https://img-cf.sansui233.com/imgs/2026/05/202605252012857.webp" alt="4_padded_padded"></p>
<p>但此时渲染更不对了。一是<strong>字体不对</strong>，其次是 <strong>SVG 内的文字默认不换行</strong>。</p>
<p><img src="https://img-cf.sansui233.com/imgs/2026/05/202605252012858.webp" alt="5_padded_padded"></p>
<p>这是因为 draw.io 的 SVG 默认面向 HTML 的，Word 对于很多 HTML SVG 的渲染特性是不支持的。如果需要 draw.io 的渲染和 Word 一致：</p>
<ol>
<li>在图形框上设置字体，而不是选中文字内部设置字体。</li>
<li>在导出前需要全选图形，然后在右侧栏的文字选项卡中勾选「转换标签为 SVG」。</li>
</ol>
<p><img src="https://img-cf.sansui233.com/imgs/2026/05/202605252012859.webp" alt="6_padded_padded"></p>
<p>但是就算是这样，你还是有可能会发现英文字体间距（kerning）有问题。</p>
<p><img src="https://img-cf.sansui233.com/imgs/2026/05/202605252012860.webp" alt="7_padded_padded"></p>
<p>我看了下<a href="https://www.drawio.com/doc/faq/SVG-export-text-problems">官网的说明</a>，这种情况应该要取消前两项。</p>
<p><img src="https://img-cf.sansui233.com/imgs/2026/05/202605252012861.webp" alt="8_padded_padded"></p>
<p>这样最终效果就完全一致，导出为 PDF 打印后，图表内的文字也和正文一样清晰，而且可以被选中。
<img src="https://img-cf.sansui233.com/imgs/2026/05/202605252012862.webp" alt="9_padded_padded"></p>
<h2>总结</h2>
<p>如果用像素图，记得图像够大，让图像不要压缩即可。</p>
<p>如果用矢量图，需要</p>
<ul>
<li>全选图像，「文本」中取消「自动换行」和「格式化文本」。手动换行</li>
<li>draw.io 导出 SVG 时取消「嵌入字体」和「嵌入图像」，并添加一点边距</li>
</ul>
<p>这样 Word 转 SVG 为 PDF 时，文字可以保持矢量状态，而且可以被选中。</p>]]></content:encoded>
            <category domain="https://sansui233.com/categories/工具">工具</category>
        </item>
        <item>
            <title><![CDATA[Windows 调整之中文字体]]></title>
            <link>https://sansui233.com/posts/2023-09-29-windows-system-chinese-fonts-adjustment</link>
            <guid isPermaLink="false">https://sansui233.com/posts/2023-09-29-windows-system-chinese-fonts-adjustment</guid>
            <pubDate>Wed, 25 Mar 2026 15:33:14 GMT</pubDate>
            <description><![CDATA[让 windows11 字体更好看的一些设置与字体浅谈]]></description>
            <content:encoded><![CDATA[<blockquote>
<p>以下仅适用于低于 4k 缩放 200% 的显示器</p>
</blockquote>
<p>微软雅黑作为随着 Windows7 出现的字体，加上遥遥领先（？）的 ClearType，在当时的 1080p 显示器上十分清晰易读。</p>
<p>但如今的显示器分辨率越来越高，旧版微软雅黑的设计存在着明显的缺陷。</p>
<p>一是其字形设计并不平衡，中宫过大，有的字形可以以难看来形容；二是微软雅黑字形只在 4K 屏 200% 缩放（以上的配置）上有着较好的显示效果。</p>
<p>微软曾经设计过“另一版的微软雅黑”，即 Noble Scarlet，但并没有在正式的系统中使用。这一版字体设计依然中宫偏大，但相对老版收敛了不少，平衡了一些。</p>
<p>另外，如果你不巧像我一样用着 2K 或 2.5K 屏，</p>
<ul>
<li>在 24寸时，100% 缩放字体比较合适，但与 16 寸 1080p 显示器差不多清晰度，不过屏幕可用空间更大。</li>
<li>在 21 寸时，100% 缩放字体会偏小，比较锻炼眼睛。150% 缩放字体大小比较合适，效果更细腻，但字型会比较怪，且屏幕可用空间与 1080p 相同。</li>
<li>在 16 寸时，150% 缩放字体稍微偏小，效果比较细腻，但非整数倍缩放+ClearType 的加持下，一些像素被吞掉，笔画的间距不平衡，有种“ windows 特有的字被虫噬的美”。</li>
</ul>
<p><img src="https://img-cf.sansui233.com/imgs/2024/08/202408190158527.webp" alt="字形"></p>
<p>可以看到，上图的 100% 200% 缩放没有字形变形问题，可以说微软雅黑小字优化是考虑的 100% 缩放。100% 缩放显得糊则是因为图片放大放大倍率过高，实际不会有糊，而是有锯齿感。</p>
<p>150% 缩放会由于 clearType 的“锐化”导致字形变化，不知道的还以为换了个字体。如果是125%、175%的缩放，字体变形更加糟糕。</p>
<p>造成缩放问题的原因大概可以用下图进行简要解释：</p>
<p><img src="https://img-cf.sansui233.com/imgs/2024/08/202408190318888.webp" alt="缩放"></p>
<p>Mac 上的 Retina 渲染相当于 4k 200% 缩放起步。而 windows 下， 2k-2.5k 的屏幕都在 200% 以下的缩放中挣扎。如果软件没有适配高分屏，没有 clearType，强制进行双线性缩放（常见于图片UI），就会显得非常糊。想体验这样的糊，可以下载旧版的原神启动器。</p>
<h2>需要准备</h2>
<ul>
<li><strong>Noble Scarlet</strong>  替换系统的微软雅黑。由于 Noble Scarlet 是一个未完成的字体，普遍使用的是社区修正版，以下是资源参考。
<ul>
<li><a href="https://bbs.pcbeta.com/viewthread-1960120-1-4.html">pcbeta</a></li>
<li><a href="https://www.bilibili.com/read/cv6059905/">bilibili</a></li>
</ul>
</li>
</ul>
<blockquote>
<p>以上苹方加粗版本不一致性问题太多、新版苹方的英文表现相当糟糕，因此不建议使用，其他版本直接替换的都还不错。</p>
</blockquote>
<ul>
<li>系统字体替换工具：搜索 “<a href="https://www.fishlee.net/soft/SysFontReplacer/">字体替换工具 by 随风飘扬</a>”。替换完后重启，否则可能有缩放错误。另外，github 上有一个非侵入式的系统字体替换工具 <a href="https://github.com/Tatsu-syo/noMeiryoUI">noMeiryoUI</a>，可惜换不全 windows 11，只是作为预览不同字体在系统上的效果倒是个很不错的工具。</li>
<li><a href="https://www.mactype.net/"><strong>MacType</strong></a> 改善 ClearType 的虫噬渲染方式带来的不均匀，使用后提升非常非常大。</li>
<li><strong><a href="https://source.typekit.com/source-han-serif/cn/">思源宋体</a></strong>：推荐将浏览器的 Serif 字体设置为此字体。默认的宋体真的，不论中文英文，都很丑……只适合打印。</li>
</ul>
<h2>字体替换说明</h2>
<p>位于 <code>C:\Windows\Fonts</code> 下有三个文件。这个三个文件可以使用上述的<strong>系统字体替换工具</strong>替换（推荐），或者安全模式下 <code>xcopy</code> 命令也可以替换。但是自己替换时要注意备份，这是真正意义上的替换了底层字体。网上也许会说用 PE 启动，但其实并不需要从 PE 启动这么麻烦。</p>
<ul>
<li><code>msyhbd.ttc</code></li>
<li><code>msyh.ttc</code></li>
<li><code>msyhl.ttc</code></li>
</ul>
<p>位于 <code>C:\Users\你的用户名\AppData\Local\Microsoft\Windows\Fonts</code> 也有三个文件，这三个文件可以不用管，直接安装对应新字体就可以让新字体生效，同时老字体也没有被删除，只是会生成 <code>msyhhv_0.ttc</code>，等于是修改了注册表中的字体文件Link。</p>
<ul>
<li><code>msyhhv.ttc</code></li>
<li><code>msyhsb.ttc</code></li>
<li><code>msyhsl</code>.ttc</li>
</ul>
<p>当然，其实你也可以生成注册表</p>
<h2>常用正文黑体简述</h2>
<p><img src="https://img-cf.sansui233.com/imgs/2024/07/202407260100518.webp" alt=""></p>
<h3>苹方</h3>
<p>苹方是一款设计上很优秀的字体，其间架结构、中宫非常平衡，既兼顾了传统的汉字笔画细节又有规整而现代的几何化，间距合理，阅读起来非常舒适。</p>
<p><del>但是……苹方的设计缺字重。</del> 苹方已经发布了可变字体，目前不再缺字重了，下段内容已过时。</p>
<blockquote>
<p>在设计上，苹方没有 Heavy 字重（<a href="https://support.apple.com/en-us/103203">参考</a>）。而在<a href="https://github.com/paraself/PingFang-Fonts">流行的 github 苹方字体仓库</a>中，则是将 Bold 字重映射到了 Heavy，而将原本的Medium 映射到了 bold。虽然这个问题不是苹果设计的导致的，而是一个再次分发时的错误，但致使目前网上能搜索到的第三方仓库的苹方字体整体字重均偏细。</p>
</blockquote>
<p><del>另外，苹方在 2.5K 屏上表现非常糊。</del> hinting 有了，不糊了，下段内容已过时。</p>
<blockquote>
<p>苹方问世时已经进入了 Retina 屏的时代，没考虑过在低 PPI 屏幕上的表现（不是4K屏缩放200%都别用）。</p>
</blockquote>
<p>第三，苹果设备的显示的西文字体是 <a href="https://zh.wikipedia.org/zh-hans/San_Francisco_(2014%E5%B9%B4%E7%9A%84%E5%AD%97%E4%BD%93)">San Francisco</a>，不是苹方。在 <a href="https://lrd.im/blog/2022-01-17">细数 Pingfang SC 的七宗罪</a> 中，也提到仅使用苹方导致不同设备字体 fallback 的不一致的问题。而作为系统字体里的其他问题，例如缺失本地化的字型，也是大部分字体所缺乏的，这已经不仅仅是一个字体问题，而是和字体相关的和 UI 技术标准化问题，难以仅通过字体解决。而无比例数字、冒号不垂直居中、没有垂直标点等细节，则都是因为苹果显示标点数字用的 SF 字体，苹方在此类字符上算是基本能用，但缺少多种场景下的细节。</p>
<blockquote>
<p>其他资源： <a href="https://www.figma.com/community/file/1089832205783108371">Pingfang for windows - Figma</a></p>
</blockquote>
<p>另外，苹方是有版权限制，以下字体除了思源黑体，和大厂的开源黑体，均不可免费商用。</p>
<h3>思源黑体系列</h3>
<p>思源黑体(Noto sans) 是 google 的开源可商用字体，用于 Android 系统，在开源可商用的的黑体其质量无可替代。</p>
<p>更纱黑体是思源黑体的衍生，修改了西文部分，相比思源黑体上更符合作为 无明显风格特征的系统字体，带 hinting 在 1080p 和 2.5k 下都能保证良好的清晰度。</p>
<p>但是，思源黑体系列设计相比于国产的商用字体并不能算好，有时间架结构比较怪异，字形的细节不太统一，比如“用”字明显矮了一截，整理风格上给人一种不稳定感。同时也不是一个大气的字体，比如口字旁处理对于黑体而言偏小，“用”字矮了一些，但是在宋体设计上，“用”字矮的这一截反而让字体看起来平衡。而一个系列的字体衬线、非衬线的统一感来源于其比例，个人理解为思源/更纱系列是优先考虑宋体的字形，和黑体的比例有一定的结合。整体而言还是宋体的设计更加优秀。</p>
<p>相对而言更纱黑体更适合作为系统字体，有着合理的 hinting。思源黑体是不太适合低 ppi 屏的，它的 Regular 字重看起来像 Bold。</p>
<h3>方正兰亭系列（微软雅黑）</h3>
<p>Noble Scarlet （社区版）常规体是新设计中宫收窄的微软雅黑，而粗体是方正兰亭黑 Pro，因此在加粗时，字体明显会变小一圈。</p>
<p>微软雅黑系列字体在标点处理上很差，最直观的就是全角引号，太像半角的处理方式，很难看出前引号与后引号的区别。其实我在写这一篇文的时候，换了 Typora 的字体，才发现前后引号全打反了……</p>
<p>方正兰亭黑 Pro 想对于两版微软雅黑都有着更小的中宫，字形设计中正。但也由于稍小了一些，在低 ppi 屏的小字上笔画更容易显得不太均匀，渲染效果不太好。另外使用此字体需要相比于其他所有字体更大的行距，因为其较小的中宫，字间距显得相对宽了。</p>
<h3>汉仪旗黑系列</h3>
<p>近年来的国产安卓厂商字体都是汉仪旗黑的衍生，代表阿里的普惠体、鸿蒙体、小米的字体、Oppo的字体。</p>
<p>这系列字体间架结构合理，但笔画上更加激进，减弱了起笔与收笔的的传统突出，以追求几何感与现代的科技感。在观感上，这样规矩的方形会使得字体相比方正系列更加圆润，多了现代感但少了汉字的人情味，用于阅读小说时尤其明显。</p>
<p>仅字形而言，作为 UI 是非常不错的。不过 Misans 渲染出来明显偏粗，我没有测试其他同系列字体是否也有这样的问题。</p>
<h2>改掉 Windows 的默认中文无衬线字体</h2>
<p>很多无法分别修改中英字体的 windows 原生应用，当只设置了英文字体时，显示的中文是新宋体（SimSun），比如 vs studio。原因在于系统里的 Microsoft Sans-serif 字体名，回落到的第一个字体就是新宋体……难以想象微软雅黑出了十多年了还有这样的问题。</p>
<p>解决办法：</p>
<ul>
<li>winkey + R, 输入 regdit，进入 windows注册表</li>
<li>进入 <code>HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontLink\SystemLink</code></li>
<li>把 Microsoft Sans Serif 的值中 SIMSUN.TTC 那一行去掉。这样默认的无衬线体就会往后 fallback 到系统的微软雅黑上。</li>
<li>把 <code>Segoe UI</code> 的 <code>TAHOMA.TTF,Tahoma</code> 挪到 <code>MSYH.TTC,Microsoft </code>后面</li>
</ul>
<hr>
<p>创建于 2023-09-29 02:25:44</p>
<ul>
<li>2026-03-25 更新：针对苹方字体资讯更新，增加字体替换说明。</li>
</ul>]]></content:encoded>
            <category domain="https://sansui233.com/categories/工具">工具</category>
        </item>
        <item>
            <title><![CDATA[Minecraft v1.20.1 常用设置]]></title>
            <link>https://sansui233.com/posts/2023-09-26-minecraft-settings-for-v1-20</link>
            <guid isPermaLink="false">https://sansui233.com/posts/2023-09-26-minecraft-settings-for-v1-20</guid>
            <pubDate>Mon, 12 Jan 2026 18:38:09 GMT</pubDate>
            <content:encoded><![CDATA[<blockquote>
<p>更新：<a href="/static/mc-1.20.1-mods/dependencies.html">1.20.1 版本 mod 列表</a>，有详细的 mod 分类与依赖关系。大部分为实用工具</p>
</blockquote>
<p>在 Minecraft 1.20 版本光照引擎被大幅改写，使得帧数提升，模组的数量似乎又多了起来。另外在 fabric 发展起来以后，mod的社区生态有了很大的变化，有很多老牌模组有了更新的替代。现在记录一下实现常用的基本功能需要的模组与修改设置。</p>
<p>我使用的 hmcl 启动器，在其中进行模组下载可显示模组间的依赖情况。以下内容在 1.20.1 中完全兼容，且项目均在维护中。</p>
<h2>1. Mods</h2>
<p>MC 是一款肝度明显过高的游戏。mod 的选用主要是为了：</p>
<ol>
<li>使画面养眼</li>
<li>降低肝度，同时少引入额外的快捷键</li>
<li>优化细节使用体验</li>
</ol>
<p>使用以 fabric-api 构建的模组。</p>
<h3>1.1 渲染类</h3>
<ul>
<li>Sodium: 渲染优化之神，许多模组的前置</li>
<li>Sodium-extra: 渲染优化之神的扩展，相应 GUI 为reeses sodium options</li>
<li>Lithium: 原版机制的算法改进</li>
<li>Iris: Sodium 加光影</li>
<li>Custom Entity Models: 自定义实体模型，增强对 optifine 材质包的支持</li>
<li>Continuity: 无缝纹理，安装后需要启用相应的材质包。对第三方材质包支持一般，主要和 optifine 的格式还是不一样。</li>
<li>Indium: 许多模组的前置，提供 Fabric Rendering API的支持</li>
</ul>
<h3>1.2 功能类</h3>
<ul>
<li>modmenu: 显示所有模组和相应的设置页面（如果有的话）设置为 <code>\</code> 开配置</li>
<li>carpet: 单人生存必备，可使用命令放置假人以常加载区块刷红石</li>
<li>tweakeroo: 一系列微调的小功能。主要使用 freecamera（灵魂出窍）<code>f5</code>以获得更好的摄影视角，zoom 开启类似 optifine 的按 <code>c</code> 视角放大，handrestock 可自动补货手里的工具、方块</li>
<li>xaero's minimap: 小地图，降肝度必备。需要设置一下显示的东西，默认会非常多，我只开启了玩家、时间、坐标。关闭了网格显示和生物显示。有世界地图和世界地图的 Plus 版本，联动领地声明功能（虽然单人用不太到）</li>
<li>Carry on：手里没有东西时，<code>shift+右键</code> 搬运箱子，降低装饰的肝度。</li>
<li>JEI + EMI + 通用拼音搜索: 物品搜索，查看合成配方、查看方块用途，EMI 增加了<strong>查看合成树</strong>，在 JEI 的 <code>r</code> 键可看。切换可合成物品。</li>
<li>Invertory Profile Next: 高版本的 R 键背包整理（但被我改成 <code>z</code> 键整理，R 键通常是 JEI 查看合成表）。自动补充工具、连续合成、捡物品时默认扔到背包中，以及在打开箱子时使用滚轮移动物品。关掉快破损时替换工具。</li>
<li>imblock: 输入法冲突修复</li>
<li>Panda's falling tree：砍树时树会倒下，降低砍树的肝度。</li>
<li>Leawind's Third Person: 更好的第三视角。这算是第一个可以日常使用的第三视角模组，挖方块瞄准都很方便。日常的垂直平滑 0.5 以上，不然爬山能晕死。特点是不绑快捷键。</li>
<li>better combat: 动作战斗优化，攻速和攻击范围都有反馈了。</li>
<li>Litematica：投影。辅助红石机械建造，也算是一种降生存建筑的肝度。使用相当简单，一根木棍，control+滚动切换模式，快捷键进菜单。最难的其实是收集足够多的预置模型。但这个模组，要抢 Map 的 M 键……键位需要大改。</li>
<li>Hey Wiki: 在指向物品时按 h 键查询wiki。在物品越来越多的高版本具有一些引导作用。</li>
</ul>
<h3>1.3 新物品</h3>
<ul>
<li>Gliders：类似塞尔达的滑翔伞，防摔。在空中按空格展开滑翔。使用方式和大部分游戏一致。只是要占一个盔甲位。动画做得很不错。</li>
<li>Waystones：传送石碑，后期物品，降低交通的肝度。如果用地图作弊路径点传送就不需要这个东西了，但理想的玩法还是地图只是用来看的，让传送石碑在地图上显示（需要前期多刷小黑），只能传送石碑处，禁止任意传送。传送石不是个好设计，MC背包不能放下更多东西了。除非有单纯扩容用的背包模组。</li>
<li>travelersbackpack：背包模组，终于有了 fabric 版。虽然 mojang 一直很谨慎地加入新的方块，但似乎从未考虑过方块越来越多时的背包使用问题。再者模组整合包也因为方块种类数爆炸的问题增加背包模组。在 1.12 版本时，背包容量是刚好够的。个人并不是很喜欢背包的设计。</li>
</ul>
<h2>2. 设置</h2>
<ul>
<li>画面尺寸: 1920*1080@60fps，窗口化</li>
<li>视场角: 85</li>
<li>鼠标灵敏度: 75</li>
<li>模拟距离：8</li>
<li>渲染距离：12</li>
</ul>
<h3>2.1 快捷键修改</h3>
<p>总体的键位映射图如下。深绿色为原版的功能。橘色为Mod功能，蓝色为创造模式功能。键位分为直接按键、组合键、修饰键（长按）。MC 原版只能定义直接按键，组合键与修饰键在复杂的 mod 中用得多，并且会覆盖原版的直接按键。</p>
<p><img src="https://img-cf.sansui233.com/imgs/2026/01/202601132155912.webp" alt="KeyMaps"></p>
<h4>游戏主界面</h4>
<p>首先把 ctrl 改到 capslock 键位，方便疾跑。系统全局 powertoys 改的（吐槽一万句control的键位）</p>
<ul>
<li>长按 <code>tab</code>，滚轮切换物品栏。在tweakroo 的「工具」中开启 hotbarscroll，再在 tweakroo  的「快捷键」中把 hotbarscroll 的快捷键设置为 Tab。</li>
<li><code>v</code>: 切换第三人称视角(visual)，很常用的功能。原本是f5，实在太远了</li>
<li><code>f4</code>: Leawind's Third Person 第三人称视角相机调位置。同时关掉左右切换。点按左右，长按居中</li>
<li><code>f5</code>:  灵魂出窍，在 tweakroo 的 freecamera 中设定</li>
<li><code>c</code>: 望远镜，在 tweakroo 的 zoomactivate 中设定</li>
<li><code>b</code>：开背包（如果物品栏有的话）</li>
<li><code>t</code>: 路标点传送管理(transport)。聊天改 <code>enter</code> 键</li>
<li><code>x</code>: 锦致装饰-箭袋</li>
<li><code>m</code>:  显示大地图和设定。地图的其他快捷键全关掉。</li>
<li><code>n</code> Litematica 投影菜单</li>
<li><code>h</code> Hey Wiki 查询指向的物品 Wiki</li>
<li><code>shift+右键</code> 空手时搬运箱子，carry on 自带。</li>
<li><code>\</code> Mod Menu配置</li>
<li><code>n+c</code> Litematica 配置。n系列特别多键。</li>
<li><code>x+c</code> tweakroo 配置</li>
</ul>
<p>特定工具下的修饰键：</p>
<ul>
<li>木棍工具
<ul>
<li><code>~</code>  Litematica 木棍工具修饰键，改变区域大小</li>
<li><code>n+enter</code> Litematica 木棍工具模式5且创造模式下放置投影</li>
</ul>
</li>
</ul>
<p>预留键位：</p>
<ul>
<li><code>g</code> 圆盘菜单</li>
<li><code>~</code>  特定工具修饰键，比如连锁挖矿</li>
<li><code>b</code> 背包(backpack)</li>
<li><code>j</code> FTB任务书(journal)</li>
<li><code>左alt</code> 创造模式下，建筑模组 axiom 用 alt 切换专用物品栏。</li>
</ul>
<h4>合成台、箱子UI</h4>
<ul>
<li><code>r</code> : JEI 查看光标下物品的合成方式</li>
<li><code>u</code> : JEI 查看光标下物品的用途</li>
<li><code>ctrl + 左键点击</code> JEI的物品，移动物品到合成台</li>
<li><code>z</code> : 一键整理。在 IPN 的设置中修改。</li>
<li>使用滚轮以在背包和箱子间移动物品，按shift移动整组</li>
</ul>
<h2>3. 光影</h2>
<ul>
<li>BSL v8.2.04，默认配置High，把 Camera 中的 Bloom 关闭，把 Atmosphere 中的 fog 调到 0，开启 lighting 中的handDynamicLight。抗锯齿的TAA随便开不开，取决于风扇响不响</li>
<li>Complementary Reimagined，配置 medium，high 会开启材质的反射运算量明显变大。夜晚也比较亮，适合生存。</li>
<li>itt 3.0，更适合搭配了写实系材质的建筑，风格最写实的 shader 没有之一。不适合生存。</li>
</ul>
<h2>4. 材质</h2>
<ul>
<li>任意矿物发光材质。比如 <a href="https://www.curseforge.com/minecraft/texture-packs/new-glowing-ores">New Glowing Ores</a>。主要是因为 BSL 光影没有矿物发光，所以要加一个材质以确保有 fallback。</li>
<li><a href="https://afdian.net/a/Nan2uu">彩虹像素</a>，非常优秀的免费猛男材质包，原版风但更精致。有很多更可爱的附加包。</li>
</ul>
<h2>5. 创造模式附加</h2>
<h3>5.1 Mod</h3>
<p>Axiom 高版本环境必备，可以创建实体方块随意拉伸模型，相当好用。</p>
<p>effortLess structure 快速建造几何体。原 effortless buidling。</p>
<p>lotweaks 自定义材质轮盘</p>
<p>wordedit 经典创世神</p>
<h3>快捷键</h3>
<p><code>tab</code>: effortLess structure 轮盘。</p>
<p><code>r</code>: lotweaks 轮盘，和手中方块有关。会禁用丢东西（但创造模式本来就不用丢东西除了篝火灭火，何不用 Axiom 的调试棒？）</p>
<p><code>左 alt</code>： Axiom 的大菜单</p>]]></content:encoded>
            <category domain="https://sansui233.com/categories/游戏">游戏</category>
        </item>
        <item>
            <title><![CDATA[z-index 设计与海浪模型]]></title>
            <link>https://sansui233.com/posts/z-index-and-context-management-and-design-logic</link>
            <guid isPermaLink="false">https://sansui233.com/posts/z-index-and-context-management-and-design-logic</guid>
            <pubDate>Tue, 06 Jan 2026 18:20:00 GMT</pubDate>
            <description><![CDATA[z-index 只是个插件，层叠上下文才是真正的 z 轴]]></description>
            <content:encoded><![CDATA[<blockquote>
<p>摘要：本文针对前端中多个元素层叠时 z-index 管理混乱的问题，提出一个名为海浪模型的设计模型，以构建复杂 z-index 管理的最佳实践。</p>
</blockquote>
<p>……好像 AI。但我是人，我纯手打的。</p>
<h2>基础知识 - 代码的画布</h2>
<p>层叠上下文是代码逻辑上的画布。一旦一个元素产生了层叠上下文，它内部的所有子元素就被包裹在这个范围里。</p>
<p><strong>层叠上下文的产生</strong></p>
<ul>
<li>根元素：<code>&#x3C;html></code></li>
<li>定位 + 层级：<code>position</code> 为 <code>relative</code> / <code>absolute</code> 且 <code>z-index</code> 不是 <code>auto</code>。</li>
<li>固定定位：<code>position: fixed</code> 或 <code>sticky</code>。</li>
<li>CSS3 属性：
<ul>
<li>opacity 小于 1。</li>
<li>transform 不为 none（比如旋转、缩放）。</li>
<li>filter（滤镜）、flex/grid 子元素的 z-index 等。</li>
</ul>
</li>
</ul>
<blockquote>
<p>❗注意：层叠上下文的产生，和层内元素关系，是两套规则，两者之间<strong>没有关系，没有关系，没有关系</strong>。因为部分规则相似，很容易给记混了。</p>
</blockquote>
<p><strong>层叠内元素关系</strong></p>
<p>为了好解释，我使用 context-level 说明绝对的上下覆盖关系。</p>
<ul>
<li>CL-1: 背景和边框（最底层）</li>
<li>CL-2: 定位元素（如absolute）且负 z-index</li>
<li>CL-3: 块级元素（static 定位的普通 div 等）</li>
<li>CL-4: 浮动元素（float）</li>
<li>CL-5: 内联/行内块元素（文字、图片）</li>
<li>CL-6: 定位元素（如absolute）且 z-index 没有设定为负，还有 opacity，transform 等。</li>
<li>CL-7: 定位元素（如absolute）正 z-index（最顶层）</li>
</ul>
<p>z-index 在其中的作用相当于是一个算层叠关系的插件。<strong>必须和定位配套使用，否则不生效。</strong></p>
<p>从功能上说，<strong>层叠上下文才是真正面向用户的Z轴</strong>，z-index属性只是这个 z轴的一个插件。</p>
<h2>视觉画布</h2>
<p>可以发现，被提升到 <strong>CL-6</strong> 的层，其规则和产生一个层叠上下文高度重合，<strong>就像产生了一个新的画布</strong>。这也是为什么说，容易把 CL-6 层等同于产生层叠上下文的层，但是不是的，<strong>CL-6 是描述自己作为子元素的层级</strong>，而“产生层叠上下文”描述的自己作为父元素的行为。</p>
<ul>
<li>opacity 且 z-index: 0。位于 CL-3，产生了层叠上下层文，但是其实层级很低，z-index 是无效的。</li>
<li>CL6: relative 且 z-index: auto。位于 CL-6，产生不了层叠上下文，其子元素如果有更低的层级，可能会被盖掉。子元素有更高的层级，会盖掉别人。</li>
<li>CL6: relative 且 z-index: 0。位于 CL-6，产生不层叠上下层文，其子元素层级和当前元素严格一致。</li>
</ul>
<p>理解了这一点，可以记住。在做目录头时，并不是设置了 <code>relative</code> 就万事大吉了，如果你的后面的元素也是 relative，很容易被覆盖。</p>
<h2>z-index 划分</h2>
<p>考虑到我们不可能把所有画布内元素全挤在 CL-6，全靠 DOM 关系划分层级，因此需要设计 CL-7 的层级，也就是正 index 区域。</p>
<p>正 z-index 的画布内元素应处于同一个层叠上下文内。如果不在同一个，则按产生了新的层叠上下文设计。</p>
<h3>基础逻辑</h3>
<p>对于一个画布（层叠上下文）内，我设计新产生的画布设计上分100层。对应 z-index 0（CL-6）到 z-index 100。每 20 层为一个全屏大画布，比如 Modal。也就是</p>
<ul>
<li>0-20：画布内组件层级</li>
<li>20、40、60、80、100：新画布层级</li>
</ul>
<p>那 21-39 有什么用？<strong>没有用，不要用</strong>。只是为了提醒你，这个东西是个大画布。如果把画布内组件设定到了 20 以上，你可能就不知道什么东西溢出到了 Modal。</p>
<p>此外，如果真的想做一些在不同层级上换来换去的小组件，也可以根据模型的定义很快决定放到哪个层级，非常方便。</p>
<h3>海浪模型</h3>
<p>想象一个海星被 5 层海浪（大画布）冲到沙滩上，每一层海浪上有自己的生物群。</p>
<p>大部分生物都挤在海底（0层以下）层，形成了基石。到第 0-19 层有一堆小东西争先恐后地彰显存在感，但是你又觉得不那么重要。之后的20层、40层、60层通常而言清澈透明，但一旦染色后，就会将下面的生物变得不见天日。</p>
<p>此时你觉得这个海星，你应该看到它吗？应该放在哪一层？</p>
<p>通常而言，层级设计遵循以下基础逻辑。</p>
<ul>
<li>大尺寸元素的层级低小，小尺寸元素的层级高。</li>
<li>重要性高的层级高。</li>
</ul>
<p>第一条是一个视觉规律，第二条则是功能需要。</p>
<h3>0-19 层</h3>
<p>根据基础的逻辑，0-20 层我会如下划分。</p>
<ul>
<li>移动端菜单栏 -> 中偏小，重要，9</li>
<li>浮动按钮 -> 中偏小，但不重要，5</li>
<li>侧边栏 -> 大，但重要。你很难说和浮动按钮哪个在上面。这两个要权衡一下，给到 4。</li>
<li>Hover tips -> 小，重要，19<br>
如果 Hover tip 也可能本身是一个交互丰富的大画布，这时要看重要性。如果重要性与 Modal 相当，设到 20（新一层海浪）。如果只是随便看看，共享当前层的主要内容，只是覆盖一下正文，设到 0 或 1。大画布谨慎设置中间值，容易造成混乱。</li>
<li>目录头：暂时一下冒头，给到 0（注意是 z-index:0，不能是 z-index:auto）</li>
<li>拖拽：暂时冒一下头，给到0。</li>
</ul>
<p>在海浪模型里，<strong>带 9 的数字被表示为重要，而整十数表示为新的起点</strong>。</p>
<h3>20、40、60层</h3>
<p>几乎为 Modal 层。通常页面上只会出现一个Modal，20 层足够使用，或者你要设置为40，60，都可以。如果你有很多层 Modal 要排序（窗口管理）。要么从 z-index 入手，要么从 DOM 结构入手。显然，别去动 DOM 结构树，靠 z-index 足够完成窗口层级管理。</p>
<h3>最重要的海星</h3>
<p>这个海星如果你认为是稀世珍宝，任何时候都需要被看见，请直接设置到 999。但一旦，你认为它有可能会被覆盖，请思考它被覆盖时，是不是还是这么重要。</p>
<p>如果不确定，参考基础逻辑：<strong>面积越小通常越重要</strong>。这不是一个我定义的规则，而是客观的视觉逻辑。面积越小，通常代表了信息量越密集。一个很常见的对比是：</p>
<ul>
<li>Hover tips（小面积）：在一个层非常非常重要。但需要被新画布覆盖</li>
<li>消息通知（中小面积）：重要吗？超重要的，但是消息通知上是不是还是应该可以 Hover 一些提示？</li>
<li>Hover reference（大面积）：比如参考。重要吗？很重要。但是你觉得需要被消息通知、进度条覆盖吗？需要。</li>
</ul>
<h3>天空层（1000+）</h3>
<p>总有些东西，你希望他们不要在海浪里浮动，而浮动在天上，不被任何东西覆盖。比如全局进度条、全局 Hover、全局消息。</p>
<p>放在天空的这点问题本身不大。最大的问题是，你觉得这个海星，应该放在海浪还是天空？<strong>不要让本该在海里的海星升天</strong>。一旦你觉得这个海星会被新逻辑的 Modal 覆盖，请让海星立刻返回 0-19 层。</p>
<h2>为什么要思考海浪模型</h2>
<ul>
<li>易于复用：对于可复用的浮动组件，不管其父元素的 CL 层级，总能被安插到正确的位置。如果发现异常，那就是忘了使父元素产生层叠上下文来包裹他</li>
<li>避免混乱，减少设计的心智负担</li>
</ul>]]></content:encoded>
            <category domain="https://sansui233.com/categories/学习">学习</category>
        </item>
        <item>
            <title><![CDATA[Better Web Typography for a Better Web 中文版]]></title>
            <link>https://sansui233.com/posts/2025-12-30-Better-Web-Typography-for-a-Better-Web-Chinese-Version</link>
            <guid isPermaLink="false">https://sansui233.com/posts/2025-12-30-Better-Web-Typography-for-a-Better-Web-Chinese-Version</guid>
            <pubDate>Mon, 29 Dec 2025 22:10:00 GMT</pubDate>
            <description><![CDATA[我的排版启蒙书]]></description>
            <content:encoded><![CDATA[<p>这是一本讲网页排版的书籍，书中内容有在线示例与代码，是这么多年来对我极其有用的平面设计书籍之一，说是我的排版启蒙也不为过。此博客的采用的正文排版均构建于此书所介绍的基础上。</p>
<ul>
<li>书名：Better Web Typography for a Better Web</li>
<li>译名：更好的网页排版，造就更好的互联网</li>
</ul>
<blockquote>
<p>此书为 90% 的 AI 翻译，完全保留原书排版，由人工校对以确保大部分用词统一。</p>
</blockquote>
<h2>推荐语</h2>
<p>2018 年，我还在大学社团做海报，那时候对排版的理解更多是靠“直觉”。直到接触到了 Matej Latin 的网页排版公开课，也就是这本书的起源。课和中提出“排版的完美等边三角形”——即字号、行高与行宽之间的动态平衡，以及“模块化比例”的概念，彻底改变了我观察网页的视角。我至今铭记在心：“要获得完美的段落，需要三样东西：字体大小、行高和行宽。它们需要达到平衡。”</p>
<p>从那以后，这三要素就成了我做阅读文字时绕不开的底层直觉。每当我看到一个网页，总会下意识地去拆解它的文字比例是否协调。尽管此书以英文为基准，其中的排版规律对多种语言均适用。</p>
<p>虽然这本书写在八年前，在互联网平面设计风格迭代如此之快的今天，它讨论的核心规则却依然稳固。甚至可以说，如今主流的网页排版方向，就如书中的所言。如果你想摆脱“凭感觉”排版，真正理解排版的美学逻辑，倾情您阅读推荐这本书。</p>
<h2>简介</h2>
<p>Better Web Typography for a Better Web 是一本源自高分在线课程的著作，旨在向网页设计师和开发人员等网站构建者讲解排版。作者 Matej Latin 将垂直节奏（vertical rhythm）、模块化比例（modular scale）和页面构成（page composition）等复杂概念，以通俗易懂的方式进行了深入浅出的解析。本书配有实时代码示例，读者在阅读过程中将亲历设计并构建一个示例网站的完整流程。这是一本针对新媒介的排印新书：基本规则虽未改变，但除此之外的一切都已焕然一新。</p>
<h2>摘录</h2>
<ol>
<li>“……如果说我希望你们从这次演讲中记住一个关键要点，那就是以下内容——要获得完美的段落，需要三样东西：字体大小、行高和行宽。它们需要达到平衡。”</li>
<li>大多数网站都会犯的一个错误，就是将主体文本设置得过小。早在21世纪初，将主体文本大小设置在大约11像素是常见的做法。但当时的屏幕更小，分辨率也较低，这意味着11像素的字体在当时看起来比现在更大。</li>
<li>推荐文本行长度为45至75个字符。需考虑所用语言的平均词长。</li>
<li>我认为，我们开始创建网站时，首先应该审视网站的主要目的。不仅仅是我们正在设计的特定网站，而是其真正、根本的目的。我指的是——<strong>内容</strong>。试想，没有内容的网站是什么？它是一个空壳。内容糟糕但外观精美的网站是什么？它就像一个外表好看但缺乏个性的人。那么反过来说呢——内容出色但外观贫乏的网站？它就像是一个个性鲜明、趣味十足的人，却因为“外表不够标准”而无人关注。</li>
</ol>
<h2>资源链接</h2>
<p>CloudFlare - R2 直链下载：</p>
<ul>
<li><a href="https://img-cf.sansui233.com/books/%E6%9B%B4%E5%A5%BD%E7%9A%84%E7%BD%91%E9%A1%B5%E6%8E%92%E7%89%88%EF%BC%8C%E9%80%A0%E5%B0%B1%E6%9B%B4%E5%A5%BD%E7%9A%84%E4%BA%92%E8%81%94%E7%BD%91%20-%20Matej%20Latin.epub">更好的网页排版，造就更好的互联网 - Matej Latin</a></li>
</ul>
<p>标签： 排版，字体排印，平面设计，网页设计</p>]]></content:encoded>
            <category domain="https://sansui233.com/categories/书和剧">书和剧</category>
        </item>
        <item>
            <title><![CDATA[uv 管理 conda 项目依赖]]></title>
            <link>https://sansui233.com/posts/2025-07-24-embed-python-with-uv</link>
            <guid isPermaLink="false">https://sansui233.com/posts/2025-07-24-embed-python-with-uv</guid>
            <pubDate>Thu, 24 Jul 2025 12:12:32 GMT</pubDate>
            <description><![CDATA[沐神都解决不了的……]]></description>
            <content:encoded><![CDATA[<h2>conda 的问题</h2>
<p>Python 新项目使用 uv 管理容易，但是总是有一些老项目不用。 conda 包管理一直以来都是 AI 的标配。我用 python 99% 都是在扒别人代码运行。这就导致了我运行了多少个项目，就装了多少份 torch……硬盘再大也经不起十几次折腾。</p>
<p><img src="https://img-cf.sansui233.com/imgs/2025/07/202507242029977.webp" alt="沐神都解决不了的"></p>
<p>conda 的问题在于</p>
<ol>
<li>requirements.txt <strong>全手写</strong>！很多人可能忘更新配置，导致扒拉下来缺库运行不了，先解决一个小时的依赖问题再说。</li>
<li>依赖和安装顺序强相关。比如项目需要更新的 numpy，但你可能要装个别的项目的库，python 发了论文和仓库就跑的项目是很多的。安装一个旧项目导致之前安装 numpy 被卸载，然后整个项目就垮掉。这种情况相当之多，又解决两个小时的依赖问题。</li>
<li>（至少我不愿意看到）电脑里十几个相同版本的 torch 和 cuda。当时的硬盘还只有 256G，多装几个 torch 无法接受，嗯……</li>
</ol>
<p>直到现在都还是这样的，大家主打一个能跑完实验就行。包的更新是激进的，包管理是落后的。在几年前有人说用 PDM，后面有 poetry。这两是不用再手写 <code>requirements.txt</code> 了，依赖也会自动 resolve 不会覆盖来覆盖去的，但还是会装十几个 torch。直到 uv 开始用硬链接进行包管理。</p>
<h2>uv 之于 conda 项目</h2>
<p>uv 接管 python 界的依赖管理按理说已经没什么问题。但实际情况是，很多项目还是在用 conda。除非哪天 torch 和 HF 都把 uv 设置为首推，否则就得一直与  conda 存在的问题战斗。</p>
<h3>1. 不提供 venv 的项目</h3>
<p>用于研究的项目一般都是不提供的打包好的环境的，主要是太大了，每个人设备情况也不一样。所以下载后第一件事是</p>
<pre><code class="language-sh">uv venv
./.venv/Script/activate
</code></pre>
<p>如果这个项目不再更新了，或者是打算迁移到 uv，可以直接使用 uv 的方式管理依赖。uv 会自动维护 <code>pyproject.toml</code> 和 <code>uv.lock</code> 文件。</p>
<pre><code>uv add -r requirements.in -c requirements.txt
</code></pre>
<p>如果这个项目，他还在更新，你时不时就得去拉一下分支。这时候最好用 <code>uv pip</code> 。至于依赖混乱问题，听天由命吧。<del>跑得起来就得了</del></p>
<pre><code>uv pip install -r requirement.txt
</code></pre>
<h3>2. 提供 venv 的项目</h3>
<p>提供 venv 的项目通常是给人用的，b 站的整合包一大堆。这种已经配好环境的项目也意味着你最好只用 pip。通常还是非常原始地调用 pip</p>
<pre><code>./.venv/python -m pip install xxx
</code></pre>
<p>……等于说又开始了安装十几份 torch 的依赖管理模式。用 uv 是可以重复利用缓存的。这个时候 uv 的问题在于无法接管 python 环境，需要设置一下环境变量：</p>
<pre><code class="language-sh">export UV_PYTHON="./.venv/python"
uv pip list
</code></pre>
<p>然后就可以利用 uv 的缓存了。</p>
<p>当然，依赖混乱问题使用 <code>uv pip</code> 是无法避免的。这对于发行版也是一种麻烦。因为发行版的环境全给你配好了，但有的项目设计了插件系统，插件系统又需要装插件的 requirement.txt，安一个许久没更新的插件让主项目废掉的情况也不是不可能……</p>
<p>如果让插件作者指定的兼容版本？只靠规范做不到，必须像MC那样检查版本号，不更新版本号就不放行。这样就算不更新代码了，也得倒逼作者每个版本都进行一次（至少是与主项目的）依赖兼容性测试。</p>
<p>我觉得以当前 python 的运行方式，不 lock 子依赖的版本，这个问题是没法解决的。</p>
<h2>uv 管理 torch 下载源</h2>
<p>通常而言，在不指定 index 时 uv add torch 是去 pypi 或清华镜像源找 CPU 版本。如果打算每个项目都采用一样的 torch 版本 和 cuda ——</p>
<h3>uv 创建的新项目</h3>
<p>共用的 <code>uv.toml</code> 指定下载源。</p>
<p>Linux 在 <code>.config/uv/</code> 下，Windows 在 <code>%APPDATA%/uv/</code> 下。</p>
<pre><code class="language-toml">[[index]]
url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/"
default = true
[[index]]
name = "pytorch-cu128"
url = "https://download.pytorch.org/whl/cu128"
explicit = true
</code></pre>
<p>项目级别的 <code>pyproject.toml</code></p>
<pre><code class="language-toml">dependencies = [
  "torch>=2.8.0",
  "torchvision>=0.23.0",
  "torchaudio>=2.8.0",
]

[tool.uv.sources]
torch = [
  { index = "pytorch-cu128"},
]
torchvision = [
  { index = "pytorch-cu128"},
]
torchaudio = [
  { index = "pytorch-cu128"},
]
</code></pre>
<p>然后执行 <code>uv sync</code> 安装。</p>
<h3>uv pip 管理老项目</h3>
<p>直接指定命令行 的 <code>--index-url</code> 和 <code>--torch-backend</code></p>
<pre><code class="language-shell">uv pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126 --torch-backend=cu126
</code></pre>
<p>和用 pip 的方式差不多，区别是会硬链接到集中的缓存，不会重复占用十几份 torch。当然。该有的依赖冲突还是会有的。<del>关键是装好后就不要更新了</del></p>]]></content:encoded>
            <category domain="https://sansui233.com/categories/学习">学习</category>
        </item>
        <item>
            <title><![CDATA[踩了一圈 CSS 构建方案的坑]]></title>
            <link>https://sansui233.com/posts/2025-07-12-compare-css-solutions</link>
            <guid isPermaLink="false">https://sansui233.com/posts/2025-07-12-compare-css-solutions</guid>
            <pubDate>Sat, 12 Jul 2025 04:49:09 GMT</pubDate>
            <description><![CDATA[前端代码中质量最薄弱的一环]]></description>
            <content:encoded><![CDATA[<p>css 的写法一直算比较混乱的。层叠的样式表与 DOM 结构的分离看似清晰，但也因此容易产生屎山，组合太自由，哪些选择器用了哪些选择器没用，共用的嵌套的，分离的。今天小编就带你一探究竟（……）</p>
<h2>CSS类复用粒度</h2>
<p>我自己把 css 选择器（类）的复用粒度分三个层级。</p>
<h3>组件类</h3>
<p>粒度最大的层级，通常按组件级别语义化。选择器一般是下面这些名字</p>
<pre><code class="language-css">.wrapper
.container
.list-item
</code></pre>
<p>组件化的选择器下面通常有很多条的 css。</p>
<h3>功能类</h3>
<p>通常是共用的样式或状态，比如</p>
<pre><code class="language-css">.open
.close
.light
.dark
.glass-effect
</code></pre>
<p>这个看起来好像和组件类不冲突，但硬说的话组件类其实应该是这样</p>
<pre><code class="language-css">.container.open { 此处将 .open 的所有样式全覆盖 }
.container.close { 此处将 .close 的所有样式全覆盖 }
.container.light { 此处将 .light 的所有样式全覆盖 }
.container.dark { 此处将 .dark 的所有样式全覆盖 }
</code></pre>
<p>组件类的状态严格在组件的 scope 下。功能类则是可以不限 Scope 的复用。</p>
<p>这 CSS 容易混乱的根源。在工程维护角度，功能类是最不敢乱动的类，不知道动了后哪里样式就会出问题。但在设计角度，用功能类复用一些状态又确实很方便，统一设计也好用。比如增加统一的圆角、描边、阴影样式。</p>
<p>功能类的优缺点是一体两面——图像的只有主观的好看与否，没有客观的对错。</p>
<h3>原子类</h3>
<p>定义海量常用的基础样式类，在 class 上直接写类名就能获得对应效果。就是 tailwind css。</p>
<p>原子类相较于功能类粒度更小，也不会轻易改动 css 属性。</p>
<pre><code class="language-css">.flex
.col-1
.text-sm
</code></pre>
<h2>方案</h2>
<p>通常来说，一个库的样式会着重在一个某一个粒度上。</p>
<h3>原生 css</h3>
<p>用原生 css 时通常会以 <strong>组件化</strong> 的粒度为主，带极少的功能类。现在配合 css 变量使用。早期的网页简单，一个 CSS 文件就能搞定全站，设计上并没有考虑项目变得越来越复杂后的实践。</p>
<p><strong>优点</strong>：性能好，扁平的结构利好小项目。适合写研究新样式。</p>
<p><strong>缺点</strong>：过于扁平，大量工程化后易屎山，存在样式与 DOM 分离带来的维护混乱。</p>
<h3>SCSS</h3>
<p>古法预处理器，可能多层嵌套 css，可组合。是 <strong>组件化</strong> 的粒度。在 CSS.module 出来前，用 SCSS 分割 Scope 挺好用。</p>
<p><strong>优点</strong>：结构非常清晰</p>
<p><strong>缺点</strong>：</p>
<ol>
<li>编译后的选择器很长一串，从浏览器渲染角度，匹配DOM是耗性能的</li>
<li>难以应对复杂项目 DOM 结构的改变，需要考虑扁平化 + 命名，但这样做和原生 CSS 的维护体验也不相上下。</li>
</ol>
<h3>CSS Module</h3>
<p>CSS Module 是完全 <strong>组件化</strong> 的粒度。相比起 SCSS 的样式与 DOM 分离，CSS Module 为组件内部样式耦合，组件间样式分离。</p>
<p><strong>优点：</strong> 在组件粒度分割合理的情况下，清晰易维护。</p>
<p><strong>缺点</strong>：依赖预构建，写类名写起来太磨叽了。整体我用得不多没法评价。</p>
<pre><code class="language-jsx">const Button = () => {
  return (
    &#x3C;button className={styles.button}>
      Click me
    &#x3C;/button>
  );
};
</code></pre>
<h3>BootStrap</h3>
<p><strong>组件化</strong> 为主，少量原子化修饰的预制样式库，拿来即用是不错的。早期 CSS 框架大多是指预制样式，和预构建的库有本质区别。</p>
<h3>Tailwind css</h3>
<p>完全原子化的神奇之库，通过编译可以有功能类和组件类。它更像是重新定义了 css 语法。</p>
<p><strong>优点</strong></p>
<ol>
<li>灵活，快，好看</li>
<li>工具链齐全，可以裁剪掉不用的原子类。</li>
</ol>
<p><strong>缺点</strong></p>
<ol>
<li>稍微要写复杂一点的样式，DOM 就会被一大堆 class 埋没。</li>
<li>从浏览器渲染角度，匹配、合并大量 CSS 样式是需要更多性能开销的</li>
<li>要做到同种样式的复用，必须组合原子类，变成功能类或组件类，否则维护起来相当麻烦。这似乎违背了用 tailwind css 的初衷，熟悉了 css 的不如直接自己用 css 手撮功能类和组件类。</li>
<li>其实我是 tailwind 黑，嗯。但无法否认开发时确实很快很方便。</li>
</ol>
<pre><code class="language-jsx">function Card({ title, description, imageUrl, imageAlt }) {
  return (
    &#x3C;div className="max-w-sm rounded overflow-hidden shadow-lg">
      &#x3C;img className="w-full" src={imageUrl} alt={imageAlt} />
      &#x3C;div className="px-6 py-4">
        &#x3C;div className="font-bold text-xl mb-2">{title}&#x3C;/div>
        &#x3C;p className="text-gray-700 text-base">{description}&#x3C;/p>
      &#x3C;/div>
      &#x3C;div className="px-6 pt-4 pb-2">
        &#x3C;span className="inline-block bg-gray-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2">#photography&#x3C;/span>
        &#x3C;span className="inline-block bg-gray-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2">#travel&#x3C;/span>
        &#x3C;span className="inline-block bg-gray-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2">#adventure&#x3C;/span>
      &#x3C;/div>
    &#x3C;/div>
  );
}
</code></pre>
<h3>原生 css in js</h3>
<p>指 JS Object 转译为 CSS。由于写起来太不像 CSS，复杂的功能写起来过于不直观 ，我直接 PASS。</p>
<pre><code class="language-jsx">const InlineStyleExample = () => {
  const myStyle = {
    color: 'blue',
    backgroundColor: 'lightgray',
    padding: '10px',
    borderRadius: '5px'
  };

  return (
    &#x3C;div style={myStyle}>
      &#x3C;p style={{ fontSize: '18px', fontWeight: 'bold' }}>
        This text is styled with inline CSS.
      &#x3C;/p>
    &#x3C;/div>
  );
};
</code></pre>
<h3>Styled-components</h3>
<p><strong>组件化</strong>的 CSS in JS 方案，写起来像 CSS 实际是 JS。支持客户端动态修改 CSS 具体属性（其他方案做状态改变主要依靠 selector 的匹配）</p>
<p><strong>优点</strong>：</p>
<p>灵活好拓展，比如主题管理不仅仅是颜色，还可以是图片资源一类的。</p>
<p><strong>缺点</strong>：</p>
<ol>
<li>因为是 JS 转 CSS，服务器编译慢和客户端渲染慢得选一个</li>
<li>React 的 useContext 要被废弃了，而 styled-components 严重依赖此 hook，导致进入了维护状态。JS 框架发展太快了。</li>
</ol>
<pre><code class="language-jsx">import styled from 'styled-components';

// Create a styled button component
const StyledButton = styled.button`
  background-color: blue;
  font-size: 16px;
  padding: 10px 20px;
  border-radius: 5px;

  &#x26;:hover {
    background-color: darkblue;
  }
`;

function App() {
  return (
    &#x3C;div>
      &#x3C;StyledButton>Click Me&#x3C;/StyledButton>
    &#x3C;/div>
  );
}
</code></pre>
<h3>Linaria</h3>
<p>自定义 <strong>功能类</strong> 的 CSS in js 方案，同时也支持 <strong>组件化</strong> 写法。生成的是完全静态的 css，样式值的复用靠变量，片段的复用靠 <code>css</code> 生成的类。</p>
<p><strong>优点</strong>：</p>
<p>是预构建方案，在服务端渲染。和原始的 CSS 写法和思路差不多。</p>
<p><strong>缺点</strong>：</p>
<ol>
<li>
<p>值复用靠变量，但是由于是 <strong>静态 css</strong>，这个并不会变。所以变量插值<strong>其实是常量</strong>。比如下面的 font-size 并不会变化。</p>
<pre><code class="language-jsx">const fontSize = 16;
const Title = styled.h1`
  font-size: ${fontSize}px;
`
</code></pre>
<p>也就是说，你如果想在客户端随意改变字体，用 context/zustand 这种 runtime 的 fontSize，这样写报错。不过，Linaria 允许你借助 react 的 props 和 <code>styled</code> 组件来实现客户端的值变化。</p>
<pre><code class="language-jsx">const Title = styled.h1`
  font-size: ${props => props.size}px;
`
export default function MyComponent() {
  const fontSize = useAppStore(state => state.fontSize)
  return &#x3C;Title fontSize={fontSize}>Hello&#x3C;/Title>
}
</code></pre>
<p>相当于生成</p>
<pre><code class="language-jsx">&#x3C;h1
  className="_title_xyz"
  style={{ '--linaria-font-size': `${size}px` }}
>
</code></pre>
<p>那这和 styled-components 写起来已经差不多了。而且要做主题化的值都得用快要废弃的 <code>useContext</code> API。只不过 linaria 改的 style 属性，styled 是改的 css  API。改 style 属性其实已经不能算静态了。</p>
</li>
<li>
<p>组件间的<strong>样式复用方案</strong>只有原生的 CSS 方案，上述的奇妙客户端插值做不了这个需求。假设，你要做一个主题化的对话框的卡片阴影，只能使用原生 css 类中加原生 css 变量。上述动态改变样式的因为依赖 props，只能使用 <code>styled</code> 的写法，但这样就会把 html 标签了也继承了，不同的样式也无法随意组合。这也是为什么我说 Linaria 是原生 css 的替代，而不是 styled-components 的替代，构建方式就决定他们差得太了远。</p>
</li>
<li>
<p>基于2，导致你写组件又要检查 <code>styled</code> 又要确认 <code>css</code> 类又要检查 JSX classname 的顺序。如果用组件继承会被迫连 DOM 类型都继承。</p>
</li>
<li>
<p>使用功能类有点像原子化，又完全不如 tailwind 已经给你预设好一堆东西的效率。写类名和 cssmodule 一样，太磨叽了</p>
</li>
</ol>
<p>我博客本想迁移至此方案，但由于工作量实在巨大而放弃。linaria 主要还是解决了个命名空间冲突的问题，想用得更深入一点就会四不像。</p>
<pre><code class="language-jsx">import { css } from '@linaria/core';

const eleStyle = css`
  color: red;
  font-size: 3rem;
  &#x26;:hover {
    color: blue;
  }
`;

function App() {
  return &#x3C;h1 className={eleStyle}>Hello Linaria!&#x3C;/h1>;
}

export default App;
</code></pre>
<h2>构建组建库</h2>
<p>每一个 CSS 方案都有对应的构建组件库的实践。 <a href="https://github.com/shadcn-ui/ui">shadcn</a> 是基于 tailwind 构建组件库实践。</p>
<h2>CSS 框架选择要素</h2>
<ol>
<li>样式复用</li>
<li>样式组合</li>
<li>动态样式</li>
<li>主题切换</li>
<li>代码提示</li>
<li>自动裁剪</li>
<li>随意重构</li>
<li>渲染性能</li>
<li>实践的统一性</li>
</ol>
<p>最重要的还是自己的需求。</p>]]></content:encoded>
            <category domain="https://sansui233.com/categories/学习">学习</category>
        </item>
        <item>
            <title><![CDATA[Steam 假入库是怎么做的]]></title>
            <link>https://sansui233.com/posts/2025-04-22-techs-about-steam-crack</link>
            <guid isPermaLink="false">https://sansui233.com/posts/2025-04-22-techs-about-steam-crack</guid>
            <pubDate>Mon, 21 Apr 2025 19:59:00 GMT</pubDate>
            <description><![CDATA[入库不仅仅是入库]]></description>
            <content:encoded><![CDATA[<p>很久以前被淘宝的 Steam 假 CDKey 给坑过，因为价格其实也不便宜，打的正版宣传，其实是盗版，后来感觉太可疑了查了一下确认被坑了。现在突然想起来了解了一下。本文概述是日常语境中的 “Steam假入库”需要的一些步骤，概括起来为五个方面：解锁、下载、入库、DRM、API验证。</p>
<h2>下载验证</h2>
<p>steam 的下载鉴权流程是</p>
<ol>
<li>查找账号是否有拥有此游戏，有则显示下载按钮</li>
<li>点击下载后，把游戏软件 Manifest 对应的密钥（DecryptionKey）明文写入一个本地文件 <code>Steam\config\config.vdf</code></li>
<li>Steam （原版）根据 <code>config.vdf</code>中的信息，发送下载请求至 Steam CDN 进行下载</li>
</ol>
<p>“Steam 解锁” “Steam 假入库” 指的是绕过上述机制。具体而言，如果没有购买游戏，可以：</p>
<ol>
<li>将按钮变为可下载（至于是伪造请求实现还是逆向 hook 实现，我不知道，都可以，因为甚至不需要变按钮，给个外部的下载按钮也可以）</li>
<li>点击按钮后，从不知名渠道获取一个正版账号的 Manifest（下载清单）和 Decryption Key（下载密码），写入<code>Steam\config\config.vdf</code></li>
<li>Steam（原版）根据 <strong><code>config.vdf</code></strong>，发送下载请求至 Steam CDN 进行下载</li>
</ol>
<p>Steam 的下载验证可以说是相当简单，明文本地存密码，CDN 无状态的验证，这么多年没有改过流程，给入库工具空间（虽然说前端的事总有办法 Hack 但也是可以让 Hack 成本变高很多的）。不过 Steam 理念本来就是以平台服务留住玩家的，反倒是扩大了其影响力与营收。</p>
<p>一些名词解释：</p>
<ul>
<li>解锁：指对没有购买的游戏，“可以显示下载按钮”。和能不能下载没有关系。</li>
<li>下载：Steam 根据 <strong><code>Steam\config\config.vdf</code></strong> 的信息下载游戏文件。</li>
<li>入库：指把下载好的游戏，在当前电脑的 Steam 库中显示。</li>
</ul>
<p>以上过程均不涉及对游戏本身的破解，只是对 Steam 下载过程的破解。也就是，破解的是 Steam，不是游戏。</p>
<h2>运行时验证</h2>
<p>这里开始才会涉及到游戏破解。</p>
<p>有的 Steam 游戏下载下来后是不用破解的，直接找到游戏目录，点 exe 可以正常游玩（比如星露谷）。只是无法通过原版 Steam 打开，也就只能离线。</p>
<p>有的游戏是无法脱离 Steam 直接运行的。这里涉及两层验证：</p>
<h3>加密算法层</h3>
<p>这是一层 DRM（数字版权加密保护）。Steam DRM 系统的名称为 SteamStub。SteamStub 的加密有各种的变体，每个游戏使用的不一致。只对 exe 的算法加密，是一个离线的步骤。不涉及 Steam 平台的验证。</p>
<p>网上有一个开源工具叫 Steamless，可以破除 SteamStub 对游戏的 DRM，称为脱壳。但脱壳本身不处理 Steam 在线验证相关，只进行了脱壳的游戏也是无法正常游戏的。</p>
<blockquote>
<p>SteamStub DRM 和 Steamworks API 是两个独立层。Steamless <strong>仅移除 SteamStub 加密外壳</strong>，但游戏代码中与 Steam 平台功能（如成就、云存档、联机）相关的 API 调用（通过 <code>steam_api.dll</code>）仍会保留。</p>
</blockquote>
<h3>Steam API 验证</h3>
<p>游戏还可能调用 Steam api 进行在线通信，如成就、云存档、联机相关的 API 调用。</p>
<p>这是使用入库工具玩破解游戏可能被红信或封号的根本原因，因为对 API 的调用是发送到 Steam 官方服务器的。在小红书上了解到，有的玩的盗版可以与正版联机，说明 Steam 在联机时并不会验证账号是否拥有该游戏。包括 Steamtools 实现的家庭共享联机，也说明了 Steam 对于是否账号可以进行联机鉴权不足。但只要留有记录就有可能导致被封号，取决于 Steam 什么时候想管理盗版现象。</p>
<p>反之，如果伪造一个 Steam 的服务器，并且替换游戏中的 Steam 相关的动态链接库，如 <code>steam_api.dll</code> ，游戏里所有对 Steam API 的调用被发送到假服务器上，返回一个假的结果。这种工具也已经有了，项目为 goldberg_emulator，简称 GBE。破解版的游戏通常会内置一个这样的虚拟 Steam 环境。</p>
<h3>第三方厂商验证</h3>
<p>很多大厂的游戏有自己的联机服务器和验证机制、不仅走 Steam API 的验证。这种也是可以通过虚拟环境破解，但没人做，除非专门对这个游戏的所有 API 做逆向。难度比逆向通用的 Steam API 高很多。</p>
<h2>Steamtools 是什么</h2>
<p>已知 Steamtools 主要是做 <strong>解锁</strong> 和 <strong>入库</strong>。对于会不会破解游戏，网上没有更多的信息。我也不想冒风险尝试使用它。</p>
<p>根据官网的解释，Steamtools 可以离线运行（不如说破解游戏只能是离线运行），是提供了类似 GBE 的验证环境。有没有对 DRM 脱壳不清楚，但个人倾向于有，很多游戏都有 DRM 的保护，除了 SteamStub，还有其他的 DRM 验证方式，不脱壳玩不了。</p>
<p>因此个人推测是，Steamtools 是集 <strong>解锁、下载、入库、破解、运行时验证</strong> 为一体的工具集。</p>
<h2>SteamAutoCrack 是什么</h2>
<p>只做 DRM 脱壳和 Steam API 验证。项目在 Github 上，破解后的游戏会运行在 GBE 的环境下。这种方式是完全离线运行的单机。</p>
<h2>风险来源</h2>
<p>完全脱离 Steam 运行没有风险，只要在线就可能有风险。</p>
<p>假入库阶段的风险主要来自于入库工具对 Steam 请求拦截的覆盖程度不足。例如 Steam 版本更新了，使得 API 和下载流程有变化，而入库工具没有对其做处理，无法完全欺骗下载流程。网上看到假入库的人可能有囤积癖或者是打算做灰产，一次性入库了几十个游戏，直接导致被 SteamCDN 拉黑。</p>
<p>运行时的风险也是来自于在线验证，如果是开着 Steam 玩的破解游戏，没有离线时甚至尝试联机，使得游玩信息发送到了 Steam 的服务器（比如不该有的存档、不该有的联机等等）。</p>
<p>另外，入库工具会侵入式修改 Steam的客户端，直接打开 Steam 可能会有检测文件是否被修改。 Steamtools 提供了三种启动模式，可以随时恢复为原版 Steam 的运行。但淘宝卖的入库工具说不准是什么样的，当年骗我的店家那个用的是早期的 steamtools，使用店家的账号下载游戏后，使用 steamtools 离线运行（本来已经忘记了，努力想想竟然想得起来一点细节）。但现在的店家说不准是什么样的，在 B 站看到说有的是直接修改文件，从此都是盗版Steam 客户端，只能卸载重装。</p>
<p>没有风险的方式：如果你有方式得到 Steam 正版的游戏文件，然后用 SteamAutoCrack 破解，能直接脱离 steam 运行则没有风险。</p>
<p>对于更多的人而言，下载木马是最大的风险。</p>
<h2>参考资料</h2>
<ul>
<li>bbs.steamtools论坛</li>
<li>SteamManifestCache wiki</li>
<li>SteamLess Readme</li>
</ul>]]></content:encoded>
            <category domain="https://sansui233.com/categories/Diary">Diary</category>
        </item>
    </channel>
</rss>