---
name: steamdeck-dev
trigger: /steamdeck-dev
description: >
  Everything needed to build, run, and ship apps and games on Valve's Steam
  Deck — hardware specs (LCD + OLED), SteamOS, and four dev paths: Godot
  native Linux export (primary), Proton for Windows builds, Flatpak for
  desktop apps, and Steam distribution + Deck Verified. Includes a REVIEW
  rubric to audit a project against Deck best-practices. Use when targeting
  the Steam Deck: porting a game/app, controller or touchscreen support,
  1280x800 display, suspend/resume, battery/TDP, gamescope, or a Deck
  Verified submission.
user_invocable: true
---

> **Public / shared version** — trimmed from a private Claude Code setup and
> posted at smereski.com as a reusable pattern.

# Steam Deck Dev

## What this is

A goal-driven reference for getting apps and games running and feeling great
on a **physical Steam Deck**, plus the surrounding dev paths (Proton, Flatpak,
Steam distribution).

The Deck is an x86_64 PC running **SteamOS 3** (Arch-based, immutable root,
KDE desktop mode, Gamescope compositor, Steam Input layer, Proton for Windows
games). Native Linux is the best target — no Proton overhead.

Two modes:
- **BUILD** (default) — apply to a task: export, deploy, fix input, ship.
- **REVIEW** — audit an existing project against Deck best-practices.

## The one decision that routes everything

> **What is the binary, and where does it run?**

| You have… | Path | Runtime |
|---|---|---|
| Godot 4.x game | **Native Linux** (best) | Runs directly on SteamOS |
| Windows-only build / dependency | **Proton** | Wine fork wraps the .exe |
| Flutter/Electron desktop app (non-game) | **Flatpak** | SteamOS desktop mode |
| Shipping on the store / want the badge | **Steam + Deck Verified** | — |

Always prefer native Linux. Use Proton only when a Windows-only dependency
forces it.

## Hardware reference

Target the **lower** spec (LCD) so it runs everywhere; OLED headroom is a
bonus.

Both models: **1280x800, 16:10, touchscreen, 4-15W TDP, x86_64 Zen2 / RDNA2
(8 CU, Vulkan)**.

- LCD: 60Hz fixed, ~400 nit, 40Whr.
- OLED: up to 90Hz, 1000-nit HDR, 50Whr.

Design rules that fall out of the hardware:
- **1280x800 (16:10), not 16:9.** Support 1280x800 AND 1280x720. Never
  hardcode resolution.
- **Legibility:** smallest font ≥9px at native (hard min), aim ≥12px;
  readable at 30cm. 7-inch screen + thumbs = big tap targets.
- **Battery/heat:** cap fps (40/60 LCD, up to 90 OLED), prefer the lighter
  renderer, don't peg the GPU on a menu screen.
- **It suspends instantly.** Games must survive focus-out → resume without
  crashing.

## Path 1 — Godot → Native Linux (recommended)

### Export

```bash
# Requires Godot export templates for Linux/X11 to be installed.
# Run headless from a shell (adjust binary path for your install):
godot --headless --export-release "Linux/X11" build/mygame.x86_64
```

After export, verify the file exists and is > a few MB before deploying.

**Winget Godot shim gotcha:** the `godot` command from `winget install Godot`
on Windows may be a stub that spawns zombie processes. If the export hangs,
kill all `godot*` processes and use the direct path to the real Godot console
binary.

### Deploy to Deck over SSH

```bash
# Copy build to Deck (Deck runs SSH on port 22 in developer mode)
scp -r build/ deck@<deck-ip>:~/games/mygame/
ssh deck@<deck-ip> "chmod +x ~/games/mygame/mygame.x86_64"
# Add as Non-Steam Game in Steam's Game Mode UI
```

### Proxy-verify on your dev machine (no Deck needed)

Force 1280x800 to check UI fit without physical hardware:
```bash
# Linux dev machine with gamescope installed:
gamescope -W 1280 -H 800 -r 60 -- ./mygame.x86_64
# Without gamescope, use SDL_VIDEODRIVER and a windowed forced res:
SDL_VIDEODRIVER=x11 ./mygame.x86_64 --windowed --resolution 1280x800
```

**Stop condition:** no Deck reachable over SSH → run proxy gates only and
mark real-Deck sign-off as PENDING. Never mark it done without hardware
verification.

## Path 2 — Proton (Windows builds)

Use only when a Windows-only dependency prevents native Linux export.

1. Build your Windows binary normally.
2. Add to Steam as a Non-Steam Game, then force a Proton version in
   Properties → Compatibility.
3. Test: launch from Game Mode on Deck; check for Proton-specific quirks
   (file-path casing, DX12 vs Vulkan, audio drivers).
4. Validate suspend/resume — Proton games sometimes need `esync` / `fsync`
   tuning.

For a game destined for the Steam store, check the Proton compatibility
database (ProtonDB) for your engine/framework version.

## Path 3 — Flatpak (Flutter / Electron desktop apps)

```yaml
# flatpak-manifest.yml skeleton
app-id: com.yourname.yourapp
runtime: org.freedesktop.Platform
runtime-version: '23.08'
sdk: org.freedesktop.Sdk
command: yourapp
finish-args:
  - --share=network
  - --share=ipc
  - --socket=wayland
  - --socket=fallback-x11
  - --device=dri
modules:
  - name: yourapp
    buildsystem: simple
    build-commands:
      - install -Dm755 yourapp /app/bin/yourapp
    sources:
      - type: file
        path: yourapp
```

Build and install locally:
```bash
flatpak-builder --user --install build-dir com.yourname.yourapp.yml
flatpak run com.yourname.yourapp
```

## Path 4 — Steam + Deck Verified

Requirements for the green "Verified" badge (Valve's checklist):
- **Controller support:** full Steam Input integration, no keyboard/mouse
  required.
- **Default configuration:** a recommended controller layout ships with the
  game.
- **Display:** native 1280x800 support; text legible at 30cm; no text
  cut-off.
- **Seamless:** launches and exits cleanly; no setup wizard; no manual
  launcher steps.

Submit via the Steamworks partner portal under the "Steam Deck Compatibility"
section. Valve will review within a few weeks.

## Input and touch (don't skip)

The Deck is a gamepad AND a touchscreen AND two trackpads plus gyro, all
funneled through **Steam Input**. Every screen must be fully controller- and
touch-navigable — no mouse-only path.

Key points:
- Use Steam Input action sets, not raw button codes.
- Map all UI actions to both controller buttons and touch regions.
- Show Deck-appropriate glyphs (ABXY, not keyboard keys) when a controller
  is active.
- Test on-screen keyboard integration for any text-entry field.

## REVIEW rubric

Use this checklist to audit an existing project:

### Input mapping
- [ ] All gameplay and UI reachable via controller alone
- [ ] Touch controls map cleanly to the touchscreen
- [ ] Steam Input action set defined (not raw SDL button polling)
- [ ] Controller glyphs shown (not keyboard icons)
- [ ] On-screen keyboard triggers for any text input field

### Resolution scaling
- [ ] Supports 1280x800 (16:10) natively
- [ ] Also works at 1280x720 (pillarboxed or letterboxed gracefully)
- [ ] No hardcoded pixel offsets assuming a specific resolution
- [ ] Smallest readable text ≥ 12px at native res

### Suspend / resume
- [ ] Game pauses cleanly on focus-out (OS suspend)
- [ ] Resumes without crash, corruption, or audio glitch
- [ ] Network reconnects gracefully if needed after resume

### Controller layout
- [ ] Default controller layout exported and submitted to Steam
- [ ] Gyro support configured if applicable (aim / pan use cases)
- [ ] Trackpad emulation mode set appropriately (mouse / joystick / custom)

### Battery / performance
- [ ] Framerate cap in place (40 or 60 fps LCD; up to 90 OLED)
- [ ] GPU not pegged at 100% on menus or loading screens
- [ ] TDP headroom tested under sustained load (target 10-12W for LCD)

## Gotchas

- Winget `godot` on Windows may be a zombie-spawning shim — use the direct
  console binary path for headless exports.
- `gamescope` is the Deck's compositor; some rendering quirks only appear
  under it, not under a plain desktop window manager.
- Proton file-path casing: Linux is case-sensitive, Windows is not. A path
  like `Assets/Texture.png` and `assets/texture.png` are different files.
- Flatpak sandbox: network, filesystem, and device permissions must be
  explicitly granted in the manifest `finish-args`.
- Real-Deck hardware sign-off cannot be self-certified — it requires running
  on the physical device in Game Mode.
