A collection of motion experiments with Rive and JavaScript. Some shipped, some scrapped, and some… just because they were fun to build

Motion in the

Margins

Motion in the

Margins

Eye Counter Animation

Where motion met micro feedback

Titan’s read receipt had a plain static counter and a green eye, functional but forgettable. I saw an opportunity to add subtle motion to signal attention and increase interaction

How I built the prototype

Used Rive’s state machine to manage idle and blink animations, and a trigger input to fire the blink. Applied text-run to dynamically update the count. Used JavaScript to update the text-run value in real-time as the count changed

What it did

Once implemented (and yes, my seniors loved it 😄), this micro-interaction led to a 30% spike in eye icon clicks. A tiny touch but one that delivered clear, visible impact

🎃 Flashy Promo Block (Halloween Prototype)

I built this as a playful proof of concept to explore

  • How Rive animations could make email blocks feel more alive

  • How users could customise glow effects and animated tickers


Why it didn’t ship

Most email clients don’t support advanced CSS let alone Rive animations. So this wouldn’t render reliably in email


Where it could shine

Blocks like this are perfect for web use. Titan’s website builder offering (NEO Site) could use these in landing pages and promo sections for a richer visual experience


A few scalable ideas

  • Users could upload their own images with auto glow styling

  • Customisable ticker with selectable path curves for dynamic motion

Like Reaction

A custom heart animation I built for my portfolio. Used Rive's layers, state machine, inputs, and listeners to create smooth, responsive interaction

A loader for Titan's Email Designer

A lightweight and playful loading animation built to add a bit of personality to wait times in the editor

Warning: Entering the Nerd Zone

❗️Talking about T20 World Cup 2024 :)

Cute Dropdown

Rive gives me a canvas to tinker, test, and bring ideas to life, right where code and creativity meet. Just me, Rive, a bit of JavaScript

const r = new rive.Rive({
    src: 'color_mixing.riv', 
    canvas: animationPattern,
    artboard: 'Pumpkin color mixing', 
    stateMachines: ['Haloween pumpkin'], 
    autoplay: true,
    onLoad: () => {
   
        const inputs = r.stateMachineInputs('Haloween pumpkin');
        const redColor = inputs.find(input => input.name === 'Red');
        const greenColor = inputs.find(input => input.name === 'Green');
        const blueColor = inputs.find(input => input.name === 'Blue');

        if (!redColor || !greenColor || !blueColor) {
            console.error("State machine inputs not found!");
            return;
        }


        function calculate(){
            const color = colorPicker.value;

            // Parse color values
            const red = parseInt(color.slice(1, 3), 16);
            const green = parseInt(color.slice(3, 5), 16);
            const blue = parseInt(color.slice(5, 7), 16);

            // Update Rive inputs
            redColor.value = red;
            greenColor.value = green;
            blueColor.value = blue;

Viewing Portfolio00 : 00

Motion in the

Margins

A collection of motion experiments with Rive and JavaScript.

Some shipped, some scrapped, and some… just because they were fun to build

Titan's Read Receipt

Where motion met micro feedback

Titan’s read receipt had a plain static counter and a green eye, functional but forgettable. I saw an opportunity to add subtle motion to signal attention and increase interaction

How I built the prototype

Used Rive’s state machine to manage idle and blink animations, and a trigger input to fire the blink. Applied text-run to dynamically update the count. Used JavaScript to update the text-run value in real-time as the count changed

What it did

Once implemented (and yes, my seniors loved it 😄), this micro-interaction led to a 30% spike in eye icon clicks. A tiny touch but one that delivered clear, visible impact

🎃 Flashy Promo Block (Halloween Prototype)

I built this as a playful proof of concept to explore

  • How Rive animations could make email blocks feel more alive

  • How users could customise glow effects and animated tickers


Why it didn’t ship

Most email clients don’t support advanced CSS let alone Rive animations. So this wouldn’t render reliably in email


Where it could shine

Blocks like this are perfect for web use. Titan’s website builder offering (NEO Site) could use these in landing pages and promo sections for a richer visual experience


A few scalable ideas

  • Users could upload their own images with auto glow styling

  • Customisable ticker with selectable path curves for dynamic motion

Like Reaction

A custom heart animation I built for my portfolio. Used Rive's layers, state machine, inputs, and listeners to create smooth, responsive interaction

A loader for Titan's Email Designer

A lightweight and playful loading animation built to add a bit of personality to wait times in the editor

Warning: Entering the Nerd Zone

Bad Form

❗️Talking about T20 World Cup 2024 :)

Cute Dropdown

Rive gives me a canvas to tinker, test, and bring ideas to life, right where code and creativity meet. Just me, Rive, a bit of JavaScript

const r = new rive.Rive({
    src: 'color_mixing.riv', 
    canvas: animationPattern,
    artboard: 'Pumpkin color mixing', 
    stateMachines: ['Haloween pumpkin'], 
    autoplay: true,
    onLoad: () => {
   
        const inputs = r.stateMachineInputs('Haloween pumpkin');
        const redColor = inputs.find(input => input.name === 'Red');
        const greenColor = inputs.find(input => input.name === 'Green');
        const blueColor = inputs.find(input => input.name === 'Blue');

        if (!redColor || !greenColor || !blueColor) {
            console.error("State machine inputs not found!");
            return;
        }


        function calculate(){
            const color = colorPicker.value;

            // Parse color values
            const red = parseInt(color.slice(1, 3), 16);
            const green = parseInt(color.slice(3, 5), 16);
            const blue = parseInt(color.slice(5, 7), 16);

            // Update Rive inputs
            redColor.value = red;
            greenColor.value = green;
            blueColor.value = blue;