← Case studies

Case study

Space Horror FPS: a 3D shooter in SceneKit from one prompt

One prompt made a neon arena shooter with waves of enemies. Two plain-English follow-ups added a plasma cannon, a railgun, a radar and a new enemy.

Space Horror FPS running on a Mac
Prompts
1 + 2

one build, two follow-ups

First draft
15 min

writing the code in the cloud

Follow-ups
1.5 to 6 min

a reply, then a compile on the Mac

AI usage
≈661 credits

whole session, from the usage log

Times and usage come from the build log. Usage is the AI session’s running total at the last reply.

Model: Claude Sonnet 5.5, run through Claude Code.

The idea

Could one prompt make a good-looking 3D shooter with no model files, no textures and no sound files? The prompt asks for Apple's SceneKit for the 3D world and SpriteKit for the HUD, and says everything must be made in code. It also tells the builder to read Apple's documentation first, so it does not rely on memory for the APIs. It was built with the SiliconDevKit desktop app, so the code was written in the cloud and compiled on a Mac.

See it play

A screen recording of the finished game, played on a Mac.

The whole conversation

Every message below is word for word, as it appeared in the desktop app. The first one is the exact prompt. The other two are follow-ups in plain English, each asking for new weapons and enemies. One follow-up was stopped early and sent again, so it appears once here. Nothing was edited or typed by hand in between.

Space Horror FPS
Build a Mac first-person shooter called Hollow Point, a small but good-looking 3D game in one window. It uses Apple's SceneKit (import SceneKit) for the 3D world, SpriteKit for the HUD, and runs at 60 frames per second on Apple silicon. Everything is made in code: no model files, no texture files, no sound files, no asset catalog and no packages. RESEARCH FIRST (use WebSearch and WebFetch before you write code) Do not rely on memory for these APIs. Read Apple's documentation for: (1) SCNView, SCNScene, SCNRenderer and the SCNSceneRendererDelegate update loop (renderer(_:updateAtTime:)); (2) SCNPhysicsWorld and SCNPhysicsBody (categoryBitMask, contactTestBitMask, kinematic and dynamic bodies, SCNPhysicsContactDelegate) and SCNPhysicsWorld.rayTestWithSegment; (3) SCNMaterial with physicallyBased lighting, SCNCamera (wantsHDR, bloomIntensity, motionBlurIntensity, ambient occlusion), SCNParticleSystem, fog (scene.fogStartDistance); (4) mouse look on macOS: CGAssociateMouseAndMouseCursorPosition, NSCursor.hide, mouseMoved with deltaX and deltaY, and how to keep a mouse captured in a window; (5) GCController or key events for WASD; (6) AVAudioEngine with AVAudioPCMBuffer for sounds made from numbers. Where a page disagrees with this prompt, follow the page and say what changed. THE GAME - One arena level built from boxes and cylinders: a large room with pillars, crates, a raised platform and two side corridors, with a dark sky gradient and fog. Walls are static physics bodies so the player and enemies cannot pass through them. - Player: first person camera at eye height on an invisible capsule. WASD to move, mouse to look (clamp the pitch), Shift to sprint, Space to jump, Esc to release the mouse and pause, click to capture it again. Smooth acceleration and a small head bob. Do not let the player fall through the floor or slip through a wall; use a physics body with the player's capsule, damping and a speed limit. - Weapon: a gun model made of boxes shown at the bottom right of the view, a hitscan shot with an SCNPhysicsWorld ray test from the screen centre, muzzle flash light, a short recoil animation, a spread that grows while firing, 12 rounds, reload on R (about 1.5 seconds), a crosshair that reacts to a hit. A bullet that hits a wall leaves a small spark particle; one that hits an enemy shows a hit marker. - Enemies: three kinds built from primitives with simple walk animation (swing the limbs with SCNAction): a runner (fast, weak), a soldier (medium, shoots back with a visible tracer and some inaccuracy) and a brute (slow, tough, melee). They chase the player by steering toward them and around obstacles (simple wall avoidance by ray tests, not a navmesh). They spawn at the edges in waves, each wave bigger than the last, with a short break between waves. - Health and damage: the player has 100 health with a red screen flash, a slow regeneration after 5 seconds without damage, and a game over screen with the wave reached and the best wave (UserDefaults) and "Press Return to play again". Pickups (health and ammo) drop from some enemies. - Looks: use .physicallyBased materials with roughness and metalness values for the concrete, metal and crates (colours and procedural noise images you draw with Core Graphics into an NSImage, not files), one directional light with soft shadows, a few point lights and emissive strips on the walls, HDR with bloom and a slight vignette, ambient occlusion where available, and fog. Death makes an enemy collapse and fade with a small particle burst. It should look clean and modern, not like a grey box. - Sound: synthesize every effect with AVAudioEngine (gunshot as filtered noise with a fast decay, reload clicks, hit, enemy hurt and death, pickup, low ambient drone). Master volume and a mute key (M). No files. - HUD: a SpriteKit overlay scene (SCNView.overlaySKScene) with health bar, ammo, wave number, score, a small FPS counter that can be toggled with F, a pause menu and a title screen with a Start button. PERFORMANCE AND HONESTY - Target 60 frames per second at 1280 by 800 or the window size. Reuse nodes (a pool for bullets, sparks and enemies), share geometries and materials, flatten static level geometry with flattenedClone where it helps, keep the number of lights low, and set SCNView preferredFramesPerSecond to 60 and antialiasingMode to .multisampling4X. Use a fixed time step for game logic that is separate from drawing. Show the real measured FPS, never a fake number. - Do not fake anything. If a feature cannot work (for example ambient occlusion on some systems), skip it quietly and keep the game playable. QUALITY - macOS 13, Swift 5 language mode, SwiftUI shell hosting an SCNView through NSViewRepresentable (a custom SCNView subclass that handles keyDown, keyUp, mouseMoved, mouseDown and acceptsFirstResponder). Only Apple frameworks, no Xcode project or asset catalog. - Modular files: GameController (state, waves, score), LevelBuilder, PlayerController, WeaponSystem, EnemyFactory and EnemyAI, MaterialFactory (procedural textures), SoundSynth, HUDScene, and the SwiftUI shell. - The code is compiled later on the user's Mac, not here: check every initializer, argument label and optional, with no force-unwraps. Mouse capture, the feel of the controls, collisions and the frame rate cannot be tested here, so keep tuning values (speeds, gravity, sensitivity) together in one Config struct with a sensitivity slider in the pause menu. - In your reply, say in a few sentences what you built, what the lookups changed, and what you could not test (mouse capture, controls feel, physics tuning and frame rate).
Hollow Point is written as a full SceneKit and SpriteKit game, but none of it has been compiled or run. It has a title screen with a Start button, then an arena with a raised platform and ramp, pillars, crates and two side corridors, lit by emissive strips and a few point lights. You fight waves of runners, soldiers and brutes with a 12-round pistol. The player capsule, wall collisions, wave director, pickups, UserDefaults best wave, synthesized sound and the pause menu are all in. The pause menu has sensitivity and volume sliders. FPS is measured from real frame times (F toggles it), and the tuning values are all in `Config.swift`. **What the lookups changed:** I made three lookups: ray tests, mouse capture and SCNCamera. - **Vignette:** The SCNCamera page lists `vignettingIntensity` and `vignettingPower`, so I used those names instead of the ones I would have guessed. - **Ambient occlusion:** The page confirms the `screenSpaceAmbientOcclusion*` properties exist, so they are set. I did not add any check for whether a given system supports them. - **`zNear`/`zFar`:** They are `Double` on the camera page, so I used `Double` there. - **Ray tests:** The docs show `collisionBitMask` filtering by category. Shots only hit walls and enemies, and enemy line-of-sight and wall checks only see walls. - **Mouse look:** Capture warps the cursor to the window centre, calls `CGAssociateMouseAndMouseCursorPosition(0)` and hides the cursor. Look uses `deltaX` and `deltaY` from mouse-moved events, and Esc or losing focus releases the mouse. - **Not looked up:** I did not look up AVAudioEngine or GCController. The audio follows the standard player-node and PCM-buffer pattern from memory, and movement uses key events only. - **Left out:** I skipped motion blur to protect the frame rate. The prompt listed it as a camera option, not a requirement. **Not tested:** Mouse capture, how the controls feel, collision and physics tuning, enemy steering around obstacles, and the real frame rate on Apple silicon. The ambient occlusion and shadow settings are the first things to turn down if the frame rate is short of 60.
1) Add a highly-detailed green-accented particle accelerator cannon as the default weapon. the weapon should fire rapidly and should use beautiful effects for the design of the weapon and the projectiles / energy beam produced by the weapon. the weapon should fire glowing green/blue orbs that have a glowing halo / plasma visual effect 2) Also add a new enemy type - and build the enemy's body to be extremely detailed, multicolored and hyper realistic. 3) Add a minimap radar showing enemies around the player
I made all three changes, but I haven't compiled or played any of it, so I haven't seen how the cannon, the new enemy or the radar look. - **Plasma cannon:** It replaces the pistol as the default weapon and fires about 14 shots a second from a 40-round magazine (ammo pickups now give 60 rounds). - **Model:** The cannon is built from more than 60 parts: green-painted armor over gunmetal and titanium, glowing power cells, a glass chamber with a pulsing core, six glowing accelerator rings, spinning coil fins and a four-prong glowing muzzle. A gauge on the side shows the ammo left, or the reload progress. - **Shots:** Each shot launches a bright core with green and blue halos and a comet trail, plus a thin cyan beam. The orb ends in a green plasma burst with a flash. Damage is still instant on firing, so the orb is visual. - **Sound:** There is a new synthesized zap sound for each shot. - **New enemy, the Wraith:** It's a tall armored assassin built from roughly 120 shapes with eight materials, including violet and blue pearl plate, gold trim, gunmetal, dark fabric and cyan, magenta and orange glows. It has a spinning halo, a chest reactor, a backpack with thrusters and a forearm energy cannon. It shoots purple bolts and dashes sideways in short bursts. Wraiths first appear in wave 4 and drop pickups often. - **Radar:** A circular radar sits at the top right and rotates with where you look. It has a sweeping line and colored dots for each enemy type, and enemies beyond 40 m are clamped to the edge and dimmed. - **Soldier fix:** I also fixed the soldier's rifle arm, which was pointing the wrong way. I can't tell yet whether the cannon sits well in the view or whether the Wraith's dash feels fair. I also haven't checked the frame rate with the extra glow effects.
Add a second weapon, a charged railgun, on key 2 - make the new weapon look extremely beautiful, multi-colored, futuristic, and realistic. use tons of organic shapes and angles, different colors that contrast well add a new enemy type that appears a little bit in every wave - a small purple slug (the size of a cat) with legs and it scurries toward the player also, there was a "pistol" weapon before we replaced it with plasma cannon. bring back pistol weapon as 3rd weapon type, without removing any other weapon types.
I added the railgun on key 2, the slug enemy, and brought the pistol back as weapon 3, keeping the plasma cannon on key 1. None of it has been compiled or played yet. - **Charged railgun (key 2):** Hold fire to charge for about 0.9 s and release to shoot. A charge under 0.2 s fizzles without using ammo. More charge means more damage, and the shot pierces up to four enemies and is cut off by walls. It has a 5-round magazine. - **Look:** It's built from bezier-curved extruded body panels, a pearl fairing, a copper keel blade, rounded side panels, twin copper rails with a glowing channel, copper and magenta coils and crystal shards at the muzzle. It also has a violet battery capsule with a glowing core, a scope, a swept amber-tipped fin and a floating magnetic halo. - **Contrast and charge glow:** The palette contrasts navy, pearl white, copper, amber, magenta and cyan. The coils, channel and muzzle orb glow brighter as it charges. - **Beam:** The shot is a thick white, magenta and blue beam with expanding rings. It has new charge and shot sounds. - **Pistol (key 3):** It's the original instant-hit pistol, semi-auto, 12 rounds, 34 damage, with gold tracers and wall sparks. - **Weapon switching and ammo:** Each weapon has its own magazine and reserve. Ammo pickups top up all three, giving the railgun and pistol a smaller share. The HUD shows the current weapon's name, and the bar under the ammo count shows reload or charge progress. The title screen help text mentions 1/2/3. - **Purple slug:** It's cat-sized, with a glossy segmented purple body, glowing spots, eye stalks with amber pupils, little teeth and six legs that scurry in a tripod gait while the body squirms. It's fast and fragile and bites in melee. Each wave has at least one, up to six in later waves. It shows as a small purple dot on the radar. - **Soldier arm:** The soldier's rifle arm now points forward correctly. The Wraith was affected by this too. Not tested: how the railgun's curved panels sit and align, the beam and ring effects, the slug's leg animation and the weapon-switch timing. The curved panels are the part I'm least sure of, and I haven't checked the frame rate with these extra effects.

Compiled on this Mac. Saved to /Users/you/Downloads/silicondevkit.com/252227c9

Open appShow in Finder

Apps are ad-hoc signed, not notarized. If macOS blocks the first launch, use System Settings → Privacy & Security → Open Anyway.

Ask for changes…
Send
The SiliconDevKit desktop app chat for Space Horror FPS

What happened, step by step

  1. 0:00

    Prompt sent

    The prompt above, built on this Mac in source mode: the cloud writes the Swift code, the desktop app compiles it with the Mac’s own Xcode.

  2. 14:41

    First draft written

    About 15 minutes of work. The model wrote about 129,000 tokens of code and reasoning.

  3. ≈15:00

    One compile round, automatic

    The first compile failed on one expression that was too long for the Swift compiler to check. The desktop app sent the error back to the cloud by itself and it was shortened. This is not a chat message and nobody typed it.

  4. 40:41

    Follow-up 1: plasma cannon, enemy, radar

    Reply in 6:20 minutes, then compiled on the Mac again.

  5. 587:22

    Follow-up 2: railgun, slug enemy, pistol

    Reply in 1:28 minutes, then compiled on the Mac again.

What it cost

One initial prompt, two automatic compile fixes and your two follow-up prompts, plus one follow-up that was stopped early and run again, each one a separate run. Model: Claude Sonnet 5.5. Tokens are shown as (in / out). “In” counts everything the model read, including text it had already seen in the session at a reduced price.

Initial prompt(2.14M in / 129k out)234 credits
+Compile fix(494k in / 887 out)13 credits
+Follow-up 1: plasma cannon, enemy, radar(3.85M in / 54k out)156 credits
+Follow-up 2 (stopped early, run again)(1.51M in / 45k out)92 credits
+Follow-up 2: railgun, slug enemy, pistol(1.71M in / 10k out)152 credits
+Compile fix(590k in / 490 out)14 credits
=Total(10.29M in / 239k out)661 credits

Credits are what a build uses on your plan. This counts AI usage only: hosting and the Mac that compiled it are not included.

What went wrong, and what it shows

  • One expression broke the first build. The Swift compiler stopped on a single expression that was too complex to check. The automatic compile round fixed it without anyone typing a word.
  • The replies sounded unsure. They said the code had not been compiled or played, because the cloud step cannot run it. The desktop app compiles it right after, so the build instructions now tell it to say what changed and nothing else.
  • Big asks work as a list. The first follow-up asked for three things at once: a plasma cannon, a new enemy and a radar. It numbered them, and all three arrived in one reply. The second follow-up asked for a railgun and a slug enemy, and then for the pistol to come back as a third weapon without removing the others.
  • A stopped run costs credits. The second follow-up was stopped early and sent again. The stopped run is in the usage table, because it used the model before it was stopped.
Space Horror FPS icon

Play Space Horror FPS

Free download for Apple silicon Macs, macOS 13 or later.

Get the game

Make your own

Describe a game or an app, play it, then fix it by telling SiliconDevKit what you saw.

Build your own