• About Us
  • Privacy Policy
  • Disclaimer
  • Contact Us
AimactGrow
  • Home
  • Technology
  • AI
  • SEO
  • Coding
  • Gaming
  • Cybersecurity
  • Digital marketing
No Result
View All Result
  • Home
  • Technology
  • AI
  • SEO
  • Coding
  • Gaming
  • Cybersecurity
  • Digital marketing
No Result
View All Result
AimactGrow
No Result
View All Result

Two Portfolios, One Course of: The place Design, Movement, and Code Come Collectively

Admin by Admin
December 2, 2025
Home Coding
Share on FacebookShare on Twitter


Each sturdy collaboration begins the second a designer and a developer begin talking the identical language.


Free GSAP 3 Express Course


Be taught trendy net animation utilizing GSAP 3 with 34 hands-on video classes and sensible tasks — good for all ability ranges.


Test it out

The place Design and Code Meet

We’re Max Milkin and Olha Lazarieva, a designer–developer duo whose collaboration started with curiosity, a shared need to discover how far design and code can go once you deal with them not as instruments however as inventive voices.

It was by no means nearly constructing web sites. It was about creating emotion—one thing alive, one thing that strikes and breathes.

From our very first undertaking, we’ve been exploring how typography, rhythm, and movement can form the sensation of a digital house. Each undertaking turns into a residing composition, born from professionalism, expertise, instinct, and belief, the place small concepts develop into one thing we each really feel.

Every undertaking begins with a seek for a novel thought, one which carries emotion and displays individuality, whether or not it’s a private portfolio or a company identification.

Carrying these concepts ahead, we turned our consideration to our personal portfolios. Each grew to become a mirrored image of the particular person behind it, formed by the identical shared course of however expressed in utterly alternative ways.

Within the subsequent sections, we stroll by how every thought took form, from the preliminary idea to the movement, 3D components, and technical selections that introduced every little thing to life.

Design (Olha)

The design idea started with a way of lightness and playfulness, qualities that mirror my persona. Digging deeper into that concept led to a black-and-white visible language, virtually like a chessboard, the place the animations create a way of motion and a mild interplay with the person. I didn’t even have to elucidate this idea to Max; he immediately felt the vibe behind it.

Since minimal, spacious interfaces have at all times been a part of my imaginative and prescient, the beneficiant quantity of adverse house on the positioning makes it really feel just like the person is getting into my design world.

Growth (Max)

As soon as the idea grew to become clear, I started on the lookout for a approach to translate that very same rhythm and lightness by code. My objective wasn’t simply to recreate the design, however to deliver it to life by movement – in order that interplay continues Olha’s thought.

Loader

The loader is the very first thing the person sees, so we wished it to be easy however expressive: minimal, calm, and barely “alive”. The implementation: two clear spheres with a textual content texture, light idle movement, and a small GSAP sequence that controls how they seem and disappear.

Mouse-Reactive Digital camera Orbit

To make the loader really feel extra alive, the digital camera easily reacts to the person’s mouse motion. As a substitute of snapping instantly, the digital camera interpolates towards the goal rotation, creating tender, cinematic parallax even earlier than the primary content material seems.

operate CameraOrbit() {
  const { digital camera } = useThree();
  const mouse = useRef({ x: 0, y: 0 });
  const goal = useRef({ x: 0, y: 0 });

  useEffect(() => {
    const handleMove = (e) => {
      mouse.present.x = (e.clientX / window.innerWidth) * 2 - 1;
      mouse.present.y = (e.clientY / window.innerHeight) * 2 - 1;
    };
    window.addEventListener('mousemove', handleMove);
    return () => window.removeEventListener('mousemove', handleMove);
  }, []);

  useFrame(() => {
    goal.present.x += (mouse.present.y * 0.6 - goal.present.x) * 0.05;
    goal.present.y += (mouse.present.x * 0.6 - goal.present.y) * 0.05;

    const r = 6;
    const phi = Math.PI / 2 - goal.present.x;
    const theta = goal.present.y + Math.PI;

    digital camera.place.x = r * Math.sin(phi) * Math.cos(theta);
    digital camera.place.y = r * Math.cos(phi);
    digital camera.place.z = r * Math.sin(phi) * Math.sin(theta);

    digital camera.lookAt(0, 0, 0);
  });

  return null;
}

GSAP Loader Sequence and Transition to Content material

GSAP orchestrates the total loader sequence: the spheres rise from under, idle for a second, and as soon as loading is full, transition downward whereas the hero part fades in.

This creates a clean narrative between the 3D scene and the DOM content material.

// Intro animation: spheres rise from under
  useEffect(() => {
    if (!mesh1.present || !mesh2.present) return;

    mesh1.present.place.y = -8;
    mesh2.present.place.y = -8;

    const tl = gsap.timeline();
    tl.to(mesh1.present.place, {
      y: 0.18,
      length: 2.5,
      delay: 1,
      ease: 'power4.out',
    });
    tl.to(
      mesh2.present.place,
      { y: -0.18, length: 2, ease: 'power4.out' },
      '-=2'
    );

    return () => tl.kill();
  }, []);

  // Exit animation: spheres go away, hero seems
  useEffect(() => {
    if (!exitTrigger || !mesh1.present || !mesh2.present) return;

    const tl = gsap.timeline();

    tl.to(mesh2.present.place, {
      y: -10,
      length: 1.2,
      ease: 'power4.in',
    });

    tl.to(
      mesh1.present.place,
      { y: -10, length: 1.2, ease: 'power4.in' },
      '-=1.1'
    );

    tl.to('.hero-title .hero-letter', {
      y: 0,
      length: 1.7,
      ease: 'power4.inOut',
      stagger: { every: 0.03, from: 'middle' },
    });

    tl.to(
      '.hero-designer, .hero-description, .hero-based',
      {
        opacity: 1,
        length: 1,
        ease: 'power4.out',
      },
      '-=1'
    );

    tl.to(
      'major',
      {
        opacity: 1,
        length: 1,
        ease: 'power4.out',
      },
      '-=0.5'
    );

    return () => tl.kill();
  }, [exitTrigger]);

3D Gallery

One other part I wished to focus on is the 3D gallery. Your complete room is modeled in Blender, with lighting, AO and reflections baked instantly into the textures to maintain the scene light-weight and quick to load.

When the person reaches this a part of the web page, GSAP ScrollTrigger animates a mild rotation of the whole room, making a clean “entry” into the house as an alternative of a sudden lower. This retains the transition calm and cinematic, matching the visible tone of the portfolio.

operate IntroRise({ sectionRef, kids }) {
  const stageRef = useRef();
  const { invalidate } = useThree();

  useEffect(() => {
    if (!stageRef.present || !sectionRef?.present) return;

    // begin barely tilted
    stageRef.present.rotation.set(1.5, 0, 0);

    const tween = gsap.to(stageRef.present.rotation, {
      x: 0,
      ease: "none",
      onUpdate: invalidate,
      scrollTrigger: {
        set off: sectionRef.present,
        begin: "high 40%",
        finish: "+=200%",
        scrub: 2,
        invalidateOnRefresh: true,
        // use a customized scroll container on cell to keep away from browser UI resizing
        scroller: window.innerWidth < 991 ? '.scroll-container' : null
      },
    });

    return () => {
      tween.scrollTrigger?.kill();
      tween.kill();
    };
  }, [sectionRef, invalidate]);

  return (
    
      {kids}
      
    
  );
}

Why I Use scroller

On mobile browsers, when you scroll a normal page, the top and bottom browser bars hide and show. This constantly changes the visible screen height, which makes 3D sections jump or shift.

To avoid this, I wrap the whole content in a dedicated .scroll-container and scroll that element instead of the browser window. This keeps the browser bars fixed and prevents them from hiding. As a result, the layout stays stable, and the 3D scene doesn’t shift or resize during scrolling.

ScrollTrigger just needs to know that we’re using this wrapper, so the scroller option points to .scroll-container.

Creative Flow: How a Direction Is Born

“Minimal rhythm and calm motion – the foundation of visual storytelling.”

Every project begins with a simple conversation. No screens, no mockups, just thoughts and feelings.

We ask each other: What emotion should the user feel when they open the site? Calmness? Curiosity? Excitement?

And from that emotion, we begin searching for fitting patterns, metaphors, and ideas. We collect fragments—colors, references, words, textures—and gradually combine them.

Sometimes the concept appears instantly. Sometimes it takes hours of sketches, tests, or even silence.

The best moments happen when one of us shares an idea and the other immediately understands it.

Olha suggests a concept and I instantly imagine how it moves. I propose a transition and she immediately senses how to balance the composition.

It feels like a chain reaction: one thought triggers another, and suddenly everything starts forming a single whole. Whenever we get stuck, we call each other. Sometimes we sit in silence, sometimes laughing, but twenty minutes later a new direction is born. And every time, it feels like we found it together.

Design (Olha)

The idea for Max’s site came from an image he once sent me, saying: “I don’t know why, but I like this.” That instantly sparked a flow of ideas in my head. His reaction: “This image is amazing… let’s turn it into your website concept.”

Every person has traits and a worldview that reveal themselves in everyday things. My task was to translate Max’s personality into visual form: his calmness, depth, precision. That’s how the design was born: minimal, controlled, balanced—a reflection of who he is.

Working on this website felt like traveling through a new world that you want others to discover. My mission is to make that world beautiful, by creating work that inspires.

Development (Max)

The moment I saw the design, I fell in love with it. I wanted to preserve its minimalism not just visually, but in motion, so that every animation expressed my personality: precise, calm, intentional.

The Loader

At first, I thought about building this loader as a simple SVG animation along a circular path. But after a few experiments with multiple rings and a lot of text, it quickly became clear that animating all of that in the DOM was not ideal for performance.

Instead, I switched to PixiJS and moved the whole thing to WebGL. This way I could keep the loader smooth, even with several animated rings of text breathing and rotating at the same time.

Creating Rings in PixiJS

The first step is to create a PixiJS application and build a few rings of text.

Each word becomes a separate ring, and each letter is a PIXI.Text that we will later position along a circular arc.

// PixiJS application
const app = new PIXI.Application({
  backgroundAlpha: 0,
  antialias: true,
  resizeTo: window,
});
document.body.appendChild(app.view);

const stage = app.stage;

const WORDS = ['MAX', 'MILKIN', 'DESIGN', 'CREATIVE', 'FRONTEND', 'DEVELOPER'];
const rings = [];
const middle = { x: window.innerWidth / 2, y: window.innerHeight / 2 };

// Create textual content rings
WORDS.forEach((phrase, i) => {
  const ring = new PIXI.Container();
  ring.x = middle.x;
  ring.y = middle.y;
  ring.alpha = 0;
  stage.addChild(ring);

  const type = new PIXI.TextStyle({
    fontFamily: 'RF Dewi',
    fontSize: 16,
    fill: '#10120f',
    fontWeight: 600,
  });

  const letters = phrase.break up('').map((ch) => {
    const letter = new PIXI.Textual content(ch, type);
    letter.anchor.set(0.5);
    ring.addChild(letter);
    return letter;
  });

  rings.push({
    ring,
    letters,
    radius: 80 + i * 18,
    rotationSpeed: 0.0002 + i * 0.0003,
    timeOffset: i * 0.4,
  });
});

GSAP Sequence and Respiration Movement of the Rings

As soon as the rings are in place, a GSAP timeline takes over the sequence. It fades the rings in, runs a small timed indicator, after which fades every little thing out when the loader is completed. On the similar time, the PixiJS ticker animates a delicate “respiratory” movement: every letter slides alongside a round arc whereas the rings slowly rotate.

// GSAP controls the loader sequence
const tl = gsap.timeline({ defaults: { ease: 'power2.out' } });

// counterElement - a DOM factor displaying the loading share
// onLoaderComplete - a callback that hides the loader and divulges the primary format

// 1. Fade within the rings
tl.to(rings.map(r => r.ring), {
  alpha: 1,
  length: 1,
  stagger: 0.12,
});

// 2. Timed indicator (visible, not actual loading progress)
tl.add(() => {
  const indicator = { worth: 0 };

  gsap.to(indicator, {
    worth: 100,
    length: 1.4,
    ease: 'none',
    onUpdate: () => {
      counterElement.textContent = Math.spherical(indicator.worth);
    },
    onComplete: () => {
      // 3. Fade out rings and counter, then proceed to the primary format
      gsap.to([...rings.map(r => r.ring), counterElement], {
        opacity: 0,
        length: 0.8,
        stagger: 0.1,
        onComplete: () => onLoaderComplete?.(),
      });
    },
  });
});

// PixiJS “respiratory” movement
let time = 0;
app.ticker.add(() => {
  time += 0.02;

  rings.forEach((r) => {
    r.ring.rotation += r.rotationSpeed;

    const extent = Math.PI + Math.sin(time - r.timeOffset) * 0.5;
    const begin = -extent / 2;

    r.letters.forEach((letter, idx) =>  1)) * extent;
      letter.x = Math.cos(angle) * r.radius;
      letter.y = Math.sin(angle) * r.radius;
      letter.rotation = angle + Math.PI / 2;
    );
  });
});

3D Components

The 3D components have been modeled in Blender to match the minimal tone of the positioning. Similar to within the earlier undertaking, the lighting and shadows have been baked into the textures, sufficient to provide the objects depth with out including additional weight to the scene.

Assembling Paragraph: Turning Scattered Letters right into a Single Thought

The paragraph begins in fragments: teams of letters seem in two facet columns whereas a number of characters float randomly throughout the display. Because the person scrolls, GSAP and MotionPathPlugin information every letter alongside a curved path, steadily assembling them right into a clear, completely aligned paragraph on the middle.

To maintain the typography pixel-perfect, the flying letters and the ultimate paragraph use two separate layers:
the flying characters fade out, whereas the paragraph characters fade in on the actual second every path completes.

Creating the Scattered Letters

// Construct two facet columns and a set of random letters
const root = doc.querySelector('.ap');
const colLeft = root.querySelector('.ap__col--left');
const colRight = root.querySelector('.ap__col--right');
const targetBox = root.querySelector('.ap__target');

const targetChars = [];
strains.forEach(line => {
  const lineEl = doc.createElement('div');
  lineEl.className = 'ap__line';

  [...line].forEach(ch => {
    const wrap = doc.createElement('span');
    const char = doc.createElement('span');
    char.className = 'ap__char';
    char.textContent = ch;
    char.type.opacity = 0; // last paragraph is initially hidden

    wrap.appendChild(char);
    lineEl.appendChild(wrap);
    targetChars.push(char);
  });

  targetBox.appendChild(lineEl);
});

// Facet columns: teams of flying letters
operate renderColumn(column, teams) {
  teams.forEach(group => {
    const row = doc.createElement('div');
    group.forEach(ch => {
      const span = doc.createElement('span');
      span.className = 'ap__fly';
      span.textContent = ch.ch;
      row.appendChild(span);
    });
    column.appendChild(row);
  });
}

This snippet units up the 2 layers utilized by the animation:

  • the ultimate paragraph layer – characters positioned of their actual positions however totally clear;
  • the flying layer – letters which might be rendered into the facet columns utilizing the renderColumn helper.

This separation makes the animation clear and avoids any visible jumps – the animated letters don’t have to completely land on the typographic grid, as a result of the ultimate characters fade in on the proper second.

From Chaos to Construction

// GSAP setup
gsap.registerPlugin(ScrollTrigger, MotionPathPlugin);

// Timeline pushed by scroll
const tl = gsap.timeline({
  defaults: { ease: 'power3.out' },
  scrollTrigger: {
    set off: '.about',
    begin: '50% 100%',
    finish: '50% -10%',
    scrub: 1
  }
});

// For every flying letter, generate a curved path towards its last place
flyers.forEach((f, i) => {
  const targetEl = targetChars[f.item.idx];

  const begin = getPos(f.span);
  const finish = getPos(targetEl);

  const cp = {
    x: (begin.x + finish.x) / 2 + (f.facet === 'left' ? 90 : -90),
    y: Math.max(begin.y, finish.y) + 160
  };

  const path = [start, cp, end];

  tl.to(f.span, {
    length: 1.25,
    motionPath: { path, curviness: 0.85 },
    onUpdate() {
      const p = this.progress();

      // reveal last paragraph letter close to the top of the curve
      targetEl.type.opacity = p > 0.65 ? gsap.utils.mapRange(0.7, 1, 0, 1, p) : 0;

      // conceal flying letter as soon as it is near touchdown
      f.span.type.opacity = p < 1 ? 1 - p : 0;
    }
  }, i * 0.025);
});

Every letter travels alongside a customized movement path generated from three factors:

  • its preliminary place
  • a curved management level
  • its last place contained in the paragraph

GSAP onUpdate easily transitions visibility:

  • flying letter: fades out
  • paragraph letter: fades in

This creates the phantasm that every character snaps completely into place, regardless that the flying components by no means have to align pixel-perfectly with the ultimate typographic construction.

The whole lot Begins with Curiosity

We didn’t come to this by formal schooling, however by curiosity, experiments, and a continuing need to grasp make issues higher. We realized by our personal tasks, by trials, errors, and moments when one thing lastly clicked.

This journey taught us a very powerful factor: love for the method issues greater than any guidelines. If you’re genuinely enthusiastic about what you create, the precise individuals at all times seem round you.

This shared curiosity is what sparked our collaboration, one which has grown profitable and led us to tasks with well-known studios and corporations.

That’s why we sincerely encourage others to remain open to new connections, experiments, and collaborations. As a result of it’s on this mixture—design and code, completely different visions, completely different voices—that work with actual which means is born.

Tags: CodeDesignMotionPortfoliosProcess
Admin

Admin

Next Post
Guillermo del Toro’s Cupboard of Curiosities Hardcover Ebook Is 25% Off

Guillermo del Toro's Cupboard of Curiosities Hardcover Ebook Is 25% Off

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Recommended.

Person interplay design drives outcomes

Dwelling in ghost cities | Seth’s Weblog

November 2, 2025
How To Get Purchasers On LinkedIn: Step by Step Course of

How To Get Purchasers On LinkedIn: Step by Step Course of

April 26, 2025

Trending.

AI-Assisted Menace Actor Compromises 600+ FortiGate Gadgets in 55 Nations

AI-Assisted Menace Actor Compromises 600+ FortiGate Gadgets in 55 Nations

February 23, 2026
How Voice-Enabled NSFW AI Video Turbines Are Altering Roleplay Endlessly

How Voice-Enabled NSFW AI Video Turbines Are Altering Roleplay Endlessly

June 10, 2025
Miss AV: Create A Web site Like MissAV | missav.ai

Miss AV: Create A Web site Like MissAV | missav.ai

December 13, 2025
Rogue Planet’ in Growth for Launch on iOS, Android, Change, and Steam in 2025 – TouchArcade

Rogue Planet’ in Growth for Launch on iOS, Android, Change, and Steam in 2025 – TouchArcade

June 19, 2025
10 tricks to begin getting ready! • Yoast

10 tricks to begin getting ready! • Yoast

July 21, 2025

AimactGrow

Welcome to AimactGrow, your ultimate source for all things technology! Our mission is to provide insightful, up-to-date content on the latest advancements in technology, coding, gaming, digital marketing, SEO, cybersecurity, and artificial intelligence (AI).

Categories

  • AI
  • Coding
  • Cybersecurity
  • Digital marketing
  • Gaming
  • SEO
  • Technology

Recent News

Cell app permissions (nonetheless) matter greater than you might assume

Cell app permissions (nonetheless) matter greater than you might assume

February 28, 2026
Google Uncover Core Replace Achieved, Search Volatility, Search Serving Bug, AI Immediate Injection, Google Adverts, Native & Bing

Google Uncover Core Replace Executed, Search Volatility, Search Serving Bug, AI Immediate Injection, Google Adverts, Native & Bing

February 28, 2026
  • About Us
  • Privacy Policy
  • Disclaimer
  • Contact Us

© 2025 https://blog.aimactgrow.com/ - All Rights Reserved

No Result
View All Result
  • Home
  • Technology
  • AI
  • SEO
  • Coding
  • Gaming
  • Cybersecurity
  • Digital marketing

© 2025 https://blog.aimactgrow.com/ - All Rights Reserved