authorgravatar for git@paperclover.netclover caruso <git@paperclover.net> 2026-03-20 19:17:14-07:00
committergravatar for git@paperclover.netclover caruso <git@paperclover.net> 2026-03-20 19:17:48-07:00
loge78568c30caa6d33b046571ed0c4cfc4e89c21d2
tree406a65799e87a016b6dbb30b78bed69443070995
parent3caa2f2be2dca66f2a3f44d3a85a4bf7c7270534
signature Signed by SSH key SHA256:xbd+BjjhyBfwk7GVoURf9Yx0gzDerHbvYv7SddNWmAs

feat: update log with new entries


1 files changed, 79 insertions(+), 1 deletions(-)

src/pages/log.mdo+79-1
...@@ -16,7 +16,8 @@ static const repo = "${repo}";...@@ -16,7 +16,8 @@ static const repo = "${repo}";
16[ts lie detector]: https://git.paperclover.net/clo/ts-lie-detector16[ts lie detector]: https://git.paperclover.net/clo/ts-lie-detector
17[evil inc]: https://evil.inc/17[evil inc]: https://evil.inc/
18[history of japan reanimated]: /history-of-japan-reanimated18[history of japan reanimated]: /history-of-japan-reanimated
19[react mutation]: /history-of-japan-reanimated19[react mutation]: http://jsr.io/@clo/react-mutation
20[react markdown]: http://jsr.io/@clo/react-markdown
20[HOTEWIG reanimated]: /hotewig-reanimated21[HOTEWIG reanimated]: /hotewig-reanimated
21[clover creative control]: https://git.paperclover.net/clo/creative-control22[clover creative control]: https://git.paperclover.net/clo/creative-control
22[markodown]: https://git.paperclover.net/clo/markodown23[markodown]: https://git.paperclover.net/clo/markodown
...@@ -29,6 +30,83 @@ static const repo = "${repo}";...@@ -29,6 +30,83 @@ static const repo = "${repo}";
2930
30these are like mini blog posts, but more in generally just what the heck i'm up to.31these are like mini blog posts, but more in generally just what the heck i'm up to.
3132
33## 2026-03-20
34
35tags: [react markdown]
36
37i published a new library named `@clo/react-markdown`. originally, i wanted to
38have my own version of the `streamdown` package from vercel. but i didn't
39realize how much of a loser company they all are. i wasn't even trying and i
40made a library like a hundred times better and simpler than theres. because of
41the awesome success here, instead of calling mine "memo markdown", i just said
42"yea, this covers every markdown use case for react" and called it React Markdown.
43
44you can install it from the JSR:
45
46```sh
47npx jsr add @clo/react-markdown
48pnpm add jsr:@clo/react-markdown
49```
50
51there are two main features that i deliver on:
52
53- predicting close tokens for sequences like `hello **world`, appending `**`
54 - streamdown has this too, but many many cases are not considered. while
55 theirs is extensible and mine isn't, i don't think you'll need to extend
56 my markdown predictor.
57- component memoization. all block and inline components will preserve their
58 state, even as adjacent content changes. this is done to preserve remounts
59 for things like custom `<a>` tags or other components. (for example, if a
60 custom `<a>` fetches previewing data and provides a hover card, that card
61 won't flicker).
62
63copying some architecture notes from the readme, the memoizer is performant
64from the following tricks:
65
66- Using proper `React.memo()` calls. Obviously.
67- Prediction is implemented in a stateful way that only parses the tail end of
68 the document, marking how much of the document is stable and where possible
69 incomplete syntax may live. Since prediction only applies at the end, changing
70 text midway through can invalidate the whole predictor.
71- Separate the parsed document into "blocks", noting the source location of
72 where each block lives.
73- Only start parsing after the first changed character, rounded to the nearest
74 block. In the append-only stream, this essentially means the last two blocks
75 are the only things being re-parsed.
76- Similarly, run AST transforms only on the changed data. This step has a couple
77 of slow paths for when reference link definitions are added or edited, since
78 it means any places that might have used a reference link may now have to
79 reflect it.
80- After all that, a special AST -> React node transform is used that diffs the
81 new ast with the last ast, reusing React nodes whenever possible. It supports
82 nested children as well as re-ordering top level blocks. This is what prevents
83 most rerenders and is the "secret sauce".
84
85## 2026-03-18
86
87tags: [progress.ts]
88
89laser hair removal is awesome btw. organizing things at home slowly. more work
90on the progress library, trying to handle every edge case possible for the log
91widget system.
92
93when it is done, a code snippet like this will work.
94
95```ts
96using node = progress.start("some action");
97for await (const token of stream) {
98 // correctly interweave progress TUI with partial log lines
99 process.stderr.write(token);
100}
101```
102
103the log system injects into `process` to ensure it plays nice, but there is
104only a fast path on stdout (since the main log messages uses stdout). stderr
105gets to use the crazy `getDrawLock` API i'm cooking up internally.
106
107after all of this works and is reliable, there are some more things i have to
108tidy, but then the progress blog post can be written and reviewed for realsies.
109
32## 2026-03-16110## 2026-03-16
33111
34just chilling. at work i replaced `bun install` with `pnpm`. pretty peak. in the112just chilling. at work i replaced `bun install` with `pnpm`. pretty peak. in the