feat: directory-tree hero + GSAP motion for structlint - #26
Merged
Conversation
Replace the generic terminal-window hero (shared verbatim across every
AxeForge marketing site) with a hero built around structlint's actual
mechanism: an animated directory tree with connecting branch lines and
one node flagged as a violation, matching the "directory drift" framing
in the product copy.
- New centerpiece: a hand-authored file tree (myapp/, cmd/main.go,
internal/{domain,db}, go.mod, .env.local) drawn with plain CSS
rail/elbow connectors (no SVG, no terminal chrome), with .env.local
flagged via accent color + a visible disallowed_file_pattern badge and
a CLI-style verdict line, grounded in the real --disallowed rule and
frozen violation codes from README.md.
- GSAP (CDN) drives: a hero entrance timeline (kicker -> h1 -> lede ->
ctas -> tree panel), a top-down tree "draw-in" (branches extend via
scaleY/scaleX, nodes fade in row by row) with the flagged node
pulsing once revealed, and once-per-section scroll reveals for the
card grids below the fold.
- Reduced motion is a hard branch via gsap.matchMedia(): nothing is
ever hidden by CSS, so a failed/blocked CDN load or
prefers-reduced-motion both leave the page fully visible immediately
with zero animation -- verified via Playwright's reduced-motion
media emulation (opacity 1, tree fully drawn, no tween).
- Brand shell (topbar, footer cross-links, SEO/JSON-LD, axeforge.css
tokens) untouched; side-by-side hero layout kept, only the
centerpiece and composition change.
✅ PR title follows the required formatCurrent title: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
The marketing site's hero used the same layout as the other four AxeForge
sites built this session: kicker/h1/lede/ctas on the left, a terminal-window
demo box on the right. This PR keeps the brand shell (topbar, footer
cross-links, SEO/JSON-LD,
axeforge.csstokens) untouched but givesstructlint its own hero centerpiece and adds GSAP motion.
New hero concept: an animated directory tree with a flagged violation
Replaced the terminal-window demo with a hand-drawn directory tree (plain
CSS rail/elbow connectors, no SVG, no terminal chrome/dot title bar) showing
a sample project:
.env.localis visually flagged (accent border/tint + a visibledisallowed_file_patternbadge + a CLI-style verdict line), grounded in theactual
disallowed: ["*.env*", ...]rule and the frozen violation codesdocumented in
README.md. This matches structlint's real "directory drift"framing much better than a generic scrolling log ever did. Layout stays
side-by-side (text-left, diagram-right) — only the centerpiece changed.
GSAP motion (CDN: gsap@3.12.5 + ScrollTrigger)
staggered on load.
(
scaleY/scaleX0→1) and its node fades in, row by row; the flagged.env.localnode pulses once revealed.translateY in, staggered, once per section (
ScrollTriggeronce: true—doesn't replay on scroll-up).
gsap.matchMedia()branches onprefers-reduced-motion. Nothing is ever hidden by CSS — only JS appliesautoAlpha:0/scale:0initial states, and only inside theno-preference branch — so a blocked/slow CDN load or reduced motion
both leave the page fully visible immediately, zero animation. Verified
via Playwright's
reduced_motion="reduce"emulation: computedopacity: 1on every hero/tree/section element, tree lines at fullscale, no tween.
Verification
web/locally, screenshotted at 1440×1600 and 375×1400 (Playwrightbefore capture — headless
--virtual-time-budgetdoesn't reliably driveGSAP's ticker, so raw CLI screenshots mid-animation aren't representative).
Read every image: tree renders correctly, violation node reads clearly,
no terminal-window silhouette left, hero collapses to one column on
mobile, all section reveals resolve to fully visible after scroll.
document.documentElement.scrollWidth === clientWidthconfirmed at both375px and 1440px — no horizontal overflow.
node detect.mjs --json(impeccable anti-pattern detector): identicaladvisory findings to the pre-existing
mainfile (grid background,single-font false-positive, em-dash density) — no new anti-patterns
introduced.
Playwright console/pageerror listeners).
score:
connector lines are
aria-hidden; the tree<ul>has a descriptivearia-label; violation info is conveyed via visible text/badge, nothover-only; no focusable elements ever left in a hidden pre-reveal state.
<body>(non-blocking); all animation uses transform properties(
x/y/scale) per GSAP performance guidance, no layout thrashing.var(--af-*)or reusesalready-audited semantic tones (
feed-tone-*); no new hardcoded colors.shrinks font/rail width under 480px; violation badge wraps onto its own
line via
flex-basis: 100%.fully visible with zero JS/GSAP failure);
ScrollTriggerreveals fireonce per section via
once: true, no replay on scroll-direction change.No Co-Authored-By line.