cascade

Swift Student Challenge '26 winner

Categories iPadOS
Stack SwiftUI, RealityKit, Accelerate, Swift Charts

overview

Every year Apple hosts the Swift Student Challenge, inviting students to build creative apps using the latest Apple technologies. When submissions for the 2026 edition opened, I knew I wanted to make something about space. I grew up on Jules Verne, H.G. Wells, and Kubrick's 2001, and I still spend the occasional evening lost on Wikipedia reading about new planets and missions. One of those deep dives, around 2024, introduced me to Kessler Syndrome, first proposed by Donald Kessler and Burton G. Cour-Palais in the late 1970s: as we keep launching objects into space, the density in certain orbital regions climbs to a point where collisions become exponentially more likely. Each collision then produces shrapnel, which raises the density further, which raises the collision rate further: a chain reaction unfolding over years and decades. Left unchecked, it can render entire orbital ranges unusable, taking GPS, weather tracking, and satellite internet down with them. Visualizing that felt like an idea worth building, and a surprisingly untouched one.

Cascade is the result: an educational simulator that pairs arcade-style controls with realistic gravity simulation. I built the 3D environment in RealityKit and exposed as much of the simulation as I could, including the number of satellites and variation in initial orbit altitudes. What I love most in simulators is being able to mess with them, and beyond being satisfying to tweak, that openness produces some genuinely striking ways to watch a chain collision unfold.

Since the goal is education, the interface had to stay intuitive. I went with a native TabView to separate the simulation from the reading materials. I added a Learn More tab for the science and a Swift Charts timeline to show debris accumulation since the 1960s. To reach as many users as possible, I leaned hard on customization and accessibility: rotating the camera around Earth, zooming, omni lighting, recoloring satellites, debris and the background to improve contrast, resizing or hiding objects, even hiding Earth itself (which, honestly, makes the prettiest visualization). VoiceOver got its own pass, with descriptive labels added throughout.

Cascade was also a serious learning project. I'm not a physicist, so I leaned on AI tools to study and implement the math behind orbital gravity, and getting an iPad to render thousands of colliding objects smoothly took a significant amount of optimization. Through guided learning, I picked up the Accelerate framework for parallel math, built an actor-isolated physics engine to keep the interface responsive, and batched the debris into a single dynamic RealityKit mesh. Together, those changes turned a rough draft into something that runs comfortably on-device without thermals taking over.

Cascade was selected as a SSC2026 winner. Building an app is hard, especially when the topic requires deep research into optimization and architecture, so I was overjoyed to win. There's a demo video below; the project is also available on GitHub.

0:00 / 0:00

tech stack

SwiftUI
interface & navigation
RealityKit
3D rendering engine
Accelerate
SIMD parallel math
Swift Charts
data visualization

code snippets

I used the Accelerate framework for vectorized math to keep the frame rate high. Switching to a Structure of Arrays (SoA) layout keeps memory access contiguous, making gravitational calculations much more efficient.

func updatePhysics(dt: Float, earthMass: Float, killRadiusSq: Float, maxRadiusSq: Float) {
    guard activeCount > 0 else { return }
    let count = activeCount
    let n = vDSP_Length(count)

    withSixBuffers(&posX, &posY, &posZ, &velX, &velY, &velZ) { pX, pY, pZ, vX, vY, vZ in
        let xBase = pX.baseAddress!
        let yBase = pY.baseAddress!
        let zBase = pZ.baseAddress!
        let vxBase = vX.baseAddress!
        let vyBase = vY.baseAddress!
        let vzBase = vZ.baseAddress!

        // distSq = posX² + posY² + posZ²
        vDSP_vsq(xBase, 1, scratchA, 1, n)
        vDSP_vsq(yBase, 1, scratchC, 1, n)
        vDSP_vadd(scratchA, 1, scratchC, 1, scratchA, 1, n)
        vDSP_vsq(zBase, 1, scratchC, 1, n)
        vDSP_vadd(scratchA, 1, scratchC, 1, scratchA, 1, n)

        // invDist = rsqrt(distSq)
        var n32 = Int32(count)
        vvrsqrtf(scratchB, scratchA, &n32)

        // factor = -earthMass * dt * invDist³
        vDSP_vmul(scratchB, 1, scratchB, 1, scratchC, 1, n)
        vDSP_vmul(scratchC, 1, scratchB, 1, scratchC, 1, n)
        var coeff = -earthMass * dt
        vDSP_vsmul(scratchC, 1, &coeff, scratchC, 1, n)

        // Mask out-of-range particles
        for i in 0..<count {
            if scratchA[i] < killRadiusSq || scratchA[i] > maxRadiusSq {
                scratchC[i] = 0
            }
        }

        // vel += pos * factor
        vDSP_vma(xBase, 1, scratchC, 1, vxBase, 1, vxBase, 1, n)
        vDSP_vma(yBase, 1, scratchC, 1, vyBase, 1, vyBase, 1, n)
        vDSP_vma(zBase, 1, scratchC, 1, vzBase, 1, vzBase, 1, n)

        // pos += vel * dt
        var dt_val = dt
        vDSP_vsma(vxBase, 1, &dt_val, xBase, 1, xBase, 1, n)
        vDSP_vsma(vyBase, 1, &dt_val, yBase, 1, yBase, 1, n)
        vDSP_vsma(vzBase, 1, &dt_val, zBase, 1, zBase, 1, n)
    }
}

design choices

palette

space black #000000
starlight #FFFFFF
satellite green #1BB83A
debris red #FF3B30

typography

SF Pro Display / headings and primary text
The quick fox jumps over the lazy dog
SF Mono / monospaced data and statistics
The quick fox jumps over the lazy dog

some fonts used in this project are proprietary and may not display correctly if they are not installed on your system.

rationale

The Universe is mostly pitch black. This means that not only is the predominant color in Cascade an absence of color (to some extent), but also that I had an opportunity to explore the meaningful use of colors for the interface and the simulation's mechanics. In line with my desire to allow customization and fine-tuning of the experience, Cascade allows the user to tweak the colors of satellites, debris and the background, but I settled on green for the satellites and red, which indicates danger, for the debris.

I also decided to take advantage of the new Liquid Glass design language. It allowed the UI to gain depth and dimension while remaining simple and effective. In particular, it's pretty nice watching the debris flowing behind the buttons and other UI elements, being refracted by the glass. One of the biggest advantages of Liquid Glass, in my opinion, is how it allows the app to breathe while keeping the content in focus. It feels clean, squeaky clean, but not sterile.

I decided to go with "assets" made in code with native RealityKit APIs. The only external assets used are specular and texture maps for Earth, superimposed on a RealityKit sphere. For example, debris is represented by simple tetrahedrons, which are the simplest 3D shapes that can be rendered. This was a choice made mostly for performance reasons, but I think it ended up giving the app a unique visual identity since it kind of gives off a radar vibe. The satellites being green cubes also help with this. The simple shapes combined with the colors and the lighting create a very distinct look that helps focusing on the event of Kessler Syndrome itself rather than wasting compute and render on overly complicated graphics.

credits

people

design · development
pedro wiezel

assets

textures
NASA/NOAA, Solar System Scope, Tom Patterson