jaeaeich/components

components

The pieces the writing on jaeaeich.com is made of, rendered by the same pipeline, in both themes. Markdown covers most of it; the rest are a few Astro components you can drop into an .mdx post.

colours

foundations

Every colour is a CSS variable. Dark and light share names, so components never pick a colour directly.

dark
  • --bgpage
  • --surfaceboxes, code
  • --lineborders
  • --line-strongstrong borders
  • --mutedmeta text
  • --softsecondary text
  • --bodybody text
  • --fgheadings, links
  • --accentlabels, markers, hover
  • --code-inlineinline code
light
  • --bgpage
  • --surfaceboxes, code
  • --lineborders
  • --line-strongstrong borders
  • --mutedmeta text
  • --softsecondary text
  • --bodybody text
  • --fgheadings, links
  • --accentlabels, markers, hover
  • --code-inlineinline code
usage
import Swatches from "../components/Swatches.astro";
<Swatches />

type scale

foundations

IBM Plex Mono for structure (labels, meta, code), IBM Plex Sans for reading. Seven sizes, nothing in between.

dark
  • --t-3xljaeaeich
  • --t-2xlwriting
  • --t-xlSection heading
  • --t-lgIntro paragraph
  • --t-mdBody text in a post
  • --t-smSecondary text, captions
  • --t-xsmeta · labels · tags
light
  • --t-3xljaeaeich
  • --t-2xlwriting
  • --t-xlSection heading
  • --t-lgIntro paragraph
  • --t-mdBody text in a post
  • --t-smSecondary text, captions
  • --t-xsmeta · labels · tags
usage
import TypeScale from "../components/TypeScale.astro";
<TypeScale />

text

markdown

Paragraphs, headings with a hover anchor, links, bold, inline code and keyboard keys. All plain Markdown.

dark

Pitfall: the tokio blocking pool

When the OS decided to flush its page cache under all that write pressure, everything piled up behind it. The same 5 GB download took anywhere from 4 to 29 seconds, because every pwrite went through spawn_blocking. See the s3z repo for the fix.

A smaller heading

Press Ctrl + C to disconnect, then run vpn again to stop the instance. Italics are for the occasional aside.

light

Pitfall: the tokio blocking pool

When the OS decided to flush its page cache under all that write pressure, everything piled up behind it. The same 5 GB download took anywhere from 4 to 29 seconds, because every pwrite went through spawn_blocking. See the s3z repo for the fix.

A smaller heading

Press Ctrl + C to disconnect, then run vpn again to stop the instance. Italics are for the occasional aside.

usage
## Pitfall: the tokio blocking pool
When the OS decided to flush its page cache under all that write pressure, everything piled up behind it. The same **5 GB download** took anywhere from 4 to 29 seconds, because every `pwrite` went through `spawn_blocking`. See the [s3z repo](https://github.com/jaeaeich/s3z) for the fix.
### A smaller heading
Press <kbd>Ctrl</kbd> + <kbd>C</kbd> to disconnect, then run `vpn` again to stop the instance. *Italics* are for the occasional aside.

lists

markdown

Orange markers, mono numbers. Items that start with a bold phrase read as a scannable list of points.

dark
  • Write the benchmark before the third optimization. I wrote it after the fifth.
  • Bound every channel. Buffering forever isn’t really a choice.
    • Nested items keep the same marker.
  1. Start the instance.
  2. Poll until AWS says it’s running.
  3. Rewrite the IP in client.ovpn and connect.
light
  • Write the benchmark before the third optimization. I wrote it after the fifth.
  • Bound every channel. Buffering forever isn’t really a choice.
    • Nested items keep the same marker.
  1. Start the instance.
  2. Poll until AWS says it’s running.
  3. Rewrite the IP in client.ovpn and connect.
usage
- **Write the benchmark before the third optimization.** I wrote it after the fifth.
- **Bound every channel.** Buffering forever isn't really a choice.
- Nested items keep the same marker.
1. Start the instance.
2. Poll until AWS says it's running.
3. Rewrite the IP in `client.ovpn` and connect.

quote

markdown

For quoting someone else. Serif italic, so it never gets mistaken for your own voice.

dark

Most rewrites are mistakes. The ones that aren’t usually happen because the platform underneath you grew a feature that does one of your components’ jobs.

light

Most rewrites are mistakes. The ones that aren’t usually happen because the platform underneath you grew a feature that does one of your components’ jobs.

usage
> Most rewrites are mistakes. The ones that aren't usually happen because the platform underneath you grew a feature that does one of your components' jobs.

table

markdown

The header reads like a section label. Scrolls sideways on narrow screens instead of squashing. Right-align number columns with a colon in the divider row.

dark
Change Before After
Upload memory, 40 MB files on 32 workers 1,566 MiB 85 MiB
Upload memory, 128 MB workload 79–92 MB 30–39 MB
Time for the same 5 GB download 4–29 s 4–6 s
light
Change Before After
Upload memory, 40 MB files on 32 workers 1,566 MiB 85 MiB
Upload memory, 128 MB workload 79–92 MB 30–39 MB
Time for the same 5 GB download 4–29 s 4–6 s
usage
| Change | Before | After |
| --- | ---: | ---: |
| Upload memory, 40 MB files on 32 workers | 1,566 MiB | 85 MiB |
| Upload memory, 128 MB workload | 79–92 MB | 30–39 MB |
| Time for the same 5 GB download | 4–29 s | 4–6 s |

footnotes

markdown

Footnotes for asides that would break the flow, and a three-dot divider (a plain ---) between parts of a post.

dark

RustFS started hanging at random under load, so I took it out of the benchmark.1


Stability is not something you can add by pinning an image version.2

Footnotes

  1. After half a day of trying to pin down why. ↩

  2. I tried. ↩

light

RustFS started hanging at random under load, so I took it out of the benchmark.1


Stability is not something you can add by pinning an image version.2

Footnotes

  1. After half a day of trying to pin down why. ↩

  2. I tried. ↩

usage
RustFS started hanging at random under load, so I took it out of the benchmark.[^1]
---
Stability is not something you can add by pinning an image version.[^2]
[^1]: After half a day of trying to pin down why.
[^2]: I tried.

code block

code

Highlighted in the site palette, with a copy button. Add a title for a file tab, and {n} to mark lines.

dark
s3z/src/paginator.rs
pub struct ListPaginator<'a> {
client: &'a S3Client,
continuation_token: Option<String>,
// owned copies would make this usable from Python and Node
}
fn next_page(&mut self) -> Result<Page, Error> {
let token = self.continuation_token.take();
self.client.list_objects_v2(&self.bucket, token)
}
from s3z import Client
client = Client(endpoint="http://localhost:9000")
for obj in client.list("my-bucket", prefix="results/"):
print(obj.key, obj.size) # 1,000 at a time
light
s3z/src/paginator.rs
pub struct ListPaginator<'a> {
client: &'a S3Client,
continuation_token: Option<String>,
// owned copies would make this usable from Python and Node
}
fn next_page(&mut self) -> Result<Page, Error> {
let token = self.continuation_token.take();
self.client.list_objects_v2(&self.bucket, token)
}
from s3z import Client
client = Client(endpoint="http://localhost:9000")
for obj in client.list("my-bucket", prefix="results/"):
print(obj.key, obj.size) # 1,000 at a time
usage
```rust title="s3z/src/paginator.rs" {2}
pub struct ListPaginator<'a> {
client: &'a S3Client,
continuation_token: Option<String>,
// owned copies would make this usable from Python and Node
}
fn next_page(&mut self) -> Result<Page, Error> {
let token = self.continuation_token.take();
self.client.list_objects_v2(&self.bucket, token)
}
```
```python
from s3z import Client
client = Client(endpoint="http://localhost:9000")
for obj in client.list("my-bucket", prefix="results/"):
print(obj.key, obj.size) # 1,000 at a time
```

terminal

code

Shell blocks get a terminal frame automatically. Use console for a session with output, so only the $ lines are highlighted as commands.

dark
vpn
$ vpn
Waiting for the instance to start...
Current instance state: running
Public IP Address: 13.250.xx.xx
$ vpn
Did you forget to stop EC2? ooh the bill!!!
The instance has been successfully stopped.
light
vpn
$ vpn
Waiting for the instance to start...
Current instance state: running
Public IP Address: 13.250.xx.xx
$ vpn
Did you forget to stop EC2? ooh the bill!!!
The instance has been successfully stopped.
usage
```console title="vpn"
$ vpn
Waiting for the instance to start...
Current instance state: running
Public IP Address: 13.250.xx.xx
$ vpn
Did you forget to stop EC2? ooh the bill!!!
The instance has been successfully stopped.
```

diff

code

For "I changed this to this". New lines in orange, removed lines fade out. Use a diff block with a lang, or ins/del markers.

dark
loop {
match rx.try_recv() {
Ok(job) => spawn(job),
Err(_) => poll_completions(),
}
tokio::select! {
Some(job) = rx.recv() => spawn(job),
Some(done) = tasks.join_next() => record(done),
}
}
light
loop {
match rx.try_recv() {
Ok(job) => spawn(job),
Err(_) => poll_completions(),
}
tokio::select! {
Some(job) = rx.recv() => spawn(job),
Some(done) = tasks.join_next() => record(done),
}
}
usage
```diff lang="rust"
loop {
- match rx.try_recv() {
- Ok(job) => spawn(job),
- Err(_) => poll_completions(),
- }
+ tokio::select! {
+ Some(job) = rx.recv() => spawn(job),
+ Some(done) = tasks.join_next() => record(done),
+ }
}
```

callout

components

A boxed aside. note for context, warn for a trap, lesson for the takeaway. Takes any Markdown inside.

dark

note

The TES spec calls it CANCELED with one L. The code follows the spec; the prose doesn’t.

heads up

Reusing a signed request on retry sends a stale SigV4 timestamp, and S3 rejects it as RequestTimeTooSkewed.

lesson learned

If a tool looks suspiciously bad in your benchmark, suspect your harness first.

light

note

The TES spec calls it CANCELED with one L. The code follows the spec; the prose doesn’t.

heads up

Reusing a signed request on retry sends a stale SigV4 timestamp, and S3 rejects it as RequestTimeTooSkewed.

lesson learned

If a tool looks suspiciously bad in your benchmark, suspect your harness first.

proptypedefaultnotes
type"note" | "warn" | "lesson""note"
titlestring–Overrides the default label ("note", "heads up", "lesson").
usage
import Callout from "@personal/ui/components/Callout.astro";
<Callout>
The TES spec calls it `CANCELED` with one L. The code follows the spec; the prose doesn't.
</Callout>
<Callout type="warn">
Reusing a signed request on retry sends a stale SigV4 timestamp, and S3 rejects it as `RequestTimeTooSkewed`.
</Callout>
<Callout type="lesson" title="lesson learned">
If a tool looks suspiciously bad in your benchmark, **suspect your harness first**.
</Callout>

stats

components

Before and after numbers that deserve more than a table row. Wrap Stat cards in Stats; they reflow to one column on phones.

dark

single-put memory

85 MiB−95%

from 1,566 MiB

5 GB download

4–6 ssteady

from 4–29 s

pods per task

1

from 4 + N

light

single-put memory

85 MiB−95%

from 1,566 MiB

5 GB download

4–6 ssteady

from 4–29 s

pods per task

1

from 4 + N

proptypedefaultnotes
labelrequiredstring–
afterrequiredstring–
beforestring–
changestring–Shown as a small orange tag, e.g. "−95%" or "7× steadier".
usage
import Stats from "@personal/ui/components/Stats.astro";
import Stat from "@personal/ui/components/Stat.astro";
<Stats>
<Stat label="single-put memory" before="1,566 MiB" after="85 MiB" change="−95%" />
<Stat label="5 GB download" before="4–29 s" after="4–6 s" change="steady" />
<Stat label="pods per task" before="4 + N" after="1" />
</Stats>

figure

components

An image, chart or diagram with a caption and optional credit. Pass src for an image, or put inline SVG in the slot so it follows the theme.

dark
beforeafter1,566 MiB85 MiB
Peak memory while uploading 40 MB files on 32 workers.s3z benchmarks
The jaeaeich.com social card
An ordinary image works the same way.
light
beforeafter1,566 MiB85 MiB
Peak memory while uploading 40 MB files on 32 workers.s3z benchmarks
The jaeaeich.com social card
An ordinary image works the same way.
proptypedefaultnotes
srcstring–
altstring""
captionstring–
sourcestring–Credit line, e.g. "s3z benchmarks".
sourceHrefstring–
usage
import Figure from "@personal/ui/components/Figure.astro";
<Figure caption="Peak memory while uploading 40 MB files on 32 workers." source="s3z benchmarks" sourceHref="https://github.com/jaeaeich/s3z">
<svg viewBox="0 0 640 200" role="img" aria-label="Bar chart: 1,566 MiB before, 85 MiB after">
<g font-family="var(--mono)" font-size="13" fill="var(--muted)">
<text x="24" y="62">before</text>
<text x="24" y="142">after</text>
<text x="596" y="62" text-anchor="end" fill="var(--fg)">1,566 MiB</text>
<text x="132" y="142" fill="var(--fg)">85 MiB</text>
</g>
<rect x="84" y="44" width="420" height="26" rx="3" fill="var(--line-strong)" />
<rect x="84" y="124" width="23" height="26" rx="3" fill="var(--accent)" />
</svg>
</Figure>
<Figure src="/og.png" alt="The jaeaeich.com social card" caption="An ordinary image works the same way." />

ref

components

A compact link to a repo, file or line. Use it instead of pasting commit hashes or long GitHub URLs into a sentence.

dark

The TaskPod is built in jaeaeich/poiesispoiesis/core/taskpod.py, and the whole project lives at jaeaeich/poiesis. A specific line works too: jaeaeich/vpnvpn.sh:79.

light

The TaskPod is built in jaeaeich/poiesispoiesis/core/taskpod.py, and the whole project lives at jaeaeich/poiesis. A specific line works too: jaeaeich/vpnvpn.sh:79.

proptypedefaultnotes
reporequiredstring–"owner/name" on GitHub.
pathstring–
linenumber–
atstring"main"Branch or tag.
usage
import Ref from "@personal/ui/components/Ref.astro";
The TaskPod is built in <Ref repo="jaeaeich/poiesis" path="poiesis/core/taskpod.py" />, and the whole project lives at <Ref repo="jaeaeich/poiesis" />. A specific line works too: <Ref repo="jaeaeich/vpn" path="vpn.sh" line={79} />.

tags

components

Shown under each post title. Plain text for now; pass href once tag pages exist.

dark
  • #kubernetes
  • #tes
  • #ga4gh
  • #python
light
  • #kubernetes
  • #tes
  • #ga4gh
  • #python
proptypedefaultnotes
tagsrequiredstring[]–
href(tag: string) => string–
usage
import Tags from "@personal/ui/components/Tags.astro";
<Tags tags={["kubernetes", "tes", "ga4gh", "python"]} />

bar chart

components

A few numbers compared as bars. Highlight your own. Plain HTML, so it follows the theme and screen readers get a list. Wrap it in a Figure for a caption.

dark

lower is better

s3z
0.25 s
mc
0.26 s
s5cmd
0.37 s
aws-cli
0.83 s
Downloading 768 MB from MinIO, median of 10 to 30 runs.
light

lower is better

s3z
0.25 s
mc
0.26 s
s5cmd
0.37 s
aws-cli
0.83 s
Downloading 768 MB from MinIO, median of 10 to 30 runs.
proptypedefaultnotes
rowsrequiredRow[]–
unitstring""Appended to every value, e.g. "s" or "MB".
digitsnumber0Decimal places shown.
better"lower" | "higher"–Shown top right as a reading hint.
labelrequiredstring–What the chart shows, for screen readers.
usage
import Figure from "@personal/ui/components/Figure.astro";
import BarChart from "@personal/ui/components/BarChart.astro";
<Figure caption="Downloading 768 MB from MinIO, median of 10 to 30 runs.">
<BarChart
label="Download time by tool"
unit="s"
digits={2}
better="lower"
rows={[
{ label: "s3z", value: 0.254, highlight: true },
{ label: "mc", value: 0.26 },
{ label: "s5cmd", value: 0.368 },
{ label: "aws-cli", value: 0.83 },
]}
/>
</Figure>

flow

components

A left-to-right sequence for architecture sketches. Use unit when every step is its own thing, frame when they share one box, and lane for something that runs alongside all of them.

dark
  1. TorcorchestratorPod
  2. TIFPod
  3. TexamPod
  4. exec 1Pod
  5. exec 2Pod
  6. exec 3Pod
  7. TOFPod

Redis pub/sub between every step

Poiesis v0.1: every step is its own Pod, glued together with Redis.

one Pod

  1. TIF
  2. exec 1
  3. exec 2
  4. exec 3
  5. TOF
  6. ack

TRec, a native sidecar, watches every step

Poiesis v0.2: the same task as one Pod.
light
  1. TorcorchestratorPod
  2. TIFPod
  3. TexamPod
  4. exec 1Pod
  5. exec 2Pod
  6. exec 3Pod
  7. TOFPod

Redis pub/sub between every step

Poiesis v0.1: every step is its own Pod, glued together with Redis.

one Pod

  1. TIF
  2. exec 1
  3. exec 2
  4. exec 3
  5. TOF
  6. ack

TRec, a native sidecar, watches every step

Poiesis v0.2: the same task as one Pod.
proptypedefaultnotes
stepsrequired(string | Step)[]–
framestring–Label for a box drawn around all steps.
lanestring–A bar under the steps for something that spans all of them.
unitstring–Tag shown on every step, e.g. "Pod" when each step is its own Pod.
usage
import Figure from "@personal/ui/components/Figure.astro";
import Flow from "@personal/ui/components/Flow.astro";
<Figure caption="Poiesis v0.1: every step is its own Pod, glued together with Redis.">
<Flow
unit="Pod"
lane="Redis pub/sub between every step"
steps={[{ label: "Torc", note: "orchestrator" }, "TIF", "Texam", "exec 1", "exec 2", "exec 3", "TOF"]}
/>
</Figure>
<Figure caption="Poiesis v0.2: the same task as one Pod.">
<Flow
frame="one Pod"
lane="TRec, a native sidecar, watches every step"
steps={["TIF", "exec 1", "exec 2", "exec 3", "TOF", { label: "ack", highlight: true }]}
/>
</Figure>