Rebuilt ReactBits’ Threads Animation in Flutter — and Here’s How the Math Works
Teqani Blogs
Writer at Teqani
A few weeks ago, I stumbled upon this mesmerizing animation on ReactBits.dev. It’s called Threads — soft glowing waves that move like silk in slow motion. This article dives into how to recreate that animation in Flutter, showcasing how simple sine waves and basic math can be transformed into visually stunning effects.
What We’re Recreating
The original Threads animation looks like multiple glowing lines flowing across a dark background — almost like music you can see. We’ll recreate the same effect in Flutter using CustomPaint for drawing the lines, an AnimationController for continuous motion, and a few sine waves for natural, flowing movement.
Step 1: Setting the Scene
We start with a dark canvas to make our golden lines stand out:
void main() => runApp(const MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
backgroundColor: Color(0xFF0A090F),
body: Threads(),
),
));
We paint everything on a dark background — because neon waves always look cooler in the dark. The Threads widget drives our animation with an AnimationController that loops forever. Each frame passes a changing value (time) to our painter, which we use to move the waves.
Step 2: Painting Multiple Lines (Because One Is Boring)
In the painter, we draw 22 lines (lineCount = 22) — each slightly offset vertically to create a layered look. Think of it like having a bunch of ribbons floating in the air, all wiggling differently.
for (int i = 0; i < lineCount; i++) {
double p = i / (lineCount - 1);
double offsetY = (p - 0.5) * size.height * distance;
double phase = time + p * 1.5;
}
Here’s what’s going on:
p→ A normalized value between 0 and 1 (top to bottom).offsetY→ Moves each line up or down.phase→ Gives each line a slightly different timing, so they don’t all move in sync.
If we didn’t offset them, you’d just get one boring line waving like a worm.
Step 3: Making the Waves Wiggle
Here’s the secret sauce:
double _wave(double x, double t, double freq, double speed) {
return sin((x * freq + t * speed) * pi * 2);
}
Let’s break it down:
x= where you are horizontally on the canvast= time (it changes every frame)freq= how many times it wiggles across the screenspeed= how fast it moves
We multiply everything by pi * 2 because sine waves complete a full cycle every 2π radians. So, yes, this entire animation is just a bunch of sin() functions flexing their curves.
Step 4: Layering Multiple Sine Waves
If you’ve ever mixed juice and soda together just to see what happens — we’re doing the same thing here with sine waves.
double waveY = _wave(x, phase, 0.8, 0.2)
+ _wave(x, phase, 1.5, 0.15) * 0.4;
We combine two waves with different frequencies and speeds. The first wave is smooth and wide; the second is faster and smaller. Together, they form that hypnotic, organic motion. Think of it as one wave saying “chill,” and the other yelling “party!” — the result is perfect chaos.
Step 5: Connecting the Dots
We use 200 points (points = 200) across the width of the screen. For each point, we calculate a y based on the wave result, then connect them using path.lineTo.
if (j == 0) {
path.moveTo(x * size.width, y);
} else {
path.lineTo(x * size.width, y);
}
The result? A smooth continuous thread that looks like it’s breathing.
With just a few lines of math and some Flutter magic, you can turn simple sine waves into mesmerizing backgrounds that feel alive. It’s a great reminder that animation doesn’t always need heavy libraries — sometimes, all it takes is curiosity and a pinch of trigonometry.
All blogs are certified by our company and reviewed by our specialists
Issue Number: #09e8f4e7-107d-44b9-8b2c-012fb7550cb7