Playdate Oneil Camera

The image below is cool because unlike previous ones that came from the Teensy, this one is a proper Playdate screenshot, which proves that the eval route works and allows us to stay in the context of the game, meaning that all some of the wildest dreams of the 7 voters above are achievable.

Camera 2023-04-04 23.48.47

It was a bit finicky to get there, and it takes something like 5 seconds to render a single frame because of the naive Lua implementation I wrote; but there's plenty of room for improvement (like switching to C for starters). To be continued I guess...

PS: woops looks like I got the centering wrong somewhere ¯\(ツ)/¯


The app is now processing the eval data in C, at a pretty decent framerate :slight_smile:

This means we're getting closer to a usable camera app, and can now control stuff like the dithering algorithm applied by the Teensy, or the sensor's brightness/contrast on the fly.

Below a few tests with different dithering algorithms (I'll let the experts guess what they are)

Camera 2023-04-07 01.01.40

Camera 2023-04-07 01.01.58

Camera 2023-04-07 01.02.14

I posted some updates on twitter/mastodon but I figured I could give a heads up in this thread too.

I updated the prototype to make it more compact and portable, and I made some improvements to the playdate app.

It runs at about 3 fps (the image feed, not the entire app) and I still haven't taken the time to look at why it's not faster. I suspect it's the serial though. Anyway it's quite useable as is, arrow buttons cycle through 7 different dithering modes, A button saves a picture as .gif into the apps's Data folder. No need to use system level screenshots anymore! Makes it much faster and more convenient to take pictures!

I've started adding some status information on the screen. Maybe it'll become a DSLR style overlay, for now it's on the side.

Here are some examples I took today.


Next up, maybe add brightness or contrast control, maybe build a camera roll gallery thing although the SDK's scale method destroys dithered images so it'll probably need to be a full screen roll...

I also just had an idea of using the crank to record short animated gifs, like an old school camera. Maybe saving the data as an image quilt and then having an external tool to convert that back into gif/video ?



Left right to circle through settings, up down to change values within a setting. For now, settings are filter/dithering type, brightness, contrast, threshold level. The menu is essentially a single row gridview that contains a single column gridview in each cell. The main gridview's drawCell function draws the menu header and the nested vertical gridview underneath. I have no idea if this is reasonable, but it works and it is very flexible so I can test stuff quickly.


When the camera feed is enabled FPS drops to 16-18 and I'm not sure why (that's low, but still 4-6 times higher than the actual picture refresh rate...). Camera image is using a sprite; I just setImage on it when a new picture has been processed.


I'm working on a PCB design to make this (hopefully) easy to replicate, and I've also ordered a few cheap CS lenses to try out. It's bulkier (although most are smaller than the zoom lens pictured below) but (as expected) also much better quality than the plastic lens that comes with these OV7670 boards.

Here are a couple of macros. Will do more field testing tomorrow !




Just posting to encourage you to keep making progress and sharing it here because this is insane and I love it!


Thanks for the encouragements Scott :slight_smile:

I'm currently working on the case and PCB. I received a first PCB prototype which I obviously completely messed up, and I'm now going through several iterations of a case design. I think I'm closing in. It should come with a handful of neat little features (magnets to hold the playdate, selfie mode, etc) all while being relatively easy to build, but I need to do some more designing and 3d printing to refine the design and then I'll order a new bespoke PCB...



New PCB!

This time it's purple!

Also it works!

Time to finish the case!

I hate FreeCAD!


It looks so amazing!

Here are some purple PCBs from the Playdate archive. I'm pretty sure Playdate wouldn't have happened without OSHPark. :smiley:


Ok so here's an exclusive look at the almost finished case :wink:

I started it in FreeCAD but I grew tired (polite understatement) of its quirks so I rebuilt the whole project from scratch on Onshape and carried on from there. Best decision I ever made too late.

It prints in 4 parts without support, assembles without tools using press fit and snap locks. This test print took about 4 hours on a Prusa MK3s with PETG. The design in 4 parts leverages the textured bed sheet for a nice surface finish on all back and front facing surfaces.

The case is 1.5 Playdate tall - with the extra height at the bottom when held normally - and there's a chin kind of thing that makes the front face flush with the console. This serves several purposes but combined with the added thickness, makes it quite comfortable to hold (even for just playing!).

The chin part hides the USB cable and you can take the PD out and snap it on the other side of the case for some 1-bit selfie action without disconnecting the cable in the process. The camera bump is 0.5 Playdate tall like the front chin, and is not full width so it keeps the PD's power button accessible in this configuration too.

The PD is locked with magnets in both modes (but obviously better secured in regular mode).

The case holds a giant 5000mAh battery that charges the PD in addition to powering the camera hardware. I don't know how long it's going to run, but long. There's a power switch at the top of the case and a charging port at the bottom.

Right now it's possible to easily swap out the sensor board without opening the case so I can test different lens mounts (swapping the entire board). I don't know if that's useful beyond prototyping and I might change it in the final design.

There's one last cool little feature I'm not mentioning here, I'll save it for the next update :wink:

I'm quite happy with this last test and I'd say I'm ~90% done with the design by now. I have some small adjustments to make here and there but this is very close to the end goal.

I'll show off the inside in a later post; it might not look like much but it's the most complex 3d thing I've ever designed and it was a lot of fun-pain. I hope you like it!

Now the big question is, what color should I print the final make? :wink:


That's amazing!

I kind of think a black print works well: automatically matches (part of) the Playdate, as well as the lens.

Purple would be cool too though! Or anything but a slightly-wrong yellow.

1 Like

Agreed! I think I'll simply go with jet black instead of this glittery "galaxy black".


By the way, as I discovered making this "photo roll" project (free to adapt), scaling dithered images to 1/3 does a pretty decent job of preserving a wide variety of dithered tones. Works great for ordered dithers especially, but more random scatterings don't come out half bad either.

(And I like your dawn-of-cinema cranked video idea!)

1 Like

Mark 3 is now fully designed, assembled and operational yay :slight_smile:

pd cam selfie mode small

So I got back to the software side, added mirror mode for more comfortable selfies:

Next will be the finishing touches: a start screen, a camera roll. And I think there's a nasty memory leak somewhere because the PD always ends up crashing if left streaming from the camera for a couple of minutes straignt. Problem is, it's very hard to debug. Maybe I'll just put a timeout on the viewfinder and call it fixed.

I'll make a little video to demo the whole thing end to end in the coming days. And then I'll document the build process, tidy up the code, and put everything on github. I might try another revision of the case/hardware before I do as I'd like to make it a bit more generic (right now it's designed to fit exactly the battery pack and power circuit I used).

Oh and here's the one more thing I teased in the previous post: the reason why the PCB is purple (and oversized) is because we can see it through holes in the case that act as pockets to store the console and protect its screen during transport :slight_smile:

pd cam cover mode small



This is excellent. Forget the camera, it looks fun just to change the configurations around like a transformer!


Here's a little video I made :slight_smile:


I actually did find and test your viewer earlier and this is how I knew the images didn't scale too well with error diffusion based dithering :


However I returned to it tonight and I've found a simple fix :slight_smile:
Applying a small blur before scaling down makes a huge difference !

img:blurredImage(1, 1, gfx.image.kDitherTypeScreen, true)


I'll be factoring your code inside of the camera app next ! I guess instead of saving the pictures only as gif for easy export, I'll need to save 2 copies, one gif for export and one pdi that I can read back to render this viewer. No biggie.


Very nice! Turning the dither to an ordered one like that does the trick.

Using your code as a starting point, I've updated my menu class to support images, looks rather decent to me :slight_smile:

pd cam roll

I wrote some logic to store sort of a rolling buffer of last X thumbnails in memory rather than reading the filesystem all the time. I have lots to learn on PD memory management and cost of reading/writing files :slight_smile:



I use a rolling buffer of sorts for zooming in Outside Parties. Why throw out data that might be seen again soon? It helped a lot.