# Project export: StoryLiving

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: TreeHacks 2024
- Tagline: Story-Living. Not Story-Telling. An Apple Vision Pro multiplayer app connecting seniors with their families through Spatial Memories.
- Devpost: https://devpost.com/software/storyliving
- GitHub: https://github.com/StevenLe2012/treehacks-2024
- Video: https://www.youtube.com/embed/jHisBQFxLAs?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 2 GitHub contributor(s) — Jiahui Chen (13 commits), Steven Le (4 commits)

## Devpost submission (written by the team)

### Inspiration

Social isolation among the elderly is a global problem. Around the world, 1 in 4 individuals above 60 experience social isolation. And 40% of Japan’s population aged above 60 experiences social isolation. The need for richer, more meaningful connections is critical. The inception of StoryLiving is deeply personal for all of us. After one of our team members lost their grandfather, they were struck by the realization of their missed connections and the stories left untold. We are all XR developers and enthusiasts, who have interned at several XR companies like Apple, Meta, Snapchat and others. Devices and apps with large, legible text, interactive screens, and voice commands are more accessible to older users. By using the most intuitive headset currently on the market, the Apple Vision Pro, our product enables a more social, narrative-driven way to relive memories that doesn’t require any tutorials. The advent of the Apple Vision Pro opened a doorway to an innovative solution—spatial memory. This technology allows users to not only reminisce about past stories but to truly relive and share those moments with loved ones in an immersive and social way. We set out to capitalize on this untapped vision.

### What it does

StoryLiving is an Apple Vision Pro app that transcends traditional storytelling by leveraging spatial video and photogrammetry to immerse users in 3D environments where memories were made. It enables grandparents to connect with their families in a shared virtual space, experiencing memories together as if they were physically present. Users can select and explore memories together using the Apple ecosystem’s SharePlay with FaceTime, breaking down the barriers of distance and time.

### How we built it

We built StoryLiving with the bleeding-edge Apple Vision Pro spatial computing device, focusing on user accessibility and intuitive design. Our development process involved designing an easy-to-navigate UI, ensuring that even users with no technical background could engage seamlessly. By incorporating spatial computing and photogrammetry, we crafted a platform where users can upload and navigate spatial memories, fostering a shared experience regardless of physical distance barriers.

### Challenges we ran into

One of the main challenges was designing an interface that was both powerful and accessible to an older, less tech-savvy demographic. Achieving a balance between technological sophistication and ease-of-use required extensive user testing and iteration. We talked to many mentors and elders that provided advice on building an accessible, innovative new technology. Innovating on the brand new Apple Vision Pro platform was an exciting challenge.

### Accomplishments we're proud of

We are particularly proud of creating a platform that genuinely bridges the technology gap for elderly populations, making cutting-edge AR/VR technology accessible and meaningful. We tackled leveraging a combination of AR and VR visualizations, spatial audio, eye interaction, social multiuser presence, and more. A unique technical aspect of using the Vision Pro to build our solution was incorporating depth-based 3D photos and videos to showcase spatial memories. Our user experience was designed to be easy-to-use without requiring a technical AR/VR background. It’s as simple as tapping a button and watching your family member’s spatial memories unfold in 3D. We were able to continually develop the idea and narrative, giving a compelling use case for elders in XR.

### What we learned

Throughout this project, we learned the importance of empathetic design in technology. Crafting experiences that cater to the elderly taught us to prioritize simplicity and accessibility. We had to make thoughtful design decisions for human-centric XR interfaces, and by asking the right people for help, we were able to approach the problem of how to introduce the older generation to spatial computing. We also explored the potential of AR/VR to solve real-world problems such as social isolation by creating shared experiences that are vivid and emotionally resonant.

### What's next

Looking forward, we aim to expand StoryLiving's capabilities to include other sensory experiences, such as haptic feedback, elevating the immersive interactions in the experience. We plan to explore partnerships and integrations that can bring StoryLiving to more users, focusing on making it a tool for social impact. We are excited to contribute to this revolution in accessibility for elders in XR and spatial technology. By continuously refining the technology and user experience, we envision StoryLiving as a leading solution in combating social isolation among the elderly, transforming storytelling into story-living.

## README (from the GitHub repository)

# StoryLiving - visionOS App (TreeHacks 2024)

Do you wish you could feel more connected to your loved ones? What if you could share and relive your memories with them? Now, with our app, you can view a spatial video or photo with your loved ones in the exact 3D environment in which the memory happened. **You aren't just story-telling. You are now story-living**.

- Devpost: https://devpost.com/software/storyliving
- YouTube: https://youtu.be/jHisBQFxLAs?si=hgV63IyufbpRisNO

[![StoryLiving](https://i.imgur.com/QhR6yUi.png)](https://youtu.be/jHisBQFxLAs?si=hgV63IyufbpRisNO)

### Team Contributions:
- [Steven Le](https://www.linkedin.com/in/stevenle1337/) (Stanford) - Project Manager
- [Jiahui Chen](https://www.linkedin.com/in/jchenstf/) (Stanford) - Frontend visionOS Dev
- [Rylan Pozniak](https://www.linkedin.com/in/rylandaniels/) (USC) - Backend visionOS Dev
- [Shawn Park](https://www.linkedin.com/in/shawn-park-5a4644221/) (CMU) - Video Editor + Narrative

## Inspiration
Social isolation among the elderly is a global problem. Around the world, 1 in 4 individuals above 60 experience social isolation. And 40% of Japan’s population aged above 60 experiences social isolation. The need for richer, more meaningful connections is critical.

The inception of StoryLiving is deeply personal for all of us. After one of our team members lost their grandfather, they were struck by the realization of their missed connections and the stories left untold.

We are all XR developers and enthusiasts, who have interned at several XR companies like Apple, Meta, Snapchat and others. Devices and apps with large, legible text, interactive screens, and voice commands are more accessible to older users. By using the most intuitive headset currently on the market, the Apple Vision Pro, our product enables a more social, narrative-driven way to relive memories that doesn’t require any tutorials.

The advent of the Apple Vision Pro opened a doorway to an innovative solution—spatial memory. This technology allows users to not only reminisce about past stories but to truly relive and share those moments with loved ones in an immersive and social way. We set out to capitalize on this untapped vision.

## What it does
StoryLiving is an application that transcends traditional storytelling by leveraging spatial video and photogrammetry to immerse users in 3D environments where memories were made. It enables grandparents to connect with their families in a shared virtual space, experiencing memories together as if they were physically present. Users can select and explore memories together using the Apple ecosystem’s SharePlay with FaceTime, breaking down the barriers of distance and time.

## How we built it
We built StoryLiving with the bleeding-edge Apple Vision Pro spatial computing device, focusing on user accessibility and intuitive design. Our development process involved designing an easy-to-navigate UI, ensuring that even users with no technical background could engage seamlessly. By incorporating spatial computing and photogrammetry, we crafted a platform where users can upload and navigate spatial memories, fostering a shared experience regardless of physical distance barriers.

## Challenges we ran into
One of the main challenges was designing an interface that was both powerful and accessible to an older, less tech-savvy demographic. Achieving a balance between technological sophistication and ease-of-use required extensive user testing and iteration. We talked to many mentors and elders that provided advice on building an accessible, innovative new technology. Innovating on the brand new Apple Vision Pro platform was an exciting challenge.

## Accomplishments that we're proud of
We are particularly proud of creating a platform that genuinely bridges the technology gap for elderly populations, making cutting-edge AR/VR technology accessible and meaningful. We tackled leveraging a combination of AR and VR visualizations, spatial audio, eye interaction, social multiuser presence, and more. A unique technical aspect of using the Vision Pro to build our solution was incorporating depth-based 3D photos and videos to showcase spatial memories. 

Our user experience was designed to be easy-to-use without requiring a technical AR/VR background. It’s as simple as tapping a button and watching your family member’s spatial memories unfold in 3D. We were able to continually develop the idea and narrative, giving a compelling use case for elders in XR. 

## What we learned
Throughout this project, we learned the importance of empathetic design in technology. Crafting experiences that cater to the elderly taught us to prioritize simplicity and accessibility. We had to make thoughtful design decisions for human-centric XR interfaces, and by asking the right people for help, we were able to approach the problem of how to introduce the older generation to spatial computing. We also explored the potential of AR/VR to solve real-world problems such as social isolation by creating shared experiences that are vivid and emotionally resonant.

## What's next for StoryLiving
Looking forward, we aim to expand StoryLiving's capabilities to include other sensory experiences, such as haptic feedback, elevating the immersive interactions in the experience. We plan to explore partnerships and integrations that can bring StoryLiving to more users, focusing on making it a tool for social impact. We are excited to contribute to this revolution in accessibility for elders in XR and spatial technology. By continuously refining the technology and user experience, we envision StoryLiving as a leading solution in combating social isolation among the elderly, transforming storytelling into story-<em>living</em>.


## Detected evidence (automated analysis)

Indexed codebase: 12 recognized source files, 21 KB.
- Swift (language) — detected in the code

## Codebase structure (from repository index)

### Files (40 of 40)

```
.gitignore
Packages/RealityKitContent/Package.realitycomposerpro/ProjectData/main.json
Packages/RealityKitContent/Package.realitycomposerpro/WorkspaceData/SceneMetadataList.json
Packages/RealityKitContent/Package.realitycomposerpro/WorkspaceData/Settings.rcprojectdata
Packages/RealityKitContent/Package.swift
Packages/RealityKitContent/README.md
Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.rkassets/Classroom.usdz
Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.rkassets/Immersive.usda
Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.rkassets/Materials/GridMaterial.usda
Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.rkassets/Scene.usda
Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.swift
README.md
TreeHacks2024.xcodeproj/project.pbxproj
TreeHacks2024.xcodeproj/project.xcworkspace/contents.xcworkspacedata
TreeHacks2024.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
TreeHacks2024/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Content.imageset/Contents.json
TreeHacks2024/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Contents.json
TreeHacks2024/Assets.xcassets/AppIcon.solidimagestack/Contents.json
TreeHacks2024/Assets.xcassets/AppIcon.solidimagestack/Front.solidimagestacklayer/Content.imageset/Contents.json
TreeHacks2024/Assets.xcassets/AppIcon.solidimagestack/Front.solidimagestacklayer/Contents.json
TreeHacks2024/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Content.imageset/Contents.json
TreeHacks2024/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Contents.json
TreeHacks2024/Assets.xcassets/Apple.imageset/Contents.json
TreeHacks2024/Assets.xcassets/Apple.imageset/IMG_0144.HEIC
TreeHacks2024/Assets.xcassets/Contents.json
TreeHacks2024/Assets.xcassets/Hiking.imageset/Contents.json
TreeHacks2024/Assets.xcassets/Paris.imageset/Contents.json
TreeHacks2024/Assets.xcassets/Paris.imageset/Paris.heic
TreeHacks2024/Assets.xcassets/Tibet.imageset/Contents.json
TreeHacks2024/Assets.xcassets/Tibet.imageset/Tibet.heic
TreeHacks2024/ContentView.swift
TreeHacks2024/ImmersiveView.swift
TreeHacks2024/Info.plist
TreeHacks2024/Preview Content/Preview Assets.xcassets/Contents.json
TreeHacks2024/RealityViews/Classroom.swift
TreeHacks2024/RealityViews/SceneScan.swift
TreeHacks2024/TreeHacks2024App.swift
TreeHacks2024/Views/VideoViewController.swift
TreeHacks2024/Windows/PhotoCarouselView.swift
TreeHacks2024/Windows/SceneSelectionCarousel.swift
```

### Dependencies

No dependency index available.

### Recent commits (newest first)

- Update README.md
- Merge pull request #6 from StevenLe2012/jiahui/integrate-3D-scan
- tried to fix window not dimissing bug, but haven't fixed it
- Create README.md
- Merge pull request #5 from StevenLe2012/jiahui/integrate-3D-scan
- final version
- placed 3D scan in correct directory
- debugging why can't see app
- Merge pull request #4 from StevenLe2012/jiahui/isolate-data-schema
- isolated the schema
- Merge pull request #3 from StevenLe2012/jiahui/implement-carousel-view-for-photo-selection
- created photo carousel view, leaving for Ryan to finish
- Merge pull request #2 from StevenLe2012/jiahui/implement-carousel-view-for-photo-selection
- improved immersion
- immersion working
- Merge pull request #1 from StevenLe2012/jiahui/player-around-with-placing-multiple-windows
- understood how to spwan a new window
- Update .gitignore
- Initial Project
- Initial commit

## Key source files (fetched from GitHub, selected and truncated for size)

### TreeHacks2024/ImmersiveView.swift

```swift
//
//  ImmersiveView.swift
//  TreeHacks2024
//
//  Created by Stanford User on 2/16/24.
//

import SwiftUI
import RealityKit
import RealityKitContent

struct ImmersiveView: View {
    var body: some View {
        RealityView { content in
            // Add the initial RealityKit content
            if let scene = try? await Entity(named: "Immersive", in: realityKitContentBundle) {
                content.add(scene)
            }
        }
    }
}

#Preview {
    ImmersiveView()
        .previewLayout(.sizeThatFits)
}

```

### TreeHacks2024/ContentView.swift

```swift
//
//  ContentView.swift
//  TreeHacks2024
//
//  Created by Stanford User on 2/16/24.
//

import SwiftUI
import RealityKit
import RealityKitContent

struct ContentView: View {

    @State private var showImmersiveSpace = false
    @State private var immersiveSpaceIsShown = false

    @Environment(\.openImmersiveSpace) var openImmersiveSpace
    @Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace

    var body: some View {
        VStack {
            Model3D(named: "Scene", bundle: realityKitContentBundle)
                .padding(.bottom, 50)

            Text("Hello, world!")

            Toggle("Show Immersive Space", isOn: $showImmersiveSpace)
                .toggleStyle(.button)
                .padding(.top, 50)
        }
        .padding()
        .onChange(of: showImmersiveSpace) { _, newValue in
            Task {
                if newValue {
                    switch await openImmersiveSpace(id: "ImmersiveSpace") {
                    case .opened:
                        immersiveSpaceIsShown = true
                    case .error, .userCancelled:
                        fallthrough
                    @unknown default:
                        immersiveSpaceIsShown = false
                        showImmersiveSpace = false
                    }
                } else if immersiveSpaceIsShown {
                    await dismissImmersiveSpace()
                    immersiveSpaceIsShown = false
                }
            }
        }
    }
}

#Preview(windowStyle: .automatic) {
    ContentView()
}

```

### TreeHacks2024/TreeHacks2024App.swift

```swift
//
//  TreeHacks2024App.swift
//  TreeHacks2024
//
//  Created by Stanford User on 2/16/24.
//

import SwiftUI

@main
struct ARMemoryPalace: App {
    @State private var scan4ImmersionStyle: ImmersionStyle = .full
    var body: some Scene {
        WindowGroup(id: "Carousel") {
            SceneSelectionCarousel()
        }
        .windowStyle(.plain)

        WindowGroup(id: "TibetWindow") {
            VideoViewController(videoURL: Bundle.main.url(forResource: "Tibet", withExtension: "mov"))
        }

        WindowGroup(id: "ParisWindow") {
            VideoViewController(videoURL: Bundle.main.url(forResource: "Paris", withExtension: "mov"))
        }

        WindowGroup(id: "AppleParkWindow") {
            VideoViewController(videoURL: Bundle.main.url(forResource: "Summer23", withExtension: "mov"))
        }

        WindowGroup(id: "YosemiteWindow") {
            VideoViewController(videoURL: Bundle.main.url(forResource: "Yosemite", withExtension: "mov"))
        }

        ImmersiveSpace(id: "TibetSpace") {
            Immersive(entity: "Temple")
        }
        .immersionStyle(selection: $scan4ImmersionStyle, in: .full)

        ImmersiveSpace(id: "ParisSpace") {
            Immersive(entity: "Paris")
        }
        .immersionStyle(selection: $scan4ImmersionStyle, in: .full)

        ImmersiveSpace(id: "AppleParkSpace") {
            Immersive(entity: "ApplePark")
        }
        .immersionStyle(selection: $scan4ImmersionStyle, in: .full)

        ImmersiveSpace(id: "ElCapitanSpace") {
            Immersive(entity: "El Capitan")
        }
        .immersionStyle(selection: $scan4ImmersionStyle, in: .full)
    }
}

```

### TreeHacks2024/Views/VideoViewController.swift

```swift
//
//  VideoViewController.swift
//  TreeHacks2024
//
//  Created by Jiahui Chen  on 2/18/24.
//

import AVKit
import SwiftUI

struct VideoViewController: UIViewControllerRepresentable {
    var videoURL: URL?

    private var player: AVPlayer {
        return AVPlayer(url: videoURL!)
    }

    func makeUIViewController(context: Context) -> AVPlayerViewController {
        let controller = AVPlayerViewController()
        controller.modalPresentationStyle = .fullScreen
        controller.player = player
        controller.player?.play()
        return controller
    }

    func updateUIViewController(_ playerController: AVPlayerViewController, context: Context) {}
}

```

### TreeHacks2024/RealityViews/Classroom.swift

```swift
//
//  Classroom.swift
//  TreeHacks2024
//
//  Created by Jiahui Chen  on 2/17/24.
//

import RealityKit
import RealityKitContent
import SwiftUI

/// A model of the sun.
struct Classroom: View {
    var scale: Float = 0.5
    var position: SIMD3<Float> = .zero

    /// The sun entity that the view creates and stores for later updates.
    @State private var classroom: Entity?

    var body: some View {
        RealityView { content in
            // Load your 3D model and add it to the scene
            if let local = try? await Entity(named: "Classroom", in: realityKitContentBundle) {
                content.add(local)
            }
        }
    }

    /// Configures the model based on the current set of inputs.
    private func configure() {
        classroom?.scale = SIMD3(repeating: scale)
        classroom?.position = position
    }
}

#Preview {
    Classroom(scale: 0.1)
}

```

### TreeHacks2024/RealityViews/SceneScan.swift

```swift
//
//  Test4BostonDynamics.swift
//  TreeHacks2024
//
//  Created by Jiahui Chen  on 2/17/24.
//


import RealityKit
import RealityKitContent
import SwiftUI

/// A model of the sun.
struct Immersive: View {
    var entity: String
    var scale: Float = 0.5
    var position: SIMD3<Float> = .zero

    /// The sun entity that the view creates and stores for later updates.
    @State private var scan4: Entity?

    var body: some View {
        RealityView { content in
            // Load your 3D model and add it to the scene
            if let local = try? await Entity(named: entity, in: realityKitContentBundle) {
                content.add(local)
            }
        }
    }

    /// Configures the model based on the current set of inputs.
    private func configure() {
        scan4?.scale = SIMD3(repeating: scale)
        scan4?.position = position
    }
}

#Preview {
    Immersive(entity: "Temple", scale: 0.1)
}

```

### Packages/RealityKitContent/Package.swift

```swift
// swift-tools-version:5.9
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "RealityKitContent",
    products: [
        // Products define the executables and libraries a package produces, and make them visible to other packages.
        .library(
            name: "RealityKitContent",
            targets: ["RealityKitContent"]),
    ],
    dependencies: [
        // Dependencies declare other packages that this package depends on.
        // .package(url: /* package url */, from: "1.0.0"),
    ],
    targets: [
        // Targets are the basic building blocks of a package. A target can define a module or a test suite.
        // Targets can depend on other targets in this package, and on products in packages this package depends on.
        .target(
            name: "RealityKitContent",
            dependencies: []),
    ]
)
```

### TreeHacks2024/Windows/PhotoCarouselView.swift

```swift
//
//  CarouselView.swift
//  TreeHacks2024
//
//  Created by Jiahui Chen  on 2/17/24.
//

import Combine
import Foundation
import RealityKit
import RealityKitContent
import SwiftUI

struct PhotoItem: Identifiable {
    var id: Int
    var title: String
    var color: Color
}

class PhotoStore: ObservableObject {
    @Published var items: [PhotoItem]
    
    let colors: [Color] = [.red, .orange, .blue, .teal, .mint, .green, .gray, .indigo, .black]

    // dummy data
    init() {
        items = []
        for i in 0...7 {
            let new = PhotoItem(id: i, title: "Item \(i)", color: colors[i])
            items.append(new)
        }
    }
}

struct PhotoCarouselView: View {
    @StateObject var store = PhotoStore()
    @State private var rotationAngle: Double = 0

    // Parameters for the circular layout
    let circleRadius: CGFloat = 300 // Radius of the circle on which photos will move
    let animationDuration: Double = 0.02 // Speed of rotation

    var body: some View {
        ZStack {
            ForEach(store.items.indices, id: \.self) { index in
                let item = store.items[index]
                ZStack {
                    RoundedRectangle(cornerRadius: 18)
                        .fill(item.color)
                    Text(item.title)
                        .padding()
                }
                .frame(width: 200, height: 200)
                .opacity(opacityEffect(index: index))
                .offset(x: xOffset(index: index))
                .offset(z: xOffset(index: index))
                .animation(Animation.linear(duration: animationDuration), value: rotationAngle)
            }
        }
        .onAppear {
            // Timer to update rotationAngle and cause the rotation effect
            Timer.scheduledTimer(withTimeInterval: animationDuration, repeats: true) { _ in
                self.rotationAngle += 1
                if self.rotationAngle >= 360 {
                    self.rotationAngle = 0
                }
            }
        }
    }
    
    func xOffset(index: Int) -> CGFloat {
        let angle = (Double.pi * 2 / Double(store.items.count)) * Double(index) + degreesToRadians(degrees: rotationAngle)
        return cos(angle) * circleRadius
    }
    
    func zOffset(index: Int) -> CGFloat {
        let angle = (Double.pi * 2 / Double(store.items.count)) * Double(index) + degreesToRadians(degrees: rotationAngle)
        return sin(angle) * circleRadius
    }
    
    func scaleEffect(index: Int) -> CGFloat {
        let angle = (Double.pi * 2 / Double(store.items.count)) * Double(index) + degreesToRadians(degrees: rotationAngle)
        // Simulate depth by scaling based on the cosine of the angle
        let scale = 0.6 + 0.4 * cos(angle) // Adjust scale factor as needed
        return scale
    }
    
    func opacityEffect(index: Int) -> Double {
        let angle = (Double.pi * 2 / Double(store.items.count)) * Double(index) + degreesToRadians(degrees: rotationAngle)
        // Simulate depth by adjusting opacity based on the cosine of the angle
        let opacity = 0.5 + 0.5 * cos(angle) // Adjust opacity factor as needed
        return opacity
    }
    
    func degreesToRadians(degrees: Double) -> Double {
        return degrees * Double.pi / 180
    }
}


#Preview {
    PhotoCarouselView()
}

```

### TreeHacks2024/Windows/SceneSelectionCarousel.swift

```swift
//
//  CarouselView.swift
//  TreeHacks2024
//
//  Created by Jiahui Chen  on 2/17/24.
//

import Foundation
import RealityKit
import RealityKitContent
import SwiftUI

// Define the structure of each carousel item
struct Item: Identifiable {
    var id: Int
    var title: String
    var subtitle: String
    var imageName: String
    var videoName: String
    var entityName: String
}

// Observable object to hold and manage the items
class Store: ObservableObject {
    @Published var items: [Item]

    init() {
        items = []
        let imageNames = ["Tibet", "Apple", "Hiking", "Paris"] // Placeholder image names
        let titles = ["Tibet Backpacking", "Summer Memories", "Yosemite", "Paris"]
        let subtitles = ["Feb 2024", "July 2023", "June 2021", "Aug 2023"] // Placeholder subtitles
        let videoNames = ["TibetWindow", "AppleParkWindow", "YosemiteWindow", "ParisWindow"]
        let entityIds = ["TibetSpace", "AppleParkSpace", "ElCapitanSpace", "ParisSpace"]
        for i in 0 ..< imageNames.count {
            let new = Item(id: i, title: "\(titles[i])", subtitle: "\(subtitles[i])", imageName: imageNames[i], videoName: videoNames[i], entityName: entityIds[i])
            items.append(new)
        }
    }
}

// The main view for the carousel
struct SceneSelectionCarousel: View {
    @Environment(\.openImmersiveSpace) private var openImmersiveSpace
    @Environment(\.dismissImmersiveSpace) private var dismissImmersiveSpace
    @Environment(\.openWindow) private var openWindow
    @Environment(\.dismissWindow) private var dismissWindow
    @Environment(\.dismiss) private var dismiss

    @StateObject var store = Store()
    @State private var snappedItem = 0.0
    @State private var draggingItem = 0.0

    @State var currentWindow: String = ""
    @State var currentSpace: String = ""

    var body: some View {
        ZStack {
            ForEach(store.items) { item in
                VStack {
                    Image(item.imageName)
                        .resizable()
                        .aspectRatio(contentMode: .fill)
                        .clipped()
                        .frame(width: 200, height: 200)
                        .cornerRadius(20)
                    VStack {
                        Text(item.title)
                            .font(.headline)
                            .foregroundColor(.white)
                        Text(item.subtitle)
                            .font(.subheadline)
                            .foregroundColor(.white)
                    }
                }
                .onTapGesture {
                    // Open new window
                    openWindow(id: item.videoName)
                    currentWindow = item.videoName
                    Task {
                        // Dismiss the current space if present
                        if currentSpace != "" {
                            await dismissImmersiveSpace()
                        }
                        // Open new immersive space
                        await openImmersiveSpace(id: item.entityName)
                        currentSpace = item.entityName
                    }
                }
                .frame(width: 200, height: 200)
                .scaleEffect(1.0 - abs(distance(item.id)) * 0.2)
                .opacity(1.0 - abs(distance(item.id)) * 0.5)
                .offset(x: myXOffset(item.id), y: 0)
                .zIndex(1.0 - abs(distance(item.id)) * 0.1)
            }
        }
        .gesture(
            DragGesture()
                .onChanged { value in
                    draggingItem = snappedItem + value.translation.width / 100
                }
                .onEnded { value in
                    withAnimation {
                        draggingItem = snappedItem + value.predictedEndTranslation.width / 100
                        draggingItem = round(draggingItem).remainder(dividingBy: Double(store.items.count))
                        snappedItem = draggingItem
                    }
                }
        )
    }

    func distance(_ item: Int) -> Double {
        return (draggingItem - Double(item)).remainder(dividingBy: Double(store.items.count))
    }

    func myXOffset(_ item: Int) -> CGFloat {
        let angle = Double.pi * 2 / Double(store.items.count) * distance(item)
        return CGFloat(sin(angle) * 200)
    }
}

// Preview provider to visualize the carousel in Xcode's canvas
struct SceneSelectionCarousel_Previews: PreviewProvider {
    static var previews: some View {
        SceneSelectionCarousel()
    }
}

```

### Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.swift

```swift
import Foundation

/// Bundle for the RealityKitContent project
public let realityKitContentBundle = Bundle.module

```