jaeaeich/components

components

Every piece the writing on jaeaeich.com is made of, rendered by the same pipeline the posts use and shown in both themes side by side. Plain Markdown covers most of it, and the rest is a handful of Astro components that drop straight into an .mdx post.

colours

foundations

Every colour is a CSS variable, and dark and light share the same names, so a component never has to pick a colour itself.

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 carries the structure (labels, meta, code) and IBM Plex Sans carries the reading, across seven sizes with 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 of it 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 and mono numbers, and items that open 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, set in 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, the table scrolls sideways on narrow screens rather than squashing, and a colon in the divider row right-aligns a number column.

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, plus a three-dot divider (a plain ---) between the 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 on their own, and a console block (a session with output) highlights only the $ lines 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 that", with new lines in orange and removed lines fading 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

An aside with a rule down the left instead of a box: note for context, warn for a trap, lesson for the takeaway, and 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, wrapped in Stats so they sit between two hairlines and reflow on a phone.

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 an optional credit; pass src for an image, or put a chart or 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 150" 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="52">before</text>
<text x="24" y="112">after</text>
<text x="596" y="52" text-anchor="end" fill="var(--fg)">1,566 MiB</text>
<text x="132" y="112" fill="var(--fg)">85 MiB</text>
</g>
<rect x="84" y="36" width="420" height="22" rx="1" fill="var(--line-strong)" />
<rect x="84" y="96" width="23" height="22" rx="1" 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 that reads like a word in the sentence, instead of a commit hash or a long GitHub URL.

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 as plain hash-prefixed words; 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, with your own highlighted; it is plain HTML, so it follows the theme and screen readers get a list, and a Figure gives it 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: 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>