A SwiftUI package that embeds KinesteX’s AI-powered camera workout experience as a WebView.
Easily switch between multiple exercises at runtime, track loading state, and respond to messages from the JS layer.
Use Swift Package Manager:
- In Xcode, go to File → Add Packages...
- Enter your repo URL, e.g.
https://github.com/KinesteX/KinesteX-AI-Kit.git - Select the version you want (e.g. from 1.0.0).
-
Import the package
import KinesteXAIKit import SwiftUI
-
Initialize your kit (usually in your
Appor parent view):let kit = KinesteXAIKit( apiKey: "YOUR_API_KEY", companyName: "MyCompany", userId: "user-123" )
-
Create a view that drives the camera workout:
struct WorkoutView: View { // 1) The list of exercises let exercises = ["squat", "pushup", "plank"] // 2) Bindings required by the kit @State private var currentExercise = "squat" @State private var currentRestSpeech: String? = nil @State private var isLoading = false // 3) Your kit instance let kit = KinesteXAIKit( apiKey: "YOUR_API_KEY", companyName: "MyCompany", userId: "user-123" ) var body: some View { VStack(spacing: 16) { // Embed the camera view kit.createCameraView( exercises: exercises, currentExercise: $currentExercise, currentRestSpeech: $currentRestSpeech, user: nil, // or your UserDetails isLoading: $isLoading ) { message in // Handle messages from the WebView print("JS Message:", message) } .frame(height: 400) // Display or change the current exercise Text("Now: \(currentExercise)") .font(.headline) Button("Next Exercise") { guard let idx = exercises.firstIndex(of: currentExercise) else { return } currentExercise = exercises[(idx + 1) % exercises.count] } } .padding() } }
-
Bindings
currentExercise: Binding<String>: Changing this state will update the current exercise being tracked and will provide necessary feedbackcurrentRestSpeech: Binding<String?>: Optional state to control audio during rest being playedisLoading: Binding<Bool>: Tracks the WebView’s loading state (black screen in the beginning).
-
Dynamic Updates
Just mutate your@State currentExerciseand the JS side will switch drills in real time. -
Cleanup
When the SwiftUI view unmounts or yourKinesteXAIKitdeinitializes you’ll see in the console:🗑️ KinesteX: cleaning up... 🗑️ KinesteX: Coordinator deinitialized ✅ KinesteX: cleaned up and set webView to nil 🗑️ KinesteX: WebViewState deinitialized 🗑️ KinesteX: WebView deinitialized
// Camera-based workout
func createCameraView(
exercises: [String],
currentExercise: Binding<String>,
currentRestSpeech: Binding<String?>? = nil,
user: UserDetails?,
isLoading: Binding<Bool>,
customParams: [String:Any] = [:],
onMessageReceived: @escaping (WebViewMessage) -> Void
) -> AnyView
// Preconfigured plan, workout, challenge, experience, leaderboard views:
// createPlanView(plan:), createWorkoutView(workout:), createChallengeView(...), etc.Each create…View under the hood:
- Merges your
defaultData+userprofile +customParams - Validates inputs
- Instantiates a
KinestexViewwrapping aWKWebView
Enjoy seamless, AI-driven workout guidance in SwiftUI!
Feel free to open issues or PRs on GitHub.