Interactive Livestream
Realtime Interactive Text-to-Speech YouTube Livestream, built with node.js, and Max/MSP
Realtime Interactive Text-to-Speech YouTube Livestream, built with node.js, and Max/MSP
Lux Gatherings was a startup company that had come to my agency to help with their branding, web app design and development. They were looking to create a product of connecting party hosts with luxury food and servers.
Through regular, cyclical design, development, and prototyping sessions. We worked to develop a web app from the ground up to act as the “Uber” of dinner party planning.
Ral-ly was a Sports drink start up company that wanted a website that could make them stand out from other competitors. They wanted to leave an imprint on their audience and that the best way to do that was to have something that was unlike anything on the web.
To accomplish this, we contracted with a 3D modeler to model their sports drink bottle in three flavors. We then animated the bottle to act as a quirky and fun transition while you navigate through their website.
Interested in this project?
A new startup that my agency had been working with since the beginning, looking to build an online portal for hiring servers and catering for luxury home parties was looking for a way to announce their new brand, and build hype. Their whole brand experience was based around; being an internet company (so we knew we had to have something somewhat advanced), and catering to a higher end client (thus the name “Lux Gatherings”).
So I took to building a beautifully minimalistic landing page to help communicate those two ideas. I worked with our designer to put together a simple layout, with a slight gradient, and this beautiful string light effect.
With the initial design in place I knew exactly what I wanted to do; animate the string lights. But not a static animation, I wanted them to be interactive.
So I settled on creating a physics based string lights effect. I found a great little 2D rigid-body physics engine in vanilla Javascript. This allowed me to create a rigid chain of small circular bodies, the small bodies would be set to not render. Meaning, it was a rigid line, connected to an invisible circle, then to another rigid line, and so on. Then at each invisible circle, I create a new, larger circle, connected (via a constraint, visualized as a thicker black line) to the invisible circle. Then I randomly positioned those larger, visible circles so that when the page was loaded, it would have a nice, falling effect.
function initString() { var groupId = Body.nextGroupId(); var stack = Composites.stack(0, -10, 10, 1, 0, 0, function(x, y, column, row) { var isStatic = false; x = ((column/9) * $string.width()); y = (column/9) * 200; if (column == 0) { x = 50; y = -10; isStatic = true; } if (column == 9) { isStatic = true; } return Bodies.circle(x, y, 5, { groupId: groupId, isStatic: isStatic, frictionAir: 0.3, render: { visible: false, } }); }); string = Composites.chain(stack, 0, 0, 0, 0, { groupId: groupId, stiffness: 0.9, render: { strokeStyle: "#231f20", lineWidth: 3 } }); // add string World.add(engine.world, string); }
Now. I could have created more points along the chain, giving the rope a more fluid feel, but I hedged away from this, due to the fact that in my cross browser testing, I noticed that some browsers would slow down dramatically due to the added physics calculations.
Now I wanted to give the user a hint that they could interact with it. I came up with the idea of doing a wind effect. The problem was Matter did not have any sort of additional force effects. So I decided to shift gravity. At a random interval (between 0 and 3 seconds), and at a random duration (between 0 and 3 seconds), and at a random intensity (between 0.25 and 0.5), and at a random duration (between 10 and 20 frames), and in a random direction (half the length), I would ease the gravity from straight down, to the chosen direction, imitating a gust of wind.
function initWind() { wind = window.setTimeout(function() { gust(); }, 2000); function gust() { var gravity = 0; var i = 0; var intensity = 0.25 - (Math.random() * 0.5); var length = Math.ceil(Math.random() * 20) + 10; var halflength = length/2; guster = window.setInterval(function() { if (i <= halflength) { gravity = ease(i, 0, intensity*halflength, halflength); } else { gravity = ease(i - halflength, intensity*halflength, 0 - intensity*halflength, halflength); } if (i == length) { window.clearInterval(guster); wind = window.setTimeout(function() { gust(); }, Math.random() * 3000); } i++; engine.world.gravity.x = gravity; }, 100); } }
Then the last part, creating interaction. For desktop I created an invisible circle that would simply track with the mouse, and repel other circles.
function initMouse() { var mouser = Matter.MouseConstraint.create(engine, { constraint: { render: { visible: false } } }); var groupId2 = Body.nextGroupId(); var mover = Bodies.circle(0, 0, 10, { groupId: groupId2, isStatic: true, render: { visible: false, } }); var mover2 = Bodies.circle(0, 0, 20, { groupId: groupId2, isStatic: false, render: { visible: false, } }); var mouseConstraint = Constraint.create({ bodyA: mover, bodyB: mover2, length: 0, render: { visible: false, } }); Matter.Events.on(engine, 'mousemove', function(event) { mover.position = {x: event.mouse.position.x, y: event.mouse.position.y}; }); World.add(engine.world, [mouser, mover, mover2, mouseConstraint]); }
And for Mobile I removed the wind, and instead opted to shift the gravity in the direction the user tilted their phone.
function initMobile() { $("#string").css("pointer-events", "none"); window.addEventListener('deviceorientation', updateGravity, true); function updateGravity() { oldorient = orientation; orientation = window.orientation, gravity = engine.world.gravity; if (orientation != oldorient) resize(); if (orientation === 0) { gravity.x = Common.clamp(event.gamma, -90, 90) / 90; gravity.y = Common.clamp(event.beta, -90, 90) / 90; } else if (orientation === 180) { gravity.x = Common.clamp(event.gamma, -90, 90) / 90; gravity.y = Common.clamp(-event.beta, -90, 90) / 90; } else if (orientation === 90) { gravity.x = Common.clamp(event.beta, -90, 90) / 90; gravity.y = Common.clamp(-event.gamma, -90, 90) / 90; } else if (orientation === -90) { gravity.x = Common.clamp(-event.beta, -90, 90) / 90; gravity.y = Common.clamp(event.gamma, -90, 90) / 90; } }; }
All In all, I created a very simplistic, beautiful way to grasp peoples attention, instigate interaction, and increase their likelihood of signing up to be a member of their mailing list. Thus increasing the companies likelihood of launch success.
O’Connor’s Catholic Supply store has been around for 80 years and had moved to a location that was bigger in Mission Valley. They contacted my agency to help and shift the way the community saw them as they moved into a new era.
With research we focused on the three tenants of the brand “Faith, Family, & Community,” and I made their new e-commerce website to match the brand with a robust, simple and easily navigable site.