Skip to content

Redraw the hero, retire the automaton, and rebuild the catalog - #20

Merged
saudzahirr merged 11 commits into
masterfrom
feat/mark-draw-animation
Aug 17, 2026
Merged

Redraw the hero, retire the automaton, and rebuild the catalog#20
saudzahirr merged 11 commits into
masterfrom
feat/mark-draw-animation

Conversation

@saudzahirr

Copy link
Copy Markdown
Collaborator

What this is

A pass over the whole site: a new hero animation, a page-wide particle
layer, and a content rebuild of the catalog, the community page and the
copy.

The hero

The background was Conway's Game of Life. It was random, permanently in
motion, and said nothing about eggzec. It is now a plate that draws
itself once and holds, built on the technique astral.sh uses behind its
own headline: a filled shape revealed through an alpha track matte of
rounded bars whose widths grow from zero on staggered in-points, with
trimmed strokes tracing in alongside. The bar easing here is read off
that Lottie's own keyframes.

The subject is what we actually build:

  • ∇ℒ traced out of brand/icons/nlpql.svg, the gradient of the
    Lagrangian. The nabla is outlined then filled through its bar matte;
    the script L is a run-merged bitmap in the icon, so it is kept as
    blocks and written on stroke by stroke.
  • A contour plot with a descent stepping to the optimum, a residual
    curve falling to tolerance, a Wiener sample path with pollen off it,
    binary, and the methods set as equations.

All of it is set in eggzec Block, the display font, extended with nine
maths glyphs. bitmapPath now reads its grid from the spec instead of
assuming 5x7, which is what lets those glyphs exist.

One SVG plus CSS keyframes, delays from a --i index per element. No
animation loop, no canvas, no per-frame work once it settles.

Motes

A fixed canvas behind every section holding specks in water. Each one
integrates a damped random walk rather than replaying a keyframe loop,
so the drift wanders instead of oscillating. The cursor pushes them off
it and excites them; they settle about a second later. Reduced motion
gets a single static scatter and no loop at all.

Catalog

polpack, NULAPACK, sparse_grid and cordic are retired. Everything else
carries the name it should be read as. kronrod and spinterp were
published and unmarked, so PyPI goes 10 → 12; PyOpt, bb and ogrep have
same-named packages on PyPI owned by other people and stay unclaimed.
Counts derive from the catalog, so all four stats moved on their own:
15 projects, 12 packages, 10 docs sites, 4 maintainers.

Used by

The shipping carousel listed our own packages back to us. It now shows
seventeen organisations that build on them, as their own GitHub avatars
desaturated at build time.

Every entry was verified one at a time against the live dependency
graph, either the repository's SBOM or its manifest on the default
branch. The dependents index alone was not trustworthy: IBM, PayPal,
TerraPower and NANOGrav all appear in it but declare nothing now, and
nanograv/holodeck only had it as a commented-out line. They are off
the strip.

⚠️ NASA is included on the strength of pyDOE3 in GlennOPT's
manifest
, per the note that pyDOE3 folds back into pyDOE. PyPI does
not show that yet: pydoe3 1.6.2 points at github.com/relf/pyDOE3 and
pydoe2 at clicumu/pyDOE2, both separate from ours. If that merge is
not finished, this is the one entry to pull.

Community and copy

No avatars, handles, badge walls or per-maintainer pages: a name, a
role, a description. Saif ur Rehman added. The footer drops the
maintainer mailto links and the personal email.

Implementation detail is out of the site copy — this is the org site,
not a project site, and the build details live in the API docs.

Checks

npm run typecheck and npm run build pass. Every page was rendered
and inspected at each step.

saudzahirr and others added 11 commits August 17, 2026 18:12
The hero texture was a Conway automaton: pretty, but random, permanently
in motion, and it never said anything about eggzec. astral.sh does the
opposite behind its headline — the logo is one filled shape revealed
through an alpha track matte of rounded bars whose widths grow from zero
on staggered in-points, with trimmed strokes tracing in alongside. It
plays once and resolves into the mark.

This is that construction in eggzec's own geometry. The egg silhouette
from brand/eggzec-mark.svg clips a stack of kiwi bars that grow out from
the centre line and then swell to close the gaps; stepped violet traces
run in from outside the frame and spark magenta where they land on the
outline; the nine byte cells punch in last. Bar easing is read off the
reference's own keyframes.

It is one SVG plus CSS keyframes, delays driven by a --i index per
element, so JS only builds markup and flips animation-play-state when the
host scrolls in. No animation loop, no canvas, no per-frame work once it
settles, and reduced motion gets the finished frame.

Also drops the automaton references from the 404 copy and the README, and
scopes positioning to the SVG rather than the host so the component works
in an in-flow strip as well as an absolute panel.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The plate behind the hero was the egg mark building itself. Pretty, but
it said nothing: the logo is already in the nav, and drawing it twice is
decoration rather than content. What the site is actually about is the
numerics, so that is what the plate draws now.

The anchor is ∇ℒ, traced out of brand/icons/nlpql.svg — the gradient of
the Lagrangian, which is literally what that solver differentiates. The
nabla is outlined and then filled through a bar matte, the way the
reference reveals its own mark; the script L is a run-merged bitmap in
the icon, so it is kept as blocks and written on stroke by stroke.

Around it: a contour plot with a descent stepping to the optimum, a
residual curve falling to tolerance, a Wiener sample path for the SDE
solvers with pollen suspended off it, a block of binary, and the methods
set as equations — gradient descent, Ito, Gauss-Kronrod.

All of it is set in eggzec Block, the display font, extended with the
nine maths glyphs the equations needed. So every glyph on the plate is
drawn on the same grid, with the same merged runs and quarter turns, as
the nabla beside it. `bitmapPath` is now exported and reads its grid from
the spec instead of assuming 5x7, which is what lets those glyphs exist.

Two things worth knowing:

The pollen is the only thing still moving once the plate resolves. It
drifts on three staggered keyframe tracks, transforms only, and stops
dead under prefers-reduced-motion.

Placement transforms and animated transforms cannot share an element. A
CSS transform *replaces* the SVG attribute rather than composing with it,
so every glyph that carries a translate/scale is wrapped in a `<g>` and
the animation runs on the path inside. Without that the whole binary
block collapsed onto the origin, stacked on top of itself.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sixteen of the nineteen repositories are scientific computing, so that
claim stays. But ogrep, bb and gnspy are not numerics, some of it is Go
rather than Python, and the hero admitted none of that — the lede opened
"We build the numerical layer" and never came back from it.

The headline now runs to four lines. Block lettering fits every line to
one rendered width by solving for tracking, so lines have to stay in a
similar character range: TOOLS on its own would have been stretched to
the width of COMPUTING AND and read as broken. 11/10/13/16 is the split
that holds. Knockouts move with it, to the N of OPEN and the T of TOOLS.

Four lines also want less height than three, so the display is held back
from the full measure rather than run edge to edge.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The plate carries a few grains off its Wiener path. This is that at page
scale: a fixed canvas behind every section, holding pollen in water. The
page scrolls past it rather than dragging it along, which is what looking
through a glass actually looks like.

Each grain integrates a damped random walk — momentum, plus a fresh
impulse every frame — rather than replaying a keyframe loop. That matters
for how it reads: a looped path oscillates and the eye locks onto the
period, while an integrated walk wanders and never repeats.

The cursor is a disturbance in that water. Grains inside its radius are
pushed off it with a force that falls away with distance, and they
excite: brighter, swollen, spun up, and switched from their soft dot to
the sharp pixel form. Excitement decays on its own, so a grain is back to
drifting about a second after the cursor has left.

Two things that needed bounding. Push is capped and speed is clamped, or
a fast cursor flings grains off screen and the field thins out. And the
void the cursor carves is left to refill by diffusion rather than by
pulling grains home — that is what the walk is for, and a restoring force
would have made it read as elastic instead of suspended.

One canvas, one loop, one pass per frame; it stops with the tab, and
under reduced motion it never starts at all — that case gets a single
static scatter, which keeps the texture and drops the movement.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
They were reading as content: pixel squares and crosses big enough to
look deliberate, competing with the plate rather than sitting behind it.
Now they are small circles and nothing else — at this size anything with
a corner reads as an artefact — fainter, and denser to compensate.

Renamed from pollen to motes on the way through. The plate's grains off
the Wiener path are the pollen; these are page dust, and having one word
for both made the two hard to talk about.

Dropping shape and rotation also drops the per-speck transform stack: the
paint pass is now one arc each, no save/restore.

Position was already right — a fixed layer at a negative z-index sits
behind every section and behind the hero plate, which is its own stacking
context. Nothing needed moving; they just needed to stop shouting.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The rename to motes updated the markup but not the stylesheet: the class
selector stayed .pollen while the canvas started emitting class="motes".
With no rule matching, the canvas lost position, z-index and sizing, and
fell back into normal flow at the top of the document — above the header,
drawing specks over it. That is what shipped in the previous commit.

The edit that renamed it matched on LF while the file is CRLF, so the
replacement silently did nothing. Typecheck and build both passed, since
neither has any idea whether a class name resolves.

Also masks the field out of the band the header occupies. The bar is only
78% opaque with a backdrop blur, so once the canvas was behind it again,
specks still read through the glass as though they were on it — and at
the top of the page there is no content behind the bar, so they were the
only thing showing through. The mask measures against the tallest,
unscrolled header height, so the exclusion holds when it shrinks.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Content pass across the whole site.

Catalog. polpack, NULAPACK, sparse_grid and cordic are deprecated and
gone. Every project now carries the name it should be read as — PyDOE,
MCERP, SOERP, PySwarm, NLPQL, SDEPack, SmolPack, Kronrod, Vatic — while
ad, bb, gnspy, ogrep and spinterp keep their lowercase names because that
is what they are called. New icons for kronrod, smolpack, spinterp and
vatic; the other nine already matched the assets exactly.

kronrod and spinterp are published and were not marked as such, so PyPI
goes from ten to twelve. PyOpt, bb and ogrep have same-named packages on
PyPI that belong to other people, so they stay unclaimed. Every count on
the site is derived from the catalog, so all four stats moved on their
own: 15 projects, 12 packages, 10 docs sites, 4 maintainers.

Used by. The shipping carousel listed our own packages back to us, which
proves nothing. It now lists the projects that depend on them, read off
GitHub's dependency graph and checked one repository at a time against
the API: NASA, LLNL, Sandia, LANL, IBM, PayPal, TerraPower, NANOGrav,
CMU and others. Only pydoe (1,203 dependents), pyswarm, mcerp and soerp
have any at all, and individual paper repos are filtered out — they are
real dependents but they are not what "used by" is claiming. Each entry
links to the repository, because a claim like this is only worth making
if it can be checked.

The toolchain section is gone with it. Naming our own build tools was
inward-facing in the same way.

Community. No avatars, no handles, no badge walls, and no per-maintainer
pages: a name, what they do here, and how they describe their work. The
card links to their GitHub rather than to a page about them. Saif ur
Rehman added. The footer drops the maintainer mailto links and the
personal email address.

Copy. The hero lede stopped reciting the Fortran-and-C++ paragraph, and
so did the org blurb and the meta description. The catalog page also
drops its featured block — thirteen of fifteen projects carry an icon
now, so "featured" separated nothing and showed the same card twice.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Which projects lead was computed from which ones had a brand icon. Nearly
all of them do now — fourteen of fifteen, with gnspy's icon added here —
so that signal had stopped selecting anything and the grid was just the
catalog again.

`LEAD` names them explicitly and in order: PyDOE, ad, PySwarm, SOERP,
MCERP, bb. What a first-time visitor sees first is a decision, so it is
written down as one. The nav menu takes the first four from the same
list.

Note the display names stay lowercase for ad and bb, per the naming pass
— they are written in caps in the request the way one writes an
identifier, not a label.

Of the fifteen icons in the asset folder only gnspy differed from what
was already committed; the rest are byte-identical.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The strip listed repository names ranked by stars, taken from GitHub's
dependents index. That index turned out not to be trustworthy on its own:
several entries had since dropped the dependency, and nanograv/holodeck
only had it as a commented-out line.

So every entry here was checked one at a time against the live dependency
graph, either the repository's SBOM or its manifest on the default branch.
Anything that could not be confirmed was left off however good the name
would have looked, and that cost some big ones: IBM, PayPal, TerraPower
and NANOGrav all appear in the dependents index but declare nothing now.

Seventeen organisations survived, shown as their own GitHub avatars
desaturated at build time rather than in CSS, so the strip stays even and
nothing flashes colour while it loads. Orgs whose avatar is an identicon,
a photograph or clipart were dropped: a logo strip only works with logos.

NASA is included on the strength of pyDOE3 in GlennOPT's manifest, per
the note that pyDOE3 folds back into pyDOE. Worth knowing that PyPI does
not show that yet: pydoe3 1.6.2 still points at github.com/relf/pyDOE3,
and pydoe2 at clicumu/pyDOE2, both separate from ours. If the merge is
not finished, that one entry is the one to pull.

Also drops the implementation detail from the pillars and the catalog
callout, per the note that this is the org site and not a project site,
takes the dash out of the used-by tooltip, updates the pyswarm tagline,
refreshes the gnspy icon, and sets Noor's and Saif's descriptions.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Bumped from 34px to 52px. Worth recording what the check turned up:
GitHub's own "Used by" widget runs at 24px, which is *smaller* than what
we had, because it is a dense sidebar list of user avatars. This is a
landing-page logo strip doing a different job, so matching that number
would have made visibility worse rather than better. Roughly double it
is the right answer for marks meant to be recognised in passing.

Hover darkens the logo and does nothing else. The strip is moving, so
anything that changes size or position under the cursor reads as a
glitch rather than as feedback.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@saudzahirr
saudzahirr merged commit 5300f4d into master Aug 17, 2026
2 checks passed
@saudzahirr
saudzahirr deleted the feat/mark-draw-animation branch August 17, 2026 18:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant