https://github.com/thatfactory/progressionkit
A reusable progression engine that turns player performance into configurable XP, levels, and unlocks across games and apps. 📈
https://github.com/thatfactory/progressionkit
domain-logic game-development gamification level leveling package progression swift swiftpm ui-agnostic unlocks xp
Last synced: 7 days ago
JSON representation
A reusable progression engine that turns player performance into configurable XP, levels, and unlocks across games and apps. 📈
- Host: GitHub
- URL: https://github.com/thatfactory/progressionkit
- Owner: thatfactory
- License: mit
- Created: 2026-04-07T10:19:41.000Z (2 months ago)
- Default Branch: main
- Last Pushed: 2026-05-18T21:46:20.000Z (29 days ago)
- Last Synced: 2026-05-18T23:57:22.074Z (29 days ago)
- Topics: domain-logic, game-development, gamification, level, leveling, package, progression, swift, swiftpm, ui-agnostic, unlocks, xp
- Language: Swift
- Homepage:
- Size: 20.5 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# ProgressionKit
A reusable progression engine that turns player performance into configurable XP, levels, and unlocks across games and apps. 📈
`ProgressionKit` is a pure Swift package for apps and games that need deterministic progression logic without coupling progression rules to storage or UI frameworks.
It models:
- `XP` gain from successful performance.
- Player levels derived from total XP.
- Track-scoped mastery across distinct content.
- Tier unlocks such as `beginner`, `intermediate`, and `advanced`.
The package is deliberately content-agnostic. Host apps decide what a track, content item, and tier mean, then feed those identifiers into `ProgressionKit`.
## Implemented APIs
- `PKEngine`: applies a progression event to a profile and returns the updated profile plus derived progress values.
- `PKProfile`: persisted progression state for a player.
- `PKConfig`: tunable progression rules such as level size, XP reward, tier order, and unlock thresholds.
- `PKEvent`: a single outcome emitted by the host app.
- `PKUpdate`: the result of applying one event.
## Structure
```mermaid
flowchart TB
subgraph HOST["Host App/Game"]
EVENTS["Performance Events"]
STORAGE["Storage Layer"]
UI["UI / HUD / XP Bar"]
end
subgraph PK[" "]
ENGINE["ProgressionKit"]
PROFILE["PKProfile"]
CONFIG["PKConfig"]
UPDATE["PKUpdate"]
end
EVENTS --> ENGINE
CONFIG --> ENGINE
ENGINE --> PROFILE
ENGINE --> UPDATE
PROFILE --> STORAGE
UPDATE --> UI
```
## Quick Start
Import the package and create an initial player profile:
```swift
import ProgressionKit
let profile = PKProfile()
```
Create an event whenever the player finishes one unit of content:
```swift
let event = PKEvent(
contentID: "lesson.greetings.001",
trackID: "japanese-basics",
tierID: "beginner",
wasSuccessful: true
)
```
Apply the event to the profile:
```swift
let update = PKEngine.apply(
event: event,
to: profile
)
```
`update` is a `PKUpdate` value that contains the updated `PKProfile` and derived progression values your app can render immediately.
Common `PKUpdate` values you will typically use:
- `update.profile`: persist this as the new `PKProfile`.
- `update.playerLevel`: current player level.
- `update.xpIntoLevel` and `update.xpForNextLevel`: useful for progress bars.
- `update.newlyUnlockedTierIDs`: tiers unlocked by the latest event.
- `update.didGrantXP`: whether the event changed XP.
## Configure Progression Rules
Use `PKConfig` when you want to customize level size, XP rewards, tier unlock order, and the mastery requirement for unlocking the next tier:
```swift
let config = PKConfig(
levelXP: 120,
masteryXP: 15,
tierOrder: ["beginner", "intermediate", "advanced"],
masteryRequirement: 4
)
```
Apply the same event with your custom config:
```swift
let configuredUpdate = PKEngine.apply(
event: event,
to: profile,
config: config
)
```
In practice:
- Persist `configuredUpdate.profile` (your new `PKProfile`) after each event.
- Read other `PKUpdate` values to update your UI (XP gain, level changes, unlock state, and mastery).
## SwiftUI Example (Simple Progress Bar)
This example shows a simple integration pattern: apply progression events, keep the latest `PKUpdate`, and render a progress bar from the returned values.
### Video
https://github.com/user-attachments/assets/3920bbde-7b6b-40f6-b02f-f5506410b4fb
### Code
```swift
import ProgressionKit
import SwiftUI
struct ProgressionDemoView: View {
@State private var profile = PKProfile()
@State private var lessonNumber = 1
private let config = PKConfig()
private var progress: Double {
min(Double(profile.totalXP) / Double(config.levelXP), 1)
}
var body: some View {
VStack(spacing: 16) {
Text(progress < 1 ? "Level 1" : "Level 2 🥳")
.font(.headline)
GeometryReader { geometry in
let totalWidth = geometry.size.width
let fillWidth = totalWidth * progress
ZStack(alignment: .leading) {
RoundedRectangle(cornerRadius: 10)
.fill(.gray.opacity(0.25))
RoundedRectangle(cornerRadius: 10)
.fill(.green)
.frame(width: fillWidth)
.animation(.snappy, value: progress)
}
}
.frame(height: 16)
Text("\(Int(progress * 100))%")
.font(.caption)
.foregroundStyle(.secondary)
Button("Complete Lesson") {
let event = PKEvent(
contentID: "lesson.greetings.\(lessonNumber)",
trackID: "japanese-basics",
tierID: "beginner",
wasSuccessful: true
)
let update = PKEngine.apply(
event: event,
to: profile,
config: config
)
withAnimation(.snappy) {
profile = update.profile
}
lessonNumber += 1
}
}
.padding()
}
}
// MARK: - Preview
#Preview {
ProgressionDemoView()
}
```
## Integration
### Xcode
Use Xcode's [built-in support for SPM](https://developer.apple.com/documentation/xcode/adding_package_dependencies_to_your_app).
*or...*
### Package.swift
In your `Package.swift`, add `ProgressionKit` as a dependency:
```swift
dependencies: [
.package(
url: "https://github.com/thatfactory/progressionkit",
from: "0.1.0"
)
]
```
Associate the dependency with your target:
```swift
targets: [
.target(
name: "YourTarget",
dependencies: [
.product(
name: "ProgressionKit",
package: "progressionkit"
)
]
)
]
```
Run: `swift build`