Effects & Interactions
Every effect in Rasuke is a small ES module in src/assets/js/, imported once by main.js and booted only when its markup exists. Timings and distances come from motion / layout tokens, pre-reveal states live in SCSS under .js (no FOUC), and every module honours prefers-reduced-motion. This page is the catalog; GSAP and Three.js cover the engines.
Page chrome
| Effect | What it does | Source · Hook |
|---|---|---|
| Preloader | Branded intro: RASUKE wordmark staggers in, a big outlined counter rolls 0→100 with rotating status words (Loading / Crafting / Composing → Ready), then the panel wipes away and hands over to the hero. Pauses ScrollSmoother while active; can run once per session. | preloader.js → preloader/Preloader.js · [data-preloader], data from preloader.json |
| Page transition | Between navigations #smooth-wrapper collapses to a point at its centre (same clip language as the offcanvas menu), uncovering a dark backdrop; the new page grows back out of that point. Prefetches internal links. | transition.js · partials/page-transition.njk, transition.json |
| Custom cursor | Comet cursor: a head disc with a sampled trail that shrinks/fades behind it. Over [data-cursor] targets it becomes a labelled disc; press scales it down. Disabled on touch / coarse pointers and for reduced motion. | cursor.js · partials/cursor.njk, cursor.json |
| Offcanvas menu | Fullscreen menu that opens with a centre-out polygon clip, oversized display links, secondary links, and the dark/light theme switch. Locks the smoother while open. | offcanvas-menu.js · partials/offcanvas-menu.njk, offcanvasMenu.json |
| Main navigation pill | Floating pill (header-1 pages) that stays hidden until you scroll past the token threshold, appears while scrolling up, and leaves on scroll down. | main-navigation.js · partials/main-navigation.njk + nav-primary.njk |
| Back to top | Appears after 200px (and near the page bottom), hides on upward scroll at the top; smooth-scrolls via ScrollToPlugin / the smoother. | back-to-top.js · partials/back-to-top.njk |
| Dark / light toggle | See Dark Mode. | public/assets/js/vendors/color-modes.js · [data-color-scheme-toggle] |
Text & reveal system
| Effect | What it does | Hook |
|---|---|---|
| Text mark (top / left) | Masked line reveals — lines drop in from above (text-mark-top.js) or uncover left-to-right (text-mark-left.js), SplitText line splitting after fonts load. Gated on the preloader reveal. | .text-mark-top / .text-mark-left (explicit __line children preferred) |
| Blur letter stagger | Letters start blurred and offset, then settle word-by-word (word wrappers prevent mid-word line breaks). | .text-blur-stagger |
| Text flip | Character-swap hover for links/CTAs (headers, projects-1, blog-1, footer links): each char slides up and its duplicate takes its place; leave reverses from the end. | .text-flip (hover target is the wrapping link) |
| Hero 2 title rotate | The last headline word cycles build → launch → optimize → maintain: outgoing chars lift + fade, incoming chars rise with a slight 3D tilt, ~2s hold per word. | [data-hero-2-rotate] |
| Stagger reveal | Generic scroll-in system: items fade + rise, optional media opens with a centre-out curtain wipe, optional zoom settles. Tunable per container. | [data-stagger] > [data-stagger-item] (+ data-stagger-media, data-stagger-zoom, data-stagger-y/-each…) |
| Grid wipe | Media (and big text, in footer-2) uncovered by a grid of cells wiping in from top/bottom — used for image reveals and headline entrances. | .grid-wipe, .grid-wipe--text |
| Zoom-in reveal | Orisa-style: target is wrapped in an overflow-hidden wrap, scales from 1.2 + faded to natural size on entry. | .anim-zoomin |
| Digit count | GSAP digit roll — see Digit Count. | .digit-count |
Scroll & media
| Effect | What it does | Hook |
|---|---|---|
| ScrollSmoother | Whole-page inertia smoothing (1.35 lag, same for touch), effects: true enables data-speed / data-lag in markup. | #smooth-wrapper (in main.js) |
| Scroll parallax | Oversized layers drift across their spare height while the frame crosses the viewport; the reveal zoom stays on the inner media so transforms never fight. | .scroll-parallax, [data-img-1-parallax] (img-1), [data-about-2-parallax] (about-2) |
| Scroll move up | Scrubbed translateY(-100px) drift, desktop ≥ lg only. | .scroll-move-up |
| Marquee | Infinite ticker: auto-scrolls, pointer-drag to scrub, seamless wrap. Three ready instances share one engine. | Testimonials (testimonials-1), hero-3, brands-1 — [data-*-marquee] > track > group |
| Lazy video | Ambient <video data-src> keeps its poster until it can play (ScrollTrigger-driven); a failed file drops the source so the poster stays. Autoplay is skipped on iOS WebKit / reduced motion. | video[data-src] |
| Lightbox | GLightbox with inline-video handling — see GLightbox. | GLightbox selectors in markup |
| Grid / hover deformation | Three.js per-pixel image deformation — see Three.js. | .hover-deform, grid-deform markup |
Section interactions
| Section | Interaction | Source |
|---|---|---|
| Hero 1 | Intro rise/fade after the preloader; 3-image gallery — middle zooms into place, outers open out on scroll, middle drops into the gap. | hero-1-intro.js, hero-1-gallery.js |
| Hero 2 | Whole hero rises in; rail email wipes open, social hits stagger; rotating last word (above). | hero-2-intro.js, hero-2-title-rotate.js |
| Projects 1 | Cards scale 0.8 → 1 on entry and reverse on exit, both directions; text-flip CTA. | projects-1.js |
| Services 1 / Service detail 2 | Hover/focus a row → the intro visual crossfades (+ scales) to that row's still; leaving returns to the first. | services-1.js, service-detail-2.js |
| Services 2 | Same crossfade, plus the hover-deform lens re-samples the active still. | services-2.js |
| Services 4 | Scanning the list swaps both gutter stills per row and floats a tilt-damped scope panel beside the pointer (desktop pointers only). | services-4.js |
| Team 1 | “Center-out iris”: items lift in, round portraits open with a circular clip wipe, name/role rise last; fans from the middle on desktop. | team-1.js |
| Why-us 1 | Platform name wipes left-to-right; award/year rows slide in from opposite sides like a ledger. | why-us-1.js |
| Awards 1 | Cursor-following preview frame: lerped trail, inner image drifts against the lag, per-row zoom + Ken Burns swap. | awards-1.js |
| Blog 1 / Blog posts | Editorial reveals: items rise, media uncovers with a directional curtain wipe + slow zoom, title/byline blur-to-sharp last. | blog-1.js, blog-posts.js |
| FAQs 1 & 3 | Native <details> accordions upgraded in JS: height glide, one row open at a time (faqs-3 also fades/lifts the copy). Fully usable with JavaScript off. | faqs-1.js, faqs-3.js |
| Footers 1–3 | Assembled entrances on entry: curtain headline, rising columns/forms with link cascades, scrubbed backdrop parallax (footer-1). | footer-1.js, footer-2.js, footer-3.js |
| Project filter | Discipline filter shared by the listings: [data-project-filter] buttons pair with [data-project-category] cards across sections; cards hide by class so reveals/reflow stay intact. | project-filter.js |
| Listing 4 | Hover opens the still inside the row; on coarse pointers a tap activates the row instead (one at a time). Reveal itself is CSS. | project-listing-4.js |
| Listing 5 | Typographic index with a floating print: two image layers cross-dissolve as you scrub the list; the stage drifts a few damped pixels against the pointer. | project-listing-5.js |
Project showcases (fullscreen, one per page)
| Page | Mechanics | Source |
|---|---|---|
| Showcase 1 | Slider: CSS cross-fades, looping autoplay + thumbnails with a sweeping progress ring; mouse wheel steps (40px) restart the cycle. | showcase-1.js |
| Showcase 2 | Fullscreen editorial carousel driven by one float (state.progress) with circular distance per slide; WebGL skin adds the seam / channel-split transition. Wheel, drag, and keyboard share the same float. | showcase-2.js + showcase-2-gl.js |
| Showcase 3 | Split-reverse rail: image rail reads +offset, copy rail −offset from the same progress value — halves can never drift apart; wraps circularly. | showcase-3.js |
| Showcase 4 | Fullscreen hover reel: an unclamped position float places every title by circular distance; scroll, drag, keyboard, and focus ring all read the same value. | showcase-4.js |
| Showcase 5 | Creative grid: the narrow portrait column drifts slower than the page beside the wide column (desktop only), cards reveal from “top 88%”. | showcase-5.js |
| Showcase 6 | Stacked reel: three scrubbed passes per project — title lag, card settle-from-scale, content rise (desktop only). | showcase-6.js |
Accessibility & fallbacks (all effects)
prefers-reduced-motion: reduce— ScrollSmoother is not created, reveals write their final state, counters print instantly, marquee/video autoplay is skipped.- Touch / coarse pointers — custom cursor and hover-only previews are disabled; tap equivalents are provided (listing 4).
- No JavaScript — accordions stay native
<details>, pre-reveal states are gated behind the.jsclass, content remains readable. file:/// Firefox / iOS WebKit — WebGL texture effects fall back to the static image (see Local Preview).