Gopdsdk: an another independent Go SDK and toolchain for Playdate

Hi everyone!

I’d like to introduce gopdsdk, an independent open-source Go SDK and toolchain for building Playdate games:

The project explores whether Go on Playdate can feel like a coherent SDK rather than a thin set of C bindings. Its design focuses on:

  • one public Go API for Simulator and device builds;
  • explicit ownership and deterministic cleanup of native resources;
  • game logic that can be tested as ordinary Go code;
  • a CLI that builds, runs, deploys and diagnoses the toolchain;
  • honest separation between unit tests, Simulator checks, device builds and physical hardware acceptance.

The current release is v0.6.0. It is still pre-1.0, but it already supports complete Simulator and physical-device workflows.

Getting started

go run github.com/Djunichi/gopdsdk/cmd/gopdsdk@v0.6.0 doctor

go run github.com/Djunichi/gopdsdk/cmd/gopdsdk@v0.6.0 init \
  --module example.com/my-game \
  ./my-game

cd my-game
go mod tidy

You can then build or launch the same game package for either target:

gopdsdk run .
gopdsdk run device .

The CLI also provides environment diagnostics and end-to-end probes:

gopdsdk doctor --probe
gopdsdk probe simulator --run
gopdsdk probe device
gopdsdk probe connection

Finding an executable is not treated as proof that the corresponding toolchain works: Simulator compilation, device compilation and USB deployment are reported as separate capabilities.

What is implemented today?

The current public SDK includes:

  • lifecycle events, buttons, crank and frame timing;
  • text, primitives, bitmaps, fonts and framebuffer access;
  • sprites, collisions, animation, tilemaps and cameras;
  • display control, offscreen drawing, transforms and stencils;
  • filesystem access and versioned persistence;
  • System Menu items, localization and Launcher exit;
  • accelerometer, battery, power and system preferences;
  • sample and streaming audio;
  • channels, synths, signals, instruments, sequences and effects;
  • microphone recording;
  • scoreboards and debug-message delivery;
  • video playback with screen and offscreen targets.

Native resources have explicit lifetimes. Owned bitmaps, sprites, fonts, files, audio players, synths and effects are closed deterministically, while borrowed values have restricted lifetimes. Correctness does not depend on finalizers.

Callbacks are bounded and suppressed after termination, and invalid operations such as use-after-close return defined Go errors rather than forwarding invalid handles to the C API.

A game built with gopdsdk

Crank Caverns is an external Playdate game built entirely against the public gopdsdk API.

It combines the SDK’s individual features in one game:

  • platforming with crank-assisted movement and double jumps;
  • sprites, collisions, animation, tilemaps and camera movement;
  • custom fonts, bitmaps, primitives and framebuffer drawing;
  • music and sound effects;
  • pause, lock, resume and termination handling;
  • main, pause and System Menu interfaces;
  • localized settings;
  • battery status and Launcher exit;
  • versioned save data with migration and corrupt-save recovery;
  • deterministic tests for gameplay and persistence.

The same game has been run in the official Windows Simulator and on a physical Playdate. A bounded 1,800-frame measurement reported approximately 33 ms mean frame time on both targets and a stable count of 18 explicitly owned native resources.

The physical-device build produced a 965,530-byte PDX and used 287,912 bytes of static RAM. These are bounded measurements rather than a claim of unlimited complexity or long-term performance.

Crank Caverns is useful evidence that the SDK’s features work together in a real external consumer, not only in isolated examples.

Simulator and device runtime

Simulator applications use the standard Go compiler and a native shared-library bridge.

Device applications use TinyGo 0.41.1 with:

  • hard-float Cortex-M7 compilation;
  • a conservative garbage collector;
  • a checked 256 KiB heap;
  • deterministic fail-stop behavior on panic or out-of-memory;
  • official Playdate setup and linker inputs.

The current device profile is intentionally a subset of Go. It does not support goroutines, channels, select, public reflection, finalizers or device paths requiring defer/recover. These restrictions are detected during the build instead of being left as unpredictable hardware failures.

Verification status

Pure-Go tests and external-consumer CLI checks run natively on Windows, macOS and Linux.

The complete official SDK, Simulator, device build, USB deployment and physical-device profile is currently verified on Windows with:

  • Go 1.26.5;
  • Playdate SDK 3.1.1;
  • TinyGo 0.41.1;
  • Arm GNU Toolchain 15.3.1.

macOS and Linux SDK, Simulator and device integration remain explicitly unverified. Reports and contributions from developers using those hosts would be especially valuable.

Relationship to pdgo

pdgo is another independent effort bringing Go to Playdate, with a more direct mapping of the official C API. It already exposes some areas that gopdsdk does not, notably general HTTP/TCP networking and Lua integration.

gopdsdk instead emphasizes a Go-oriented capability API, explicit resource ownership, deterministic tests, toolchain diagnostics and per-feature hardware evidence.

A fair summary today is: pdgo is broader in several direct C API areas, while gopdsdk goes deeper on the contracts and verification of its implemented vertical slices.

The projects are independent. gopdsdk uses the official Playdate SDK headers, documentation, examples and observable tools as its normative sources.

What is still planned?

Before 1.0, the roadmap includes:

  • completing the remaining graphics and display operations;
  • completing sprite configuration, queries and callbacks;
  • filling the remaining sound and system API gaps;
  • completing the offline filesystem and media audit;
  • hardening and documenting the TinyGo device profile;
  • freezing the public API and compatibility contract.

General HTTP/TCP networking is currently reserved for post-1.0 research rather than being rushed into the initial stable release.

Feedback is welcome, especially about:

  • the public API and ownership model;
  • missing capabilities that block real game designs;
  • macOS and Linux toolchain behavior;
  • device memory and performance;
  • the first-project experience.

Project:

Example game:

API:

Compatibility status:

Roadmap:

Thanks for reading! I’d be happy to answer questions about the API, toolchain or device runtime—and I’d love to see what other developers might build with Go on Playdate.

Hi everyone!

I’m happy to announce gopdsdk v0.7.0 and v0.8.0, two substantial updates to the independent Go SDK and toolchain for building Playdate games.

v0.7.0 — Graphics, bitmaps, fonts, and display information

This release expands the public graphics contract with:

  • Additional drawing primitives and graphics-state controls
  • Mutable bitmap data, copying and in-place loading
  • Bitmap tables, masks, mask collision, and rotated bitmaps
  • Persistent display-buffer snapshots
  • Text layout with wrapping, alignment, tracking, and leading
  • Font and glyph metrics, including advance and kerning
  • Logical display dimensions, refresh rate, and measured FPS

Related examples include bitmapdata, which demonstrates bitmap editing, masks, collision, rotation, tables, and screen snapshots, and fontsui, which covers the new text-layout and font-metrics API.

v0.8.0 — Complete offline sprite and collision facilities

This release significantly extends the sprite API with:

  • Sprite geometry getters and presentation controls
  • Image flipping, draw modes, opacity, stencils, and clipping
  • Explicitly owned native sprite tilemaps with live tile updates
  • Non-mutating collision checks and detailed line-hit queries
  • Bulk display-list operations and collision-world reset
  • Per-sprite procedural draw and update callbacks
  • Pair-specific collision-response callbacks

The callback API is deliberately bounded and lifecycle-aware: each context supports a fixed number of registrations, and callback slots are released deterministically when cleared or when their owning sprite is closed.

The main example is spritepresentation, an acceptance scene covering presentation state, native tilemaps, detailed queries, display-list operations, procedural drawing, updates, and collision-response callbacks. The collision example also demonstrates movement checks and the expanded query API.

Both releases preserve gopdsdk’s explicit ownership model: native resources have clear lifetimes, borrowed values cannot outlive their owners, and cleanup remains deterministic. The new functionality has been exercised with deterministic tests, the official Playdate Simulator, and a physical Playdate.

The project is still pre-v1, so API feedback, bug reports, and real-world game experiments are especially welcome!

Hi everyone!

I’m happy to announce gopdsdk v0.9.0, a new release of the independent Go SDK and toolchain for building Playdate games.

v0.9.0 - Complete offline sound facilities

This release substantially expands the public audio API with:

  • Owned audio samples with loading, reloading, data inspection, copying, decompression, playback ranges, and loop callbacks
  • Streaming player buffering, loop ranges, reload, and underrun controls
  • Explicit audio channels with source routing, volume, pan, effects, and modulation
  • Headphone, headset-microphone, and speaker-output state and control
  • Wavetable synthesis and custom generator synths
  • Envelope controls, LFOs, control signals, instruments, tracks, and sequences
  • Sequence, track, note, signal, and controller introspection
  • Bounded PCM and custom-generator callbacks

Custom audio callbacks remain lifecycle-aware and bounded. Go render callbacks run during frame updates, while the native audio thread only consumes fixed-size sample rings. An empty ring produces silence and records an underrun instead of re-entering Go or allocating from the audio thread.

Custom generator synths support native polyphonic voice copying and eight parameter slots. Raw C function pointers and userdata are intentionally not exposed; the Go API provides a portable ownership and callback contract instead.

The release includes several focused examples:

  • samples — owned sample buffers, data inspection, ranges, loops, and playback control
  • synthesis — envelope curvature, velocity sensitivity, and note-range scaling
  • wavetable — wavetable synthesis and modulation
  • callbackpcm — bounded stereo PCM generation and observable underrun recovery
  • generatorsynth — polyphonic custom generator voices and parameters
  • sequenceinspect — sequence, track, note, and controller inspection

The new functionality has been exercised with deterministic tests, the official Playdate SDK 3.1.1 Simulator, conservative hard-float device builds, USB deployment, and a physical Playdate. Final acceptance also covered routing, headphone states, samples, synthesis, callbacks, underruns, lifecycle cleanup, bounded memory growth, a conservative-GC soak, and unchanged post-run device logs.

The verified Windows toolchain remains:

  • Go 1.26.5
  • Playdate SDK 3.1.1
  • TinyGo 0.41.1
  • Arm GNU Toolchain 15.3.1

macOS and Linux continue to run the native Go and external-consumer test suites, while official SDK, Simulator, device-build, USB, and hardware integration on those hosts remain unverified. Reports from developers using those platforms would be especially welcome.

The project is still pre-v1, so feedback on the audio API, ownership model, device behavior, and real-game use cases is very welcome!

Project:

Release:

This looks awesome, great job! :clap:

Hi everyone!

I’m happy to announce gopdsdk v0.10.0, a new small release of the independent Go SDK and toolchain for building Playdate games.

v0.10.0 - Complete system integration

This release completes the offline system and lifecycle facilities planned for gopdsdk’s pre-v1 roadmap.

The new SystemControls API includes:

  • Copied launch arguments and loaded-game path
  • Restart with caller-provided launch arguments
  • Owned 400×240 system-menu images
  • Auto-lock and crank-sound control with automatic lifecycle restoration
  • Mirror-started and mirror-ended lifecycle events
  • Bounded ordered button callbacks with overflow reporting

The new SystemEnvironment API includes:

  • Current Playdate epoch time with millisecond precision
  • Validated epoch/calendar conversion
  • An independent high-resolution elapsed timer
  • Copied OS version, language, and game PDX version information

Input.DeltaSeconds now uses the wrapping monotonic millisecond clock, so frame updates no longer reset the public elapsed timer.

The release also completes an audit of the remaining low-level system functions. Allocator, instruction-cache, printf-style formatting/parsing, fatal-error, raw userdata, and similar runtime-plumbing entry points remain intentionally outside the public Go API. Native console logging remains a development facility, while measured FPS is available through the existing read-only display API.

Two focused examples demonstrate the new functionality:

  • systemcontrol — launch state, restart, menu images, system settings, mirror lifecycle events, and ordered button callbacks
  • systemenvironment — epoch/calendar conversion, elapsed-time reset, and device information

The verified toolchain remains:

  • Go 1.26.5
  • Playdate SDK 3.1.1
  • TinyGo 0.41.1
  • Arm GNU Toolchain 15.3.1

The project is still pre-v1, so feedback on the system APIs, lifecycle behavior, portability, and real-game use cases is very welcome!

Project:

Release:

Hi everyone!

I’m very happy to announce gopdsdk v1.0.0, the first stable release of the independent Go SDK and toolchain for building Playdate games.

v1.0.0 — Stable offline Playdate Go SDK

This release completes the offline SDK roadmap and freezes the documented public API, ownership and error contracts, callback behavior, CLI surface, and device Go profile for the v1.x line.

An external Go module can now create, test, build, optimize, and release an offline Playdate game using only public gopdsdk APIs, without a game-owned C bridge or imports from internal packages.

Some of the final additions on the road to 1.0 include:

  • playdate/schedule, a fixed-capacity cooperative scheduler for frame-spanning work
  • Delayed, deadline, and repeating tasks driven by the Playdate clock
  • Bounded non-blocking queues and deterministic multi-queue polling
  • playdate/json, a bounded and reflection-free JSON implementation for device builds
  • Normal-return defer support with conservative GC
  • A documented, fail-closed subset of public reflection
  • Nested audio-channel routing and borrowed channel outputs
  • Dry and wet channel-level modulation signals
  • Complete LFO initial-phase, deterministic random-seed, and global-update controls
  • Stable semantic-versioning, migration, compatibility, support, and deprecation policies

The release was exercised through native CI on Windows, macOS, and Linux, including the Linux race detector. Windows additionally passed official Playdate SDK 3.1.1 Simulator integration, conservative hard-float device builds, USB deployment, physical Playdate acceptance, lifecycle cleanup, bounded-memory and resource checks, and conservative-GC soak testing.

The verified toolchain is:

  • Go 1.26.5
  • Playdate SDK 3.1.1
  • TinyGo 0.41.1
  • Arm GNU Toolchain 15.3.1

Current limitations

The device target intentionally supports a bounded sequential Go profile rather than the complete desktop Go runtime.

  • Goroutines are not supported; use stackless playdate/schedule tasks.
  • Blocking channels and select are not supported; use bounded queues and deterministic polling.
  • time.Now, time.Sleep, timers, and tickers are not supported on device; use the Playdate clock and scheduled tasks.
  • Panic is a terminal fail-stop trap. It does not unwind the stack or run deferred cleanup.
  • recover is unsupported.
  • Normal-return defer is supported, but dynamic defer registration can allocate and should be measured before use in update hot paths.
  • Only the documented reflection subset is supported. Dynamic calls, reflected methods and channels, and other unverified paths are rejected at link time.
  • fmt and the standard encoding/json package are replaced by smaller device-oriented alternatives.
  • Finalizers and application cgo are unsupported; native resources require explicit ownership and cleanup.
  • Networking is not part of the 1.0 public contract.
  • Official SDK, Simulator, device-build, USB, and hardware verification is currently established on Windows. macOS and Linux run the native Go and external-consumer CI suites, but their official SDK and hardware integration remains unverified.

These boundaries are deliberate: the goal is a predictable Playdate runtime with explicit ownership, bounded work, and fail-closed device builds rather than silently accepting Go features that do not behave correctly on the hardware.

What comes next?

The first post-1.0 priority is validating the stable SDK through one or more commercially realistic external games. This should exercise long-lived resources, multiple scenes, saves, audio, callbacks, lifecycle transitions, performance budgets, packaging, and release workflows.

For v1.1, I plan to investigate networking and multiplayer feasibility. The current idea is to prototype:

  1. An HTTP leaderboard or asynchronous turn/ghost exchange with an offline queue.
  2. A small authoritative server with two outbound Playdate TCP clients.
  3. Physical two-device testing across disconnects, pause, lock, reconnection, and server-version changes.

This is research rather than a promised networking API. I want to measure permission flow, callback behavior, memory use, bandwidth, latency, and failure recovery before committing to a stable public design.

Reports from developers using macOS or Linux would be especially valuable, as would feedback from anyone trying gopdsdk in a real game.

Thank you to everyone who followed the project, tested it, or shared feedback during the pre-1.0 releases!

Project:

v1.0.0 release:

Stable API and compatibility details:

@greg I would really appreciate it if, if possible, you could list my SDK on the “Useful Links” page so that developers can see it, test it, and provide feedback for future development.

There is already a more fully featured Go SDK link in useful links section.

Hi everyone!

I’m happy to announce gopdsdk v1.2.0, together with dedicated integrations for Visual Studio Code and GoLand.

The last releases focused on making Playdate development in Go feel less like a collection of build commands and more like a coherent development environment. The SDK now provides a stable analyzer, machine-readable tooling protocols, project diagnostics, Simulator workflows, and physical-device operations that both editor integrations can use without parsing human-readable CLI output.

gopdsdk v1.1 — Playdate-specific Go analysis

The previous v1.1 release introduced gopdsdk check and gopdsdk lsp.

The analyzer understands constraints that ordinary Go tooling cannot infer:

  • the supported device-side Go subset;
  • application and lifecycle structure;
  • optional Playdate capabilities;
  • ownership and deterministic cleanup of native resources;
  • borrowed callback data and escape risks;
  • ignored errors and significant results;
  • manifest and packaged-resource validation;
  • structural performance risks in update and audio callbacks.

It supports deterministic text and JSON output, configurable rules and severities, inline suppressions, adoption baselines, safe fixes, related locations, and default, experimental, and deep analysis profiles.

gopls still owns normal Go completion, navigation, formatting, and refactoring. The gopdsdk language server runs alongside it and focuses only on Playdate-specific contracts.

gopdsdk v1.2 — stable tooling contracts

v1.2 adds the machine-readable contracts needed by editor integrations and other tools:

  • gopdsdk capabilities for version and feature negotiation;
  • structured doctor and Simulator/device/USB probe results;
  • structured Simulator and device build results;
  • cancellable build, packaging, deployment, launch, and cleanup progress;
  • normalized source locations for compiler failures;
  • structured crashlog and errorlog retrieval;
  • an analyzer rule catalog sourced directly from the installed gopdsdk version;
  • deterministic baseline create, update, inspect, and validate workflows;
  • explicit Data Disk mount and safe-eject operations;
  • transactional replacement of Simulator and device .pdx artifacts.

Discovery and readiness remain deliberately separate. Finding pdc, TinyGo, or pdutil does not by itself mean that the Simulator, device toolchain, USB connection, or hardware workflow is ready.

The release is backward-compatible with the existing v1 native API. Existing games should not require source changes.

Visual Studio Code extension

The new gopdsdk extension for Visual Studio Code provides:

  • Playdate diagnostics and safe quick fixes directly in the editor;
  • exact-version rule help and related source locations;
  • Simulator build and run commands;
  • device connection checks;
  • device build, installation, and launch;
  • explicit Data Disk mount and safe eject;
  • opt-in crashlog and errorlog viewing as read-only documents;
  • project and toolchain health checks;
  • project creation through gopdsdk init;
  • analyzer target, profile, rule, severity, and baseline management;
  • comparison of shared, Simulator, and device findings;
  • multi-root workspace support;
  • a Playdate activity view with workspace, target, health, device, and diagnostic state.

Build tasks are cancellable, structured progress is shown in the UI, and compiler source locations are published in the Problems view.

The extension works alongside the standard Go extension: gopls continues to provide normal Go language features.

GoLand plugin

The gopdsdk plugin for GoLand provides the same underlying SDK and analyzer workflows using native IntelliJ Platform UI:

  • Playdate diagnostics and analyzer-provided safe fixes;
  • a dedicated Playdate tool window;
  • project-health and toolchain-readiness views;
  • Simulator build and run configurations;
  • device build, installation, and launch actions;
  • connection, Data Disk, crashlog, and errorlog operations;
  • project creation;
  • analyzer configuration and rule browsing;
  • suppression and baseline administration;
  • shared/Simulator/device finding comparison;
  • status-bar progress and Run console integration.

The plugin uses GoLand’s native LSP client. It does not embed a second analyzer or copy gopdsdk’s rule catalog: the installed gopdsdk executable remains the source of truth.

The current plugin targets GoLand 2026.1.4 through 2026.2.

A shared editor architecture

Both integrations follow the same model:

VS Code / GoLand
    |
    |-- gopls or GoLand Go support
    |      normal Go language features
    |
    `-- gopdsdk lsp and CLI
           Playdate diagnostics
           safe fixes
           project health
           Simulator workflows
           device workflows

The editor clients are intentionally thin. Analysis, compatibility rules, readiness checks, and build behavior live in gopdsdk itself, so command-line use, CI, VS Code, and GoLand share the same contracts.

Links

Feedback is especially welcome on:

  • the first-project experience;
  • analyzer usefulness and false positives;
  • VS Code and GoLand workflows;
  • macOS and Linux SDK integration;
  • Simulator and physical-device behavior;
  • features that would make gopdsdk practical for larger games.

Thanks to everyone who has followed the project, tested it, or shared feedback!