Docs

Orbit

Install and make Orbit yours, the idle game in SwiftUI + Metal. Version 1.0.0.

A calm idle voyage printed like a screenprint travel poster: bodies circling a small sun, alignments, research, and supernovas that sail your sky to new regions. This guide takes you from download to a running game under your own name. It covers version 1.0.0. See the screens on its game page.

Requirements

  • Xcode 26 and an iOS 17.0 or later deployment target
  • Tuist 4 (brew install tuist)
  • An Apple Developer team for devices, Game Center, iCloud and the widget. The simulator runs without one.

Install

Download

Included with SwiftPieces Games. Not signed in? The button takes you to sign in or create an account, then starts the download when you're back. Unzip the archive; it contains one folder, Orbit/.

Make it yours

cd Orbit
scripts/setup.sh --name YourGame --bundle-id com.you.yourgame --preset riso

The script renames the target, scheme and bundle ids, rewrites the StoreKit product ids, sets the starting preset and runs tuist generate. To keep the name Orbit for now, run tuist generate instead.

Run it

Open YourGame.xcworkspace, choose an iPhone simulator and run the YourGame scheme. The scheme uses Configuration/Products.storekit, so the shop works before App Store Connect is set up.

What's in the project

  • Content: Endless, with a tuned curve
  • Game Center: 3 leaderboards, 29 achievements, 1 challenge
  • Shop: Prism packs, Starter pack, Permanent 2x (Eternal Glow), Glow boosts and time warps, Sol skins
  • Built on: GameCore, Feel, Economy, GameServices, Shaders, Motion, GameUI
  • Presets: voyage, riso, kraft
  • Swift: 8,861 lines in 83 files

Rebrand options

scripts/setup.sh changes everything that names the game, in one command:

OptionWhat it sets
--nameTarget, scheme and product name
--bundle-idBundle id. The widget, modules, App Group (group.<bundle-id>) and tests derive theirs from it
--display-nameThe name under the icon. Copy that mentions the game reads it at runtime
--teamYour team id. Required for devices, Game Center, iCloud and App Groups
--presetThe starting paper stock: voyage, riso or kraft
--product-prefixApp Store Connect product ids. Defaults to <bundle-id>.store

Then create the Game Center items in Configuration/GameCenter.md and the five products in Configuration/Products.storekit in App Store Connect. The game runs without either: Game Center reports queue until the player signs in, and the shop says when the App Store isn't reachable.

Launch arguments

Launch arguments for demos, screenshots and tests (Debug builds):

ArgumentEffect
-SPResetSaveStart from a fresh save
-SPSkipTutorialStart after the tutorial
-SPDemoSkyA mid-game sky: every body, some research, prisms
-SPOfflineHours 6Pretend you were away this long, to see the offline reveal
-SPPreset kraftStart with a paper stock
-SPTab supernovaOpen a tab: orbit (System), supernova (Chart), observatory (Study), shop (Supply)
-SPNoAudioNever start the audio engine, for CI or a Mac whose audio server is stuck

Structure

App/                   @main, the root view (sky, nav, moments, sheets), live events file, icon
Features/Play          Renderer, Orbit.metal, game session, juice director, HUD, bodies shelf,
                       System screen, Ship's log reveal, evolution card, notification soft ask
Features/Observatory   Study: research as a printed star chart
Features/Supernova     Chart: the route, the supernova boarding pass (hold to set sail), the arrival
Features/Shop          Supply: prism items, Sol skins, StoreKit items, restore
Features/Log           Daily gift, missions, achievements, stats and leaderboards
Features/Settings      Paper stock, colour-blind palette, Reduce Motion, battery saver, sound, haptics
Features/Onboarding    The first-launch title poster on the paper (the rest is taught in play)
Modules/GameCore       BigNumber, number text, fixed-step loop, event ring, seeded random, saves
Modules/Economy        Wallet, daily streak, missions, live events, offline earnings, catalog, fairness
Modules/OrbitKit       Orbit's rules and world: bodies, forms, alignments, meteors, research,
                       supernova, regions and the voyage, achievements, save migration,
                       balance simulator
Modules/DesignSystem   GameTheme tokens, paper stocks, region inks, Bowlby One and Archivo
Modules/Shaders        Metal context, printed sky, post chain (grain), particles, SwiftUI effects
Modules/Feel           Procedural synth, audio engine, haptics, shake and springs, quality tiers
Modules/Motion         Button state machine, idle variations, character and reward protocols
Modules/GameUI         Printed tickets, stamps, halftone, buttons, rolling numbers, nav strip,
                       sheets, toasts
Modules/GameServices   Game Center, StoreKit 2 store, iCloud key-value sync, reminders
Modules/AppCore        App identity, launch options, settings, widget snapshot
Widget/                WidgetKit extension: "Your sky"
Configuration/         Products.storekit, GameCenter.md
Tests/                 Engine tests (Swift Testing) and first-session UI tests

GameCore, Economy and OrbitKit import only Foundation. They are the game: deterministic, seeded, and testable anywhere (swift test runs them on Linux too). Everything above them only presents.

How it runs

  • Simulation. OrbitWorld.step() runs at a fixed 30 Hz from a CADisplayLink, with frame time clamped to 0.25 s. It never imports SwiftUI. It emits OrbitEvents into a ring buffer instead of calling the UI.
  • Presentation. GameSession (@Observable) copies what the HUD shows out of the world at most ten times a second, and only values that changed, so SwiftUI never re-evaluates at frame rate. JuiceDirector turns each event into light, particles, sound and haptics scaled to how rare it is: a tap gets a pulse and a tick, an evolution gets the full stack 60–150 ms apart.
  • Rendering. The world draws into a half-float scene texture as a screenprint: a flat night ink with a halftone glow off the horizon, star specks and the region's planet; the paper margin ruled off in ink; cream orbit lines (dashed until owned) with dotted trails; the alignment beam as a striped wedge with its red plate off register; flat inked bodies with a halftone shade in five forms; Sol as a sunburst of concentric inks; flat meteor streaks. A composite adds paper grain, a light vignette and dither. Particles are pooled flat ink flecks, allocated once.
  • Quality. QualityMonitor follows thermal state and Low Power Mode: full (120 fps, bloom, 512 particles), reduced (60 fps, no bloom, 192 particles) and minimal (30 fps, 64 particles, lighter halftone). Battery saver in Settings caps it at reduced.
  • Offline. On return, OrbitWorld.resume(at:) credits up to the cap (2 hours at 40%, raised by research to 8 hours at 80%) and the reveal plays it back. A reminder can say when the sky is full; it's asked for softly, only after the first return.

Theming

Every view reads @Environment(\.gameTheme); the renderer reads the same theme as uniforms. The paper stocks are Voyage (cream poster paper, navy ink, signal red and mustard), Riso (off-white, federal blue and fluorescent pink) and Kraft (brown wrapping paper, umber and orange), each with body inks, motion, sound scale and post-processing. Settings switches them live. The sky's inks come from the region the voyage has reached: Region in OrbitKit names the eight stops of the chart, worked out from the supernova count (nothing new in the save), and GameTheme.region(_:) reprints the sky with that region's inks from GameTheme.regionInks. The colour-blind variant moves positive and danger apart in lightness and swaps the marble set; shape cues (rings, moons, crowns) carry form, not colour alone. To make your own, copy a preset in Modules/DesignSystem/Sources/Presets.swift.

Balance

Every number lives in OrbitRules and BodyDef.all. BalanceSimulator plays the game headless; tests assert the early hooks and that idle players still progress. See BALANCE.md for the pacing table and how to change it.

Swapping in Rive or your own art

The reward reveal takes any view conforming to RewardAnimation (OfflineReveal(report:bloom:collect:)), and characters conform to CharacterView, which reads CharacterInputs (look, energy, reaction, stage). Map those to a Rive state machine's inputs of the same names and swap one line. Bodies and Sol are procedural Metal, so there are no textures to replace; change their inks in the theme.

Store and fairness

Prisms buy time savers (glow boosts, time warps, streak freezes) and Sol skins. Real-money items are prism packs, a one-time Starter Sky and Eternal Glow (×2 output, permanent). A test (catalogIsFair) checks nothing for sale grants shards, research or anything else only play should earn. The store never grants by itself: each verified transaction goes to the game once, by transaction id, so restores and replays never pay twice. For anything valuable, put your server in front with a TransactionValidator.

Tests

tuist test

Engine tests cover big numbers, number formatting, the loop, saves and migration, the economy, the rules, the world and pacing. UI tests play the first minute and collect an offline reveal.

Changelog

1.0.0

2026-10-24

  • Voyage art direction: a screenprint travel poster. Flat inks on cream paper with halftone, an off-register red plate and hard ink shadows; Bowlby One and Archivo. Bodies in five printed forms round a sunburst Sol, under a printed sky that each supernova sails to a new region of the chart (eight regions, each with its own inks and planet). Paper stocks Voyage, Riso and Kraft, plus a colour-blind palette.
  • Screens as print: System (the sky), Chart (the route and the supernova boarding pass, then the arrival), Study (research as a printed star chart), Supply, and the Ship's log for the offline return.
  • Deterministic engine (GameCore, Economy, OrbitKit) with a fixed 30 Hz step, seeded randomness, an event ring and save migration, tested with Swift Testing.
  • Eight bodies with milestones and three polish tiers; alignments that grow while the ray is open and pay Insight; meteors; 12 studies in the Observatory; supernova with shards.
  • Offline earnings with a reward reveal; a soft-asked reminder when the sky is full.
  • Daily gift on a seven-day cycle with streak freezes, three daily missions, rotating weekly live events from a JSON file.
  • Game Center: 3 leaderboards, 29 achievements with progress, 1 challenge, an offline queue.
  • StoreKit 2 shop with prism packs, a starter pack and Eternal Glow, idempotent delivery, restore, and a fairness test over the catalog.
  • iCloud key-value save sync with a merge that never loses progress.
  • Home and Lock Screen widget showing Stardust and when the sky fills.
  • Procedural audio (no sound files), Core Haptics, juice scaled to how rare each moment is, Reduce Motion variants, VoiceOver labels on the HUD, Sol and meteors.
  • Thermal and Low Power Mode quality tiers, 120 Hz on ProMotion, Game Mode.
  • One-command setup, a balance simulator, and first-session UI tests.