Shang Lun's ProgLog

Hi, I’m Shang Lun / Harry, director of PlayReactive. We’re based in Narrm / Melbourne, which is currently in lockdown. I’ll be experimenting and exploring solo during this time.

Received Playdate unit in the mail today. I don’t know anything about Lua, and I’m not a good programmer, but that hasn’t stopped me in the past! For now I won’t be working towards one particular game, but rather figuring things out as I go with a collection of prototypes. My focus is less on pushing the boundaries of the tech and more on “what cool things can I make without much coding prowess”.

So here’s my Progress Log, to help document my learning as well as motivate me and keep me accountable. Hopefully it’s helpful to other people in a similar position of feeling totally out of their depth but glad to have jumped in, and also as a form of approachability feedback to the Playdate team. This will probably be laughably basic to most of you, but I appreciate any encouragement and support.

Day 1

First impressions. Opened box. Unit is small and cute, gorgeous design. Didn’t turn on immediately, contrary to tiny booklet. Plugged into computer and immediately worked. Is Crayons an art collective? No, it’s an example drawing software. Reinforces that A is [action/select] and B is [undo/cancel]. How do I change the paint roller, the 1, the name? Can’t quit - oh, the menu button lets me go back to launcher. Satisfying sound effects. Where do my screenshots go? Screen is crisp, definitely best in sunlight. Crank and accelerometer interest me most in input test. Would have liked a mic level indicator. Having way too much fun on this screen. Connect to wifi easily, keyboard for password is great. No problems connecting Account, super smooth process. I note that when I visit Settings now, it’s unresponsive for a second while it fetches my Account information, surprised by this approach. Digital clock looks great, but it’s 2 hours off. Upside Down mode heck yeah!

Right, time to figure out this SDK thing. Download SDK. Folder with ReadMe that tells me to check Inside Playdate. I’m given an example Basic Playdate Game very quickly but I don’t really know how to run it. Structuring and compiling… Oh, Nova extension. This bit was the most helpful. I can create main.lua and copypaste the basic game code and hit run but it doesn’t work. I think the error is lack of sprites. I look at the Examples folder and grab a random player and background asset and put them into my folder using the suggested structure. It works! Here are the steps I took:

Running Basic Playdate Game
  1. The SDK is a bunch of tools used to make Playdate games. Download and install the SDK from the pinned post on the Announcements page, then read Sections 1 to 4 of Inside Playdate.html in the SDK’s folder.
  2. Nova is a code editor. Download Nova from the Nova Beta Access post and set it up with the Playdate extension, following the instructions in section 4.5 of Inside Playdate.html. Keep following the instructions to create a new project (so Build & Run is configured to Playdate Simulator). As part of this process, you’ll create a project folder.
  3. Inside the project folder, create a folder named source. Inside that, create a file called main.lua and copy the Basic Playdate Game code from Inside Playdate.html.
  4. Create a folder named images inside source. Put two .png files into it and name them background.png and playerImage.png.
  5. Click the run button. The simulator pops up and you can play the game (moving the sprite with arrow keys).
  6. From the simulator and with device plugged in, select Device > Upload Game to Device to play the game on the Playdate.

With that working, it’s time to figure out how this code works. I read this document and get utterly confused. Let’s see if I can just play with the guts of this. Looks like there’s two main sections: a game setup function, called once to initialise the game, and an update function, called every frame. Why is playerSprite outside of the game setup function? Is it because it’s also called by update? I put xvel = 0 and yvel = 0 into the game setup function and make the button presses modify them in the update function, along with playerSprite:moveBy( xvel, yvel ).

Cross my fingers and hit run. It seems to work. Still no idea where I should put variables and whether they should be local or not (or what that means). Experimentation shows me declaring xvel and yvel in game setup function as local doesn’t work, but declaring them just after playerSprite as local does. I’m guessing local means “to the level of where this was declared, but no higher”.

Onwards to Section 5. It’s impenetrable. “We recommend you review the language manual to make sure you understand the difference”. I’m not going to do that, so I expect to be besieged by very-difficult-to-track-down bugs. What is object oriented programming. Help.

Skipping ahead to accelerometer and crank, because those are exciting. Do I turn accelerator on and off each frame? I’ll turn it on at the start and never turn it off for now. What’s a tuple? I guess and set xtilt,ytilt,ztilt = playdate.readAccelerometer() and add xtilt and ytilt to xvel and yvel every frame. Neat, I have a sprite that I can move by tilting the device. Crank time. I add playdate.getCrankChange() to xvel and now I can move my sprite using the crank. I feel very powerful.

Time to load some of these example games. 2020, Flippy Fish, Hammer Down, Pathfinder, and Mode7Driver are all very technically impressive projects. Oh. I got rickrolled.

Spent a few hours poking around and looking up a bunch of things. How does text work? gfx.drawText, ok. How can I store values? In a table. Is there a way to use dynamic variable names? No idea, I’ll put the variables into a table instead. How do I call sound? There’s a helpful forum post. Et cetera. Lots of small realisations and learnings.

I put together some of the things I learned and made a tiny Dadaist toy that lets you make/find a poem by remixing the first few lines of Genesis: (190.3 KB)

…now how do I uninstall games from my device?!


Welcome! Your first day piece is really cool.

I look forward to reading your ongoing log!

Thanks Matt! I’m definitely excited to see what things I can make with minimum knowledge.

Day 2 & 3

Open up Nova. Feels like I’ve forgotten everything. Code slides off me like sad jello. Today’s project idea is an exploration of inputs. First thing to do is properly engage with sprites and maybe understand collisions. Group layers? Couldn’t figure it out, I’ll design around it and use position checks. Will investigate collisions another day. Whoops, don’t know how to swap sprite image either. I’ll just stack them and make them visible and invisible as needed.

Next, some experimentation to answer weird questions. How does the device detect that the crank is stowed? It seems like a magnet switch - I can trick it by carefully inserting a scissor blade into the slot. Can I control the LED? Ooh, maybe I can record using the microphone to turn it red. Does getHeadsetState() specifically detect headphones, or any metal in the jack? …Better not test that one.

Possibly Unusual Behaviors:

  • The crank only detects changes of 2 degrees at a time, and sometimes flickers between two values when left at rest.
  • The LED doesn’t turn on when recording audio using micinput.recordToSample(buffer, completionCallback)
  • Device crashed one time when the completionCallback function fired, which is great because I got to see the cute building blocks animation. On the downside, I couldn’t reproduce it, and the function seems to fire as normal after a certain number of seconds as defined by the buffer sample.
  • At one point my computer asked for mic control, which I allowed (and it’s still enabled in Security & Privacy settings), but I haven’t been able to use the mic to interact with the simulator after that one time.

Put together some levels based on the feeling of different physical interactions with the device. Uh oh – I quit the simulator as the game was being uploaded and now my device is stuck on the ‘sharing DATA segment as USB drive’ screen. Ohhh this is how to delete games with malformed pdxinfo files! Great. Ejected disk and tried again, works.

Here’s the result: a puzzle game where you get the red key to open the magic door, or something. (202.0 KB) Note: can only be played to completion on a device.


Day 4 & 5

It’s been a while! My colleague Adam has been teaching me code. I’ve learned how to read external files, how to procedurally construct multidimensional arrays, why not to use magic numbers. I’ve started work on porting my first ever game Impasse (here’s a HTML5 version) and am reminded why I was the designer and not the programmer.

Also did some idle brainstorming. Here are some quick ideas that play with the nature of the Playdate as a portable bespoke design object:

  • Salt & Flicker – horror in the vein of digital and folkgame creepypasta (eg The Midnight Game). Light a candle and play in the dark, use the crank to draw out protective circles, detect paranormal activity with accelerometer and microphone, capture a sprite…
  • Object of Desire – go on a nice date with your Playdate. During the day, navigate a conversation tree to agree on the time and food. At the right time, eat dinner with your device. Have a pleasant time discussing various topics. With their consent, it might get sensual. Can I push your buttons? Would you like me to turn your crank?
  • Playdate Developer Preview Spy Network – the Playdate is a telecommunications device, sending top secret missions to field agents. Everyone obtains same instructions at same time. Execute your task in the real world.

No prototype to show right now.