Repository navigation
paramountKit 4.0.33.325
paramountKit
Kotlin Multiplatform framework for the Maestro Paramount SDK — exposes Stats (live MMA/UFC data), Key Plays (Key Moments), and animated Overlays to tvOS and iOS apps via Swift Package Manager.
Installation
Add the distribution repo as a package and link the paramountKit product. Track main — each
publish updates the manifest there to the newest build:
dependencies: [
.package(url: "https://github.com/lessthan3/MaestroKit.android", branch: "main")
]In Xcode: File → Add Package Dependencies → paste that url → Dependency Rule "Branch: main" → add
paramountKit to your target. The repo has no semver tags, so a from: / version rule resolves
nothing.
To pin one build instead, point a binaryTarget at that release's asset — its url and checksum are
in the release notes:
.binaryTarget(
name: "paramountKit",
url: "https://github.com/lessthan3/MaestroKit.android/releases/download/paramountKit-<version>/paramountKit-<version>.zip",
checksum: "<checksum from the release notes>"
)Releases: https://github.com/lessthan3/MaestroKit.android/releases?q=paramountKit
Use one or the other. Two packages declaring the same paramountKit product makes SwiftPM drop one
of them from the graph, which Xcode reports as "unexpectedly did not find the new dependency in the
package graph".
Platforms
- tvOS 16+
- iOS 16+
Quick Start
import paramountKit
// 1. Configure the SDK once per session.
let instance = ParamountMaestroSDK.shared.configure(
context: PlatformContext(),
delegate: MyParamountDelegate(),
params: ParamountSDKParameters(
siteId: "your-site-id",
pageId: nil,
metadataValue: "event-metadata-value",
appPackageVersion: "1.0.0",
isProduction: true,
userAgent: "ATV"
),
buildConfigInfo: ParamountBuildConfigInfo(
versionName: "1.0.0",
isDebug: false
)
)
// 2. Observe available panels (Stats, Key Plays, Builder) from the config.
Task {
for await panels in instance.repo.enabledPanels {
print("Panels: \((panels as? [SharedPanelData])?.map { $0.name } ?? [])")
}
}
// 3. Tell the SDK which panel is currently shown (for analytics + gating).
instance.didShowPanel(panelTypeId: ParamountPanelTypes.shared.STATS)
// 4. Detach when done.
instance.detach()Delegate
ParamountEventDelegate is how the SDK talks back to the host app:
class MyParamountDelegate: ParamountEventDelegate {
func shouldShowPanel() { /* host should surface the panel UI */ }
func shouldHidePanel() { /* host should hide it */ }
func trackAction(analytics: [String: String]) { /* forward to your analytics */ }
func trackImpression(analytics: [String: String]) { /* forward to your analytics */ }
func onKeyMomentSelected(contentId: String) { /* play the clip */ }
}Features
Stats panel (MMA/UFC)
Fetches live fight data from the Helios supergraph, polls every 10s, retries with backoff.
let stats = instance.createStatsPresenter()
stats.start()
Task {
for await state in stats.state {
switch onEnum(of: state) {
case .loading:
print("Loading fights…")
case .error(let e):
print("Error: \(e.message)")
case .success(let s):
let event = s.event
print("\(event.name) at \(event.venue)")
for fight in event.fights {
print(" \(fight.redFighter.lastName) vs \(fight.blueFighter.lastName)")
}
}
}
}
stats.destroy()Key Plays panel (Key Moments)
Host app pushes key-moment data into the SDK; the presenter handles sort order + playback progress.
let keyPlays = instance.createKeyPlaysPresenter()
keyPlays.start()
// Push moments from your backend.
instance.updateKeyMomentsData(data: [
ParamountKeyMoment(contentId: "clip-1", title: "Round 1 KO", ...)
])
// Update playback progress as the user watches.
instance.updateKeyMomentsProgress(contentId: "clip-1", progress: 0.42)
// Change sort order.
instance.setKeyMomentsSortOrder(sortOrder: KeyMomentsSortOrder.newestFirst)
Task {
for await state in keyPlays.state {
print("\(state.moments.count) moments, active=\(state.activeContentId ?? "none")")
}
}
keyPlays.destroy()Animated Overlays
Rive-based broadcast overlays driven by the SDK's overlay queue.
let overlays = instance.createOverlayPresenter()
overlays.start()
Task {
for await event in overlays.events {
// event carries the Rive file URL + duration.
}
}
overlays.destroy()Type mapping
| Kotlin | Swift |
|---|---|
StateFlow<T> |
AsyncSequence — consume with for await |
sealed interface / sealed class |
Use switch onEnum(of:) for exhaustive matching |
data object Foo |
FooType.shared singleton |
List<T> |
Array<T> |
Long |
Int64 |
Sealed state pattern
switch onEnum(of: state) {
case .loading:
ProgressView()
case .error(let e):
Text(e.message)
case .success(let s):
ContentView(event: s.event)
}Working example
A complete SwiftUI demo lives in demos/demo-tvos-paramount/ in this repo. It wires up Stats, Key Plays, Overlays, and the panel-visibility bridge.
License
Copyright (c) LessThan3
Installation
.binaryTarget(
name: "paramountKit",
url: "https://github.com/lessthan3/MaestroKit.android/releases/download/paramountKit-4.0.33.325/paramountKit-4.0.33.325.zip",
checksum: "4ef9a590f7c5b7bae9b9c8df279018030d0af8bee1031b172af4f7ead3776471"
)