Modifying and Improving EmojiSaver
In this post, I take an Emoji Screensaver for macOS and modify it to do even more cool stuff.

This post is imported from my old blog.
Please note I cannot give the source code or compiled product for this as this is a modification of code given by a paid subscription to Guilherme Rambo’s Patreon. However, feel free to support him yourself and add my modifications to his code! Send me a message on Twitter or Discord for help on this (not all the required code is in this post).
Introduction
A few days ago, I subscribed to Guilherme Rambo on Patreon. Rambo is a popular iOS and Mac developer who recently discovered unreleased iOS and iPhone photos, info, and more, and leaked a lot of the Apple’s September Event beforehand. Apart from leaking Apple’s stuff, Rambo also makes apps and hacks for Mac and iOS. As a perk for donating to Rambo, I got access to some of his projects. One of them includes EmojiSaver. It’s a screensaver he made for mac with random Emoji popping up and pulsing (zooming in and out).
After testing out the screen saver and watching his coding session (where he made the saver) to understand how it was built, I went and chose to try modify a few things:
- Make emoji rotate slowly
- Make emoji move around randomly
- Change the first emoji that is generated
I’ll now go through each of these 3 tasks and detail how I made them, with code examples.
Task 1
Making emoji rotate slowly
As I had never really written any Objective-C code before, this was a blunt introduction to it.
I started out by going into the code, where I found how Rambo made Emoji rotate:
SKAction *zoomIn = [SKAction scaleBy:kEmojiMaxScale duration:3];
SKAction *zoomOut = [SKAction scaleBy:kEmojiMinScale duration:3];
SKAction *pulse = [SKAction repeatActionForever:[SKAction sequence:@[zoomIn, zoomOut]]];
[label runAction:pulse];
Just by looking through the code, we can quickly see the basics of this:
- Create an action (zoomIn) that scales the Emoji up to the max scale in 3 seconds
- Create an action (zoomOut) that scales the Emoji down to the min scale in 3 seconds
- Create an action (pulse) that repeats the sequence of zoomIn zoomOut
- Run the pulse action
Taking this code, I used Xcode’s autocomplete to test out some other action types, where I found the following 3 types for a search of “rotate”:

Looking at these, it seems like rotateByAngle should work — and this is correct. However, it’s not that easy.
In my initial code, I used:
SKAction *rotateBy = [SKAction rotateByAngle:1 duration:1];
SKAction *rotateForever = [SKAction repeatActionForever:[SKAction sequence:@[rotateBy]]];
[label runAction:rotateForever];
However, this had multiple problems. First, it didn’t run. It turns out
[SKAction sequence:@[rotateBy]]
requires more than one item — replacing it with just rotateBy fixed it. Second, it was way too quick, so I changed the duration to 4 (seconds). Third, the angle was too…. fixed. I wanted something more random, so I used
SSRandomFloatBetween(-1, 1)
Finally, this is the working code I settled on for this task:
SKAction *rotateBy = [SKAction rotateByAngle:SSRandomFloatBetween(-1, 1) duration:4];
SKAction *rotateForever = [SKAction repeatActionForever:rotateBy];
[label runAction:rotateForever];
Task 2
Making emoji move around randomly
After doing task 1, this wasn’t too hard. However, it wasn’t too easy, either.
I started off, again, with Rambo’s pulse code:
SKAction *zoomIn = [SKAction scaleBy:kEmojiMaxScale duration:3];
SKAction *zoomOut = [SKAction scaleBy:kEmojiMinScale duration:3];
SKAction *pulse = [SKAction repeatActionForever:[SKAction sequence:@[zoomIn, zoomOut]]];
[label runAction:pulse];
I won’t repeat the explanation of that code, but I tried what I did in task 1 again — using Auto Complete to suggest other actions.
These are the suggestions I got this time around:

As you can see, it seems incredibly obvious!
I immediately picked suggestion 1, so my code looked a bit like this:
SKAction *moveBy = [SKAction moveBy:1 duration:1];
SKAction *moveForever = [SKAction repeatActionForever:moveBy];
[label runAction:moveForever];
Unfortunately, this triggered an error: value 1 (for moveBy) was not a “CGVector”.
Not knowing anything about CGVector or what it was, I simply went on Google and searched something like this:
objective c spritekit move element to point
Eventually, after going through lots of options, I chose to try one of the smart ways I saw to implement this:
SKAction *moveBy = [SKAction moveByX:100 y:100 duration:1];
This worked! However, there was one last problem: All emoji just moved in thesame direction! I used my code from Task 1 to select
SSRandomFloatBetween(-100, 100)
for the task, giving me the final code of:
SKAction *moveBy = [SKAction moveByX:SSRandomFloatBetween(-100, 100) y:SSRandomFloatBetween(-100, 100) duration:1];
SKAction *moveForever = [SKAction repeatActionForever:moveBy];
[label runAction:moveForever];
This worked perfectly, so I moved on to task 3.
Task 3
Change the first emoji generated
This last task was the easiest out of the 3.
Basically, I copied the random emoji spawner and changed
label.text = emoji.glyph;
to
label.text = @"CUSTOM_FIRST_EMOJI_HERE";
Then, I just made the initial call of the random emoji spawner call this one instead
([self spawnFirstEmoji];)
and kept the timer (which makes emoji spawn every second) calling the real random spawner.
Conclusion
After all this, I now had a very good looking and smart screensaver.
I hope this blog post was interesting and made you understand a few things about what I did, as well as give some kind of an introduction to Objective C.
I’d like to give full credit to Guilherme Rambo for the initial idea and code. I also highly recommend anyone who found this post interesting to subscribe to him on Patreon.