Add Three.js hero animation and refine gradient styling - #2
Merged
Conversation
The hero's static Squares.png is replaced by an animated Three.js recreation of the brand mark: the diamonds tumble at screen center on load, the backdrop fades to reveal the page as they settle into the image's original spot, then they track scroll with a subtle rotation wobble and fade out once off-screen. Falls back to the static image when JS/WebGL is unavailable or prefers-reduced-motion is set. Also swaps the remaining Bootstrap-grey gradients in the blog styles (post headings, blockquotes, series sidebar, drop-cap) for the site's own palette tokens. Marks the layout's external Bootstrap/GitHub-card scripts as is:inline so Astro's script bundler doesn't merge them into the same module chunk as the new hero script.
Replace the tumbling-diamond intro with what was actually asked for: all five pieces start stacked as one plain, rounded white square at screen center, then explode outward into the brand mark's stacked diamonds (fading from neutral to each piece's real color as they separate) and settle at the original bottom-left spot, at a constant size throughout instead of scaling up mid-animation. Also switches the flat-cornered planes for a proper rounded-square shape geometry, matching the corner radii in the source Squares.svg instead of sharp rectangles.
Deploying y-a-s with
|
| Latest commit: |
5c8355f
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://2d67a769.y-a-s.pages.dev |
| Branch Preview URL: | https://claude-threejs-animations-bl.y-a-s.pages.dev |
On mobile the hero square is sized by viewport width (.white-square: 100vw x 100vw), but the hero container itself (#home) was still forced to 100vh via Bootstrap's vh-100 utility. Since 100vw is much shorter than 100vh on a typical phone, this left several hundred pixels of bare dark background between the hero content and the page panel below it. Cap #home to the same 100vw on mobile so the hero's height actually matches its content.
Extends the existing hero canvas with four small, low-opacity brand squares anchored near the screen corners. They fade in once the main logo settles, then each drifts upward at its own parallax speed as the page scrolls, fading out based on how far it has actually travelled (so faster squares don't get cut off before slower ones arrive). Carries the squares motif beyond the hero as a subtle, persistent visual identity element rather than a one-off intro animation.
The project cards used Bootstrap's default rounded/shadowed .card look with off-brand purple/blue gradients and stock blue/gray buttons — the one part of the site that still looked like an unstyled template next to the custom hero and blog styling. Bring them in line with the sharp-corner, left-accent-border-on-hover treatment already used by post-preview cards and the project detail sidebar, and swap the image overlay gradient and buttons for the site's own palette. Also drop the unused `github-card` custom-element script from the layout (dead code — no page ever uses that element, just an extra external script on every load), and trim the footer's team list down to a single entry.
The diamond stack was anchored to the raw column edge, bleeding flush against the left edge of the screen instead of sitting inset with the rest of the hero content (the Y-A-S heading, nav pill). Anchor it to the bordered frame's edge plus the diamond's own half-width instead, so it lines up like everything else in the hero. Drop the ambient corner squares added earlier — they read as small, distracting light artifacts rather than a clean accent. Replace the old "track the DOM slot and fade out after a bit of scroll" behavior with a sticky one: once the logo settles it stays pinned on screen, and adds three new sample content sections (How We Work, Talks & Presentations, Why Y-A-S) plus tags the existing Blog CTA section, each wired to a scroll-driven "removal" progress computed from its own position in the viewport. Crossing into a new section peels one square off the top of the stack (spin, shrink, fade, drift up) using the same ease() curve as the intro explosion; scrolling back up brings it back since the effect is a continuous function of scroll position, not a one-shot trigger. The last (neutral) square has no section of its own and fades out only once you're near the very bottom of the page, so nothing lingers stuck over the footer.
… off The stack was rendering navy-on-top, neutral-on-bottom — backwards from both the source Squares.svg and the reference the user sent (neutral top, green, blue, red, navy bottom). Flip the row-to-position mapping to match. Replace the "peel off top-down and fly away" scroll effect with a simpler one: each square now maps directly to one of the 5 content sections in order (intro, How We Work, Talks & Presentations, Why Y-A-S, Blog CTA), and shrinks in place — no drift, no extra spin — as its matching section scrolls into view. Tint each section's background with that same square's color at low opacity plus a matching left accent border, so scrolling down visually echoes the logo's own color order. Force every square down to its smallest size once the footer itself scrolls into view, since the last section's own threshold isn't always reachable on a short page and would otherwise leave a full-size square overlapping the footer branding. Left the settle size alone per request (matches what's currently deployed). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011eJ9XiGRuA6XnpgdwYtaiw
…e; drop border seams Turn each of the 5 content sections into a full-width, full-height screen instead of a short block inside the centered content column, using the standard position:relative/left:50%/negative-margin bleed trick so the color wash spans edge to edge while the actual text stays readable at the original max-width. Guard .yas-page-canvas with overflow-x:hidden since 100vw can include scrollbar width on some browsers. Shrink the logo squares (scale multiplier 1.05 -> 0.7) and anchor them to the bordered hero frame on the bottom edge too, not just the left, so the stack sits fully inside the border lines on every side instead of just horizontally. Each square was rendered as a lighter outer "frame" plane behind a smaller colored one, so wherever two overlapping diamonds met in the stack, a light seam showed at the boundary between colors. Replace the two-mesh frame+fill pair with a single flat-colored plane per row — there's no separate border layer left to interrupt, so adjacent colors now overlap cleanly. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011eJ9XiGRuA6XnpgdwYtaiw
Each settled square now raycasts against pointer events (the canvas itself stays pointer-events:none) so hovering shows a tooltip naming its section and clicking scrolls smoothly to it. The side-to-side scroll wobble is removed now that clicking is the primary interaction. Also restores the neutral outer-frame layer from the brand SVG using opaque (non-transparent) materials instead of the previous single-mesh version, so real depth occlusion hides the frame wherever squares overlap and only each diamond's exposed edge shows a border — matching the original artwork instead of drawing a full ring per square. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011eJ9XiGRuA6XnpgdwYtaiw
The stacked squares were spaced too tightly, burying most of each diamond under the next one. Squares.svg spaces rows so each diamond's tip lands just past the midline of the one above it, ending visibly inside it rather than disappearing almost entirely — the corrected 0.6421 step ratio (measured from the SVG) restores that look, with diamond size now also capped by the column's available height so the taller stack still fits inside the frame. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011eJ9XiGRuA6XnpgdwYtaiw
Suppress the neutral outer-frame mesh's color output (colorWrite: false) instead of removing it: it stays in the scene for correct depth occlusion between rows and remains a valid click/hover target, it just no longer paints a visible border, so the diamonds interlock with clean edges and no ring at the seams. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011eJ9XiGRuA6XnpgdwYtaiw
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.
Summary
This PR adds an interactive 3D hero animation using Three.js to replace the static Y-A-S logo squares on the homepage, while also refining gradient colors throughout the site for better visual consistency.
Key Changes
Hero Animation: Added a Three.js-powered 3D animation that:
prefers-reduced-motionfor accessibilityStyling Updates:
.heading-gradientto use CSS variable--danger-colorinstead of hardcoded#ff6b6b.series-introbackground gradient to use a subtle green tint with white.series-statsand blockquote gradients to use--main-light-colorvariable for consistencyDependencies: Added
three@^0.185.1to support the 3D animationScript Loading: Updated external scripts in BaseLayout to use
is:inlineattribute for proper Astro handlingImplementation Details
The animation uses an orthographic camera to render 5 layered square meshes with staggered positions. It features a two-phase animation: an initial 500ms spin phase followed by a 1400ms easing transition that moves squares to their final position while fading out the background. Once settled, the animation tracks the fallback image's position in the viewport, enabling scroll-synchronized effects.
https://claude.ai/code/session_011eJ9XiGRuA6XnpgdwYtaiw