案例

Sealed:放得下才封口的信封

给 X、Bluesky 和单条短信用的字数检查器:真的放得下,信封才封蜡;还会点名那个把短信从 160 字砍到 70 字的弯引号。

  • 6 张图片
打开页面查看将在新标签页打开 boloop-works.pages.dev,该页面是独立站点,不属于本站。

图片署名:Tink

一个能直接用的字数检查器,用三只信封来做:“X post”“Bluesky post”和“One text message”(一条短信)。只有文字真的放得下,信封才会封上红色火漆。

打开页面时已经放好一封示例信(“Running 10 minutes late — the train’s stuck outside Hongqiao…”)。第一秒内纸条滑进信封:X(125 / 280)和 Bluesky(125 / 300)合上并封蜡;短信信封合不上,纸条顶出信封盖,红色虚线以上露出的就是真正放不下的那段原文,下方写着 “Open · 55 over · sends as 2 texts”。为什么只有 70?一条虚线框直接点名:一个破折号和一个弯引号。短信里只要出现一个 GSM 字母表以外的字符,上限就从 160 变成 70。按 “Make it SMS-safe (swap 3)”,第三只信封当场以 125 / 160 封上。

每打一个字信封都会跟着变化。“Trim to fit” 会把超出的部分剪到放得下为止,不会把一个字符剪成两半;Undo 可以恢复。你打的字永远不会被悄悄改写,只有这些按钮会改动文字。emoji 换不掉,会标成 “can’t swap”,不会被偷偷删掉。可以复制文字;剪贴板被拦截等错误会直接显示并朗读。减少动态效果时直接显示最终状态。360 px 手机可用。不存储、不上传任何内容。

计数依据:X 直接用 X 开源的 twitter-text 3.1.0(未改动,打包进页面),链接算 23,大部分中日韩文字和 emoji 算 2。Bluesky 按帖子 schema 的两条线:300 个字素、3,000 字节(UTF-8)。短信按 GSM 03.38:160 个 7 位字符(分条时每条 153,€ ^ { } [ ] ~ | \ 各占 2);一旦出现 Unicode 字符就是 70(分条 67)。局限:比 twitter-text 3.1.0 更新的 emoji 按该库的方式计数,可能与 X 线上不同;Bluesky App 可能会缩短长链接;没有处理各国短信的扩展字符表。

在线试用:https://boloop-works.pages.dev/works/sealed/

下载原型文件(zip,152 KB):https://boloop-works.pages.dev/works/sealed/sealed.zip

实际设计说明

Design a small, genuinely useful character counter made of three envelopes — "X post" (280, counted with X's open-source twitter-text 3.1.0, bundled unmodified), "Bluesky post" (300 graphemes and 3,000 UTF-8 bytes, from the app.bsky.feed.post schema) and "One text message" (GSM 03.38: 160 7-bit characters, or 70 once a single Unicode character appears) — as a runnable single-page web app (plain HTML/CSS/JS, no backend, no build, English UI, local fonts, inline SVG favicon).

First second, desktop and 390 px phone: a sample letter is already in place. Paper slips slide into the envelopes; X and Bluesky close and get a red wax seal pressed on; the SMS envelope cannot close — its slip sticks out above the flap and the part above a red dashed fold line is the actual text that does not fit. Under it: "Open · 55 over · sends as 2 texts". A dashed panel names the culprits ("These 2 marks shrink one SMS from 160 to 70 characters: — ’") with one button: "Make it SMS-safe (swap 3)".

Operable: every keystroke moves the slips, opens/closes flaps and presses or lifts seals. Explicit buttons only ever change the text: "Make it SMS-safe" (swaps ’ ‘ “ ” — – … and no-break space for plain ones; emoji are listed as "can't swap"), "Trim to fit" per open envelope (cuts to fit, never inside a grapheme), and one-level Undo. Typing is never rewritten, there is no maxlength. Errors are visible and announced (role=alert): empty copy, blocked clipboard, browser without Intl.Segmenter. Status line (aria-live polite) settles 0.7 s after typing. Reduced motion: final state at once. Nothing is stored or sent.

Inspired by @binniebunnnies and @marcgmbh.