changes
Some checks failed
Deploy / build-deploy (push) Has been cancelled

This commit is contained in:
Jorijn van der Graaf 2026-08-05 22:32:03 +02:00
commit 054a26475c
4 changed files with 33 additions and 37 deletions

View file

@ -96,42 +96,42 @@ export const std::vector<Project>& Projects() {
"imsd",
"IMS/VoLTE for the Fairphone 6's Qualcomm modem: calls on a mainline-Linux phone.",
"https://forgejo.catcrafts.net/Catcrafts/imsd",
"C++23",
"C++",
true,
},
{
"Crafter.Graphics",
"A C++23 rendering engine: Vulkan with hardware ray tracing natively, WebGPU in the browser.",
"A C++ rendering engine: Vulkan with hardware ray tracing natively, WebGPU in the browser.",
"https://forgejo.catcrafts.net/Catcrafts/Crafter.Graphics",
"C++23 modules",
"C++ modules",
true,
},
{
"Crafter.Build",
"A build system with no DSL: the build description is a C++ file, compiled and run.",
"https://forgejo.catcrafts.net/Catcrafts/Crafter.Build",
"C++23 modules",
"C++ modules",
true,
},
{
"Crafter.Network",
"A QUIC and HTTP/3 stack; the same client code runs natively and in the browser.",
"https://forgejo.catcrafts.net/Catcrafts/Crafter.Network",
"C++23 modules",
"C++ modules",
false,
},
{
"catcrafts.net",
"This website, C++23 compiled to WebAssembly, server-rendered from the same renderers.",
"This website, C++ compiled to WebAssembly, server-rendered from the same renderers.",
"https://forgejo.catcrafts.net/Catcrafts/catcrafts.net",
"C++23 modules",
"C++ modules",
false,
},
{
"Crafter.Asset",
"Texture and mesh pipeline to GPU-friendly formats, decoded on the GPU where possible.",
"https://forgejo.catcrafts.net/Catcrafts/Crafter.Asset",
"C++23 modules",
"C++ modules",
false,
},
};
@ -143,7 +143,7 @@ export const std::vector<Demo>& Demos() {
{
.slug = "raytracer",
.name = "Real-time ray tracer",
.blurb = "Hardware-accelerated ray tracing through WebGPU, driven by the same C++23 WebAssembly module that renders this page. Four coloured lights, one shadow ray each, Reinhard tonemapping.",
.blurb = "Hardware-accelerated ray tracing through WebGPU, driven by the same C++ WebAssembly module that renders this page. Four coloured lights, one shadow ray each, Reinhard tonemapping.",
.tech = "WebGPU compute + WGSL",
.needs = "WebGPU: Chrome 121+, Firefox 141+, Safari 26+",
.mountId = "webgpu-demo",

View file

@ -42,7 +42,7 @@ public:
SafeHtml(std::string_view) = delete;
// Str() returns a reference (not a copy) because Format() feeds these
// to std::make_format_args, which in C++23 binds Args&... and therefore
// to std::make_format_args, which in C++ binds Args&... and therefore
// needs lvalues.
const std::string& Str() const noexcept { return v_; }
std::string_view View() const noexcept { return v_; }

View file

@ -111,7 +111,7 @@ export SafeHtml RenderFooter() {
return Format(
R"(<div class="footer-content">)"
R"(<p class="footer-tagline">Open-source systems work from the Netherlands. )"
R"(This site is C++23 compiled to WebAssembly.</p>)"
R"(This site is C++ compiled to WebAssembly.</p>)"
R"(<p class="footer-links">)"
R"(<a{}>Forgejo</a><a{}>Source</a>)"
R"(</p>)"
@ -189,22 +189,21 @@ export RenderedPage RenderHome(std::span<const Project> projects,
SafeHtml main = Format(
R"(<section class="hero">)"
// No visible headline on purpose: a hero slogan reads as marketing,
// which is not the register this site wants. The h1 stays for the
// document outline (screen readers, crawlers) but is visually hidden;
// the mission text below is the first thing anyone sees.
R"(<h1 class="visually-hidden">Catcrafts</h1>)"
R"(<p class="hero__lede">Catcrafts makes accessible, open-source software )"
R"(and hardware for the benefit of everyone. The goal: a real alternative )"
// No slogan on purpose: a hero headline reads as marketing, which is
// not the register this site wants. Instead the mission sentence IS
// the h1 — full weight in the document outline and for crawlers —
// styled as body prose (see h1.hero__lede) so nothing on screen
// changes register. The old version hid a one-word h1 offscreen,
// which spent the strongest heading on the page saying "Catcrafts"
// to nobody.
R"(<h1 class="hero__lede">Catcrafts makes accessible, open-source software )"
R"(and hardware for the benefit of everyone.</h1>)"
R"(<p class="hero__lede">The goal: a real alternative )"
R"(to big tech that anyone can use, not just Linux nerds.</p>)"
R"(<p class="hero__actions">)"
R"(<a class="btn btn--primary"{}>Browse projects</a>)"
R"(<a class="btn"{}>Browse shop</a>)"
R"(</p>)"
// The person-company weld, human-readable edition. The about page
// and the Organization founder record are the machine-readable one.
R"(<p class="hero__byline">Catcrafts is the one-person company of )"
R"(<a{}>Jorijn van der Graaf</a>.</p>)"
R"(</section>)"
R"(<section class="section">)"
R"(<h2 class="section__title">Featured work</h2>)"
@ -213,7 +212,6 @@ export RenderedPage RenderHome(std::span<const Project> projects,
R"({})",
Url("href", "/projects"),
Url("href", "/shop"),
Url("href", "/about"),
cards.empty() ? Raw(R"(<p class="empty">No featured projects yet.</p>)") : Join(cards),
recent.empty() ? SafeHtml{} : Format(
R"(<section class="section">)"
@ -227,7 +225,7 @@ export RenderedPage RenderHome(std::span<const Project> projects,
page.meta.title = "Catcrafts — open-source software and hardware";
page.meta.description =
"Catcrafts makes accessible, open-source software and hardware: an "
"alternative to big tech. A C++23 engine, build system and networking "
"alternative to big tech. A C++ engine, build system and networking "
"stack from scratch, and Linux with IMS/VoLTE on the Fairphone 6.";
page.meta.canonical = "/";
// The identity record: name, registered VAT identity and the Forgejo
@ -241,7 +239,7 @@ export RenderedPage RenderHome(std::span<const Project> projects,
R"("founder":{"@type":"Person","name":"Jorijn van der Graaf",)"
R"("url":"https://catcrafts.net/about"},)"
R"("description":"Catcrafts makes accessible, open-source software and hardware: )"
R"(the Crafter C++23 suite, the imsd IMS/VoLTE implementation, and Fairphone 6 )"
R"(the Crafter C++ suite, the imsd IMS/VoLTE implementation, and Fairphone 6 )"
R"(handsets sold with postmarketOS preinstalled.",)"
R"("sameAs":["https://forgejo.catcrafts.net/Catcrafts/"]})";
page.main = std::move(main);
@ -271,7 +269,7 @@ export RenderedPage RenderProjects(std::span<const Project> projects) {
RenderedPage page;
page.meta.title = "Projects — Catcrafts";
page.meta.description =
"The Crafter suite: a C++23 build system, graphics engine, networking "
"The Crafter suite: a C++ build system, graphics engine, networking "
"stack, and an IMS/VoLTE implementation for the Fairphone 6.";
page.meta.canonical = "/projects";
page.main = Format(

View file

@ -268,16 +268,21 @@ treatment it replaces, which read as the wrong category for the work.
.nav-link--active { color: var(--accent); }
.nav-link--active:hover { color: var(--accent-hover); }
/* hero no headline by choice: the h1 is visually hidden (see RenderHome)
and this paragraph opens the page, so it gets full text colour and a size
step up from body copy rather than the muted supporting-text treatment it
had when a title sat above it. */
/* hero no VISIBLE headline by choice: a slogan-shaped heading is the
marketing register this site refuses. The mission sentence itself is the
h1 (document outline, crawlers) but wears body-prose clothes: same size
step, weight and rhythm as the paragraph that completes it, so the two
render as one block of text. */
.hero { max-width: var(--measure); }
.hero__lede {
font-size: var(--step-1);
color: var(--text);
text-wrap: balance;
}
h1.hero__lede {
font-weight: 400;
line-height: inherit;
}
.hero__actions {
margin-top: var(--s1);
display: flex;
@ -902,13 +907,6 @@ treatment it replaces, which read as the wrong category for the work.
/* ─── utilities ─────────────────────────────────────────────────────── */
@layer utilities {
.visually-hidden {
position: absolute;
width: 1px; height: 1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.text-muted { color: var(--text-muted); }
}