After finding out this month's Creative Coding Club topic was "Hot and Sticky", I began brainstorming ideas. This was two days after coming back from a camping trip so s'mores immediately came to mind.
I thought about which technologies I wanted to use for this project. Matter.js and P5.js were two that I've been wanting to try for some time now, and this project was a great excuse to give them a shot!
Refining the idea
I gathered some ideas and ran them by a friend, which was a great way to get the creative juices flowing. I then transferred these concepts onto paper. I always like to start with a sketch for two reasons:
I find that with pen and paper, you're more inclined to try something new since there aren't many limitations. In contrast, when you start with code, you may be limited by your knowledge or your willingness to step outside your comfort zone.
Sketching on paper before searching for inspiration or examples is important to prevent tainting your idea. It's very easy to see something you like and use it as "inspiration".
|Initial Idea||Revised Idea|
The initial idea
The initial idea was a way to shoot marshmallows onto a cracker suspended by a string. The marshmallows would only stick to the cracker if they were heated by a fire for long enough. The weight of each stuck marshmallow would cause the string to stretch more, until the cracker would eventually be heavy enough and dip into the cup of hot chocolate directly below.
After a few days of tinkering with Matter.js and hashing out the details, I realized that to execute this concept to my satisfaction would warrant more spare time than I had. So I ultimately decided to simplify the idea.
The revised idea
The marshmallow would instead hang off the string, allowing you to pull and dip it into the hot chocolate. To make the interaction fun, the dipping action would trigger emotions from the marshmallow and cup.
I assembled a mood board of images that reflected the general look and feel that I wanted:
Before beginning the design, I put together a list of animations I wanted to accomplish:
- The cup's eyes would follow the marshmallow around the screen.
- The cup's cheeks would move down to reveal more of the eyes as it got angrier.
- The cup's eyebrows would pivot along its eyes to appear angry.
- Both the cup and marshmallow's mouths would invert to appear sad.
- The marshmallow's eyes would slant down to appear sad.
|Cup Emotions||Marshmallow Emotions|
The list helped me keep the design minimal while still maintaining the look I wanted.
The Matter.js physics library allowed me to add the dangling arms and legs on the marshmallow, which added life to the character when it was being pulled around on the screen.
I'll begin this section with a list of resources that I used to familiarize myself with Matter.js and P5.js. These resources are a great starting point for anyone who wants to try these two libraries:
- Introduction to Matter.js (Part 1, Part 2)
- Deleting Bodies
- Mouse Constraints
- Creating a Plinko game (Part 1, Part 2)
- Matter.js documentation
- Matter.js GitHub issues
- The documentation for this library is well-written and comprehensive. When paired with the knowledge from Daniel Shiffman's (The Coding Train YouTube channel) videos above, other resources weren't really required.
Now on to the actual code...
I started by dividing the coding tasks into smaller manageable parts:
- Create a chain with a hanging object on the end
- Create bounds for the cup
- Transfer the design over to the canvas
- Write triggers to activate the animations
- Create the hot chocolate's heat lines
1. Create a chain with a hanging object on the end
I thought this seemed fairly straightforward since Matter.js has a whole example dedicated to chains. But I was wrong.
Hanging an object off the end of a chain with an offset anchor point caused the object to appear weightless while rotating. A demonstration of this is shown in the GitHub issue that I opened. While awaiting a response for the issue, I discovered a workaround that fixed it: set the object's density to a very small value.
2. Create bounds for the cup
I laid out multiple rectangles to define the bounds of the cup. This would allow the marshmallow to interact with the cup. The cup's design was then superimposed onto these rectangles.
|Rectangle Bounds||Superimposed Cup|
3. Transfer the design over to the canvas
I separated all elements that required animation. These were:
- The marshmallow's eyes
- The marshmallow's mouth
- The marshmallow's arms and legs
- The cup's eyes
- The cup's eyebrows
- The cup's cheeks
- The cup's mouth
- The cup's heat lines
4. Write triggers to activate the animations
Two triggers were used for the animations:
- When the marshmallow is less than a certain distance from the cup in any direction: trigger the gradual transition of the eyes and mouth of the sad marshmallow; and the eyes, eyebrows, cheeks, and mouth of the angry cup.
- When the marshmallow is within the walls of the cup, and less than 100 pixels from the opening: trigger the marshmallow's flailing arms to raise in distress.
|Assembly 1||Assembly 2||Assembly 3|
5. Create the hot chocolate's heat lines
The heat lines were created using a sine wave plotted with dots. When the dots reach the top of the line, they move back to the bottom, resulting in an endless loop that looks like a heat wave.
The example below illustrates how this works using dots that are spaced farther apart. In the final pen they are close together to give the illusion of a solid heat line.
Near the beginning of the process, I considered the concept of covering the marshmallow with hot chocolate with each dip. I spent a couple of days perfecting this, and got about 90% there. However, I wasn't fully satisfied with the code, and optimizing it would take more time. In the end, I decided to forgo this concept, and instead focus my attention on the design and the other features I had in mind.
|Finding the Intersection||Dipping||Multiple Dips|
With the animations complete, I had a few final touches to make. I knew CodePen's preview window is fairly small in height, which would cause issues for certain users. This wasn't ideal, and I wanted everyone to have the optimal viewing experience. To solve this, I created an image that advises the user to scale up their browser window if it's less than 500 pixels tall.
The final two steps were:
- Always move the cup to the bottom of the screen after a resize.
- Change the length of the string depending on the height of the user's browser window.
Summary and final thoughts
Overall, I'm really pleased with how this project turned out. However, I need to learn to keep my tendency to sometimes add complex features in check, especially when working with new libraries.
Having now worked with Matter.js and P5.js, I can't wait to use them in future projects. If you have been delaying learning these two libraries, I suggest you get on it because they're amazing!
And here is the pen, in its final form. If you managed to read through all of this, you're awesome and you deserve some brownie points. If you found this process breakdown useful or have any suggestions for me, let me know.
Shout outs to some people who helped with this process: Myra for editing this post, Daniel Shiffman for the amazing video content, Liam for the awesome physics engine, and Nat Cooper for the suggestion to write this post.
Oh, and go join the Creative Coding Club if you haven't already!