Rive #characterchallenge Interactive Aquarium by Nikita WibisonoRive #characterchallenge Interactive Aquarium by Nikita Wibisono

Rive #characterchallenge Interactive Aquarium

Approve request to show earnings

View

Nikita Wibisono

Nikita Wibisono

Verified


For the Rive #characterchallenge, they wanted us to make characters that feel alive and respond to user input and data. My initial instinct was a Tamagotchi-like virtual pet, but faced with a one-week deadline while balancing a fully-booked schedule, I felt that building too many moving parts risked me spending more time on the character design and less on the actual interactivity.
My solution was an interactive aquarium. With fewer moving parts, I could focus on making what little there is to animate even more beautifully. Less quantity, more polish and interactivity.
Here are the key elements that made it work...

Smooth 2.5D body rotation mapped via Joysticks, fins rigged with Bones, color Data Bound to a Property so control it on the fly.

CHARACTER RIGGING

In my experience, the fastest way to make a mascot look premium is 2.5D rotation. My background is in motion design, so I often use the plugin Joysticks n' Sliders to rig characters in After Effects. I have to say, Rive's Joysticks blow it out of the water.
Now I'm able to have the fish smoothly rotate in 2.5D space, instead of doing it the cheap way, which is to just abruptly flip the fish horizontally. This creates a sense of volume for the fish.
The next most effective key to good character animation is secondary motion. By using bones to offset the animation keyframes, I made the fins look less rigid and, therefore, more natural.
The colors of the fish are data-bound to a color property; therefore, each instance of the same fish component can be colored differently, creating a diverse, multi-colored school of fish from a single component.

Fish automatically wander around the aquarium. Sometimes near, sometimes far, sometimes slow, sometimes fast. Swim speed is controlled by a State Machine, accelerating according to the Velocity Property.

PROCEDURAL MOVEMENT

With a Tamagotchi-like pet, people are content to let the character sit still and animate from there, and it honestly won't look too out of place. A fish however, would look dead if it didn't constantly move. So, my next order of business was to give the fish life using Scripts.
Each Fish Component's position is data bound to Number Properties, which in turn is driven by the code.
The code checks the aquarium bounds, and splits that into 3x3 sectors.
After spawning at a semi-random coordinate, each fish is given a semi-random destination coordinate within 1-3 sectors away. The fish will then travel there at a semi-randomized speed, so there's variety in how they move. Sometimes they dart, sometimes they drift.
The fish will accelerate there, then decelerate as it approaches the destination, though they never really stop to simulate momentum in water.
The fish will turn their bodies according to their heading by Data Binding it to the aforementioned Joysticks, and also rotate their body up or down depending on if their destination is above or below them.
To prevent fish from clumping too much, the code also checks a social distance radius and makes sure its destination is not too close to other fish.
My favorite bit of this Script is that I can also use that velocity Property to control the speed of the swim animation. A fast fish doesn't just go to point A and B quickly, but also beat their tails and move side to side quicker. So the higher the velocity, the higher the animation speed, creating a natural looking loop.

By adding a State Machine that randomizes at what frame the food animation starts, the flake animation desynchronizes with each other and looks more natural.

FOOD SPAWNING

I made one Component for the food, and created 5 instances of it on the main artboard. When you click within the aquarium bounds, the code moves the Component there and turns it visible.
The code will then drive the food to naturally drift downwards and even wobble side-to-side, creating a realistic fish flake sinking animation, though the animation of the flake itself is made with keyframes. Once it falls to the bottom or is eaten, it becomes invisible and moves out of frame again.
Notice that I also added an offset randomizer to the fish food's animation using State Machines, so that each fish flake doesn't animate too much in sync with each other. I actually applied this technique in multiple places, to avoid things moving too much in unison.

Fish appearance controlled by State Machine, driven by their hunger Property. The hungrier they are, the more fervently they'll seek out food.

HUNGER AND FEEDING

The fish have a hunger Property, which automatically increments in time depending on their hungerRate Property.
If a fish isn't hungry it'll ignore food. If it's hungry, it'll go for food that's near it. If it's starving, it'll dart at food no matter how far it is.
It'll compare its coordinates to that of the food, check if its in range. If multiple fish try to target the same food, I made it so that the hungrier one takes priority, to avoid conflict (I know a cooler solution would be to let fish fight over food, but ehh, maybe later).
When it reaches that food's radius, it'll trigger both an eating animation and for the food to disappear. That fish's hunger will decrement according to the food's value.
I've also tied the fish's expression and behaviors to this hunger Property, making it look energetic when healthy, and progressively weaker and sadder as it gets hungrier. It even has a unique swim animation for when it's starving.

The eye tracks the cursor, but only when the cursor enters a small circular hitbox around the fish. If it's outside of this hitbox, the eye's Distance Constraint is overridden by a Follow Path Constraint.

EYE TRACKING

One of the first cool things you learn in Rive is to make a character look towards your cursor. You achieve that by using an Align Target Listener to stick its pupils to your cursor, and give it a Distance Constraint so that it stays within your character's eyes and face.
However, having all your fish constantly stare at your cursor no matter where they are and what you're doing is a bit unsettling, so I've added an additional trick.
I gave it a Follow Path Constraint and created two States. When the cursor is within the fish's proximity, it sets the Follow Path Constraint's Strength to 0%, allowing the normal staring behavior. When it's outside the proximity however, the Strength is set to 100%, locking the eye in place.
I've also added Easing to the transition between those States, so the eyes don't snap and instead move naturally. You won't get to see this behavior on mobile since there's no cursor, though, so sorry mobile users!
The eyes also blink randomly, driven by the code randomly firing a blink trigger.

Procedural canvas-drawn bubble streams rising alongside interactive IK plant structures that bend to avoid the cursor.

AN INTERACTIVE ENVIRONMENT

Lastly, the aquarium itself has to have some life to it. I didn't have time to make a full-on digital painting-based art style like, say, Insaniquarium had, so I went with a flat vector style, designed in Affinity and imported into Rive.
There's some basic animation in there, like the top of the water and the light rays moving to simulate water, but I also have procedurally generated bubbles. These aren't Components, but circles that are drawn by the code straight onto the canvas.
The bubbles spawn in random clusters, rise at different rates, wobble, and pop either randomly or when they reach the surface, mimicking actual bubbles.
The aquarium plants are Components rigged with Bones, and each joint is controlled by its own IK Constraint. Then, I added a Distance Constraint to each IK node, which makes it so that they will begin to avoid the cursor when it enters a certain range. This makes it so that the cursor repels the plant in a natural way, as if you're physically running your hand through them.
Even if you're not interacting with them, each plant of course has its own idle animation, with an offset randomizer so that each copy of the plant animates in its own phase instead of moving in unison.
Because the plants are Components, I can duplicate multiple copies of them and they'll each behave and detect the cursor on its own.

CONCLUSION

This interactive aquarium demonstrates how character rigging, State Machine management, and Scripting can work together in Rive. By shifting the focus away from asset quantity and toward deeply integrated interactivity, the result is a responsive tank that loops beautifully, feels alive, and runs incredibly smooth.
Like this project

Posted Jul 6, 2026

An interactive, procedurally driven aquarium built entirely inside Rive for the #characterchallenge contest. Fish will wander naturally. Spawn food by clicking.

Likes

2

Views

8

Timeline

Jun 27, 2025 - Jul 3, 2026

Clients

Contra