Casset Apps · App model
An App is one capability inside an artist's existing World.
Casset owns identity, authorization, installation, Profile World framing, playback, lifecycle, exit, and cleanup enforcement. An App owns a bounded interaction and disposable local presentation state.
Anatomy
Five pieces form the local contract.
casset-app.json reviewable declaration
src/main.ts(x) local entry and manifest parsing
src/App.ts(x) App-owned presentation
CassetAppHost snapshots, subscription, request channel
cleanup() unsubscribe and release local interactionDeclaration
Manifest
Names context, placement, requested permissions, compatibility, and fan-access support. It grants nothing.
Observation
Context
Contains only the server-approved data projection for this launch. It is short-lived and replaceable.
Authority
Host
Supplies snapshots and receives narrow requests. It never hands the App a player or navigation object.
Execution
Choose the context that matches the experience.
| Context | Use it for | Playback | Current data |
|---|---|---|---|
PROFILE_SURFACE | A capability that lives inside the Profile World. | May request an approved Track through PLAY_TRACK when permission and capability are present. | Artist, theme, catalog, active release; Moments, Campaigns, and Audience are unavailable. |
TRACK_RUNTIME | A visual experience bound to one host-authorized active Track. | Read-only canonical state and seconds. No command bridge. | Exact Track, optional release/theme, entitlements, timeline, and URL-free resource references. |
Availability
Every optional data family explains its absence.
Profile data uses
CassetData<T>; do not turn a missing projection into invented content.| State | Meaning | App response |
|---|---|---|
loading | The host is resolving the projection. | Show a quiet, non-dominant loading state. |
ready | Validated data is available. | Render only the supplied fields. |
empty | The projection succeeded but has no visible rows. | Compose an authored empty state; do not fabricate. |
permission-denied | The required permission was not granted. | Explain the unavailable capability without requesting private data. |
unavailable | The host lacks an adapter or the family does not apply. | Degrade calmly; do not fetch around the host. |
Lifecycle
Context is a lease, not permanent state.
| State | Contract |
|---|---|
CONTEXT_READY | The host has validated context; prepare presentation without inventing playback. |
ACTIVE | The App may respond to current host snapshots and local input. |
CLOSED | Stop reacting, remove listeners, and release App-owned presentation state. |
const unsubscribe = host.subscribe((snapshot) => {
if (snapshot.lifecycle === "CLOSED") {
deactivate()
return
}
if (snapshot.context.kind === "TRACK_RUNTIME") {
updateFromCanonicalTime(snapshot.context.playback.currentTimeSec)
}
})
return () => {
unsubscribe()
destroyLocalInteraction()
}Playback doctrine
Apps observe or request. Casset plays.
- Profile Apps guard
PLAY_TRACKwithplayback.controlandPROFILE_PLAY_TRACK. - Track Runtime reads
currentTimeSec,durationSec, state, progress, and timeline from the canonical host snapshot. - No App receives raw audio URLs, tokens, the audio element, transport store, mutable clock, analyser, scheduler, or render owner.
- Local visual preference is allowed; local playback truth is not.
Server truth
Visible does not mean authorized.
Install and enable
The artist's server-owned installation and permission grant must exist before a production host context can be created.
Disable or remove
Future route and context creation fails closed. A fixture cannot simulate or override that authorization.
Collector access
Where supported, Casset checks the existing same-artist Casset purchase before the App implementation mounts.