Avatar Protocol — each player owns and drives a rich avatar persona (persona fields, a generated portrait, and a public profile) as a first-class game capability.
The protocol is PROVIDER-AGNOSTIC. It owns the :avatar game-state and the
event contract, but never talks to an avatar service directly. A command
validates, records the player's local mirror as :pending, and emits a
provider-neutral :avatar/* effect. The GM-side interceptor
(game.handlers/execute-avatar-effects) resolves the configured provider (see
game.protocols.avatar-provider; Yvatar is the first implementation), runs the
call holding the service credentials, and folds the normalized result back into
this protocol via the avatar/succeeded / avatar/failed system callbacks —
the exact analog of coseller's ledger-settlement callbacks.
Player↔avatar mapping is automatic: the interceptor passes provider = game-name, external-user-id = player-name, so each player owns exactly one
avatar per game with no extra input. No provider name appears anywhere in this
namespace or its state — a second provider needs zero changes here.
Avatar Protocol — each player owns and drives a rich avatar persona (persona fields, a generated portrait, and a public profile) as a first-class game capability. The protocol is PROVIDER-AGNOSTIC. It owns the `:avatar` game-state and the event contract, but never talks to an avatar service directly. A command validates, records the player's local mirror as `:pending`, and emits a provider-neutral `:avatar/*` effect. The GM-side interceptor (`game.handlers/execute-avatar-effects`) resolves the configured provider (see `game.protocols.avatar-provider`; Yvatar is the first implementation), runs the call holding the service credentials, and folds the normalized result back into this protocol via the `avatar/succeeded` / `avatar/failed` system callbacks — the exact analog of coseller's ledger-settlement callbacks. Player↔avatar mapping is automatic: the interceptor passes `provider = game-name`, `external-user-id = player-name`, so each player owns exactly one avatar per game with no extra input. No provider name appears anywhere in this namespace or its state — a second provider needs zero changes here.
(handle-accept-portrait payload)Promote the player's pending portrait to their accepted portrait.
Promote the player's pending portrait to their accepted portrait.
(handle-avatar-failed payload)Record a failed provider call on the player's avatar mirror (status :error + :last-error) and emit avatar-error. Invoked by the GM interceptor, not players.
Record a failed provider call on the player's avatar mirror (status :error + :last-error) and emit avatar-error. Invoked by the GM interceptor, not players.
(handle-avatar-succeeded payload)Fold a successful provider result into the player's avatar mirror: apply the returned ids/urls, flip status to :active, clear any prior error, and emit the declarative avatar-updated event. Invoked by the GM interceptor, not players.
Fold a successful provider result into the player's avatar mirror: apply the returned ids/urls, flip status to :active, clear any prior error, and emit the declarative avatar-updated event. Invoked by the GM interceptor, not players.
(handle-confirm-publish payload)Publish the player's current draft post live to :platform. Requires an existing draft post (call avatar/publish-post first).
Publish the player's current draft post live to :platform. Requires an existing draft post (call avatar/publish-post first).
(handle-connect payload)Bootstrap the local mirror from the avatar already linked to this player's external identity at the provider. Unlike ordinary reads, connect deliberately does not require a mirror: creating that first mirror is the operation's job.
Bootstrap the local mirror from the avatar already linked to this player's external identity at the provider. Unlike ordinary reads, connect deliberately does not require a mirror: creating that first mirror is the operation's job.
(handle-create-unsupported _payload)Refuses avatar/create. the-js does not create avatars.
The only credential the GM holds is a developer token, so anything it creates lands in the TOKEN OWNER's Yvatar account rather than the player's — and there is no claim or transfer flow to move it afterwards. The player creates in Yvatar (the picker links through to /yvatars/new) and connects it instead.
Registered-and-refusing rather than deleted, deliberately: :roles admits
:creator and :strategist, so a player AGENT can call this directly — dropping
the button from the UI would not close that path. handle-upsert is untouched
(:update still uses it), so Phase 2 re-enables creation under the player's own
authority by pointing :handler back at it.
Refuses avatar/create. the-js does not create avatars. The only credential the GM holds is a developer token, so anything it creates lands in the TOKEN OWNER's Yvatar account rather than the player's — and there is no claim or transfer flow to move it afterwards. The player creates in Yvatar (the picker links through to /yvatars/new) and connects it instead. Registered-and-refusing rather than deleted, deliberately: :roles admits :creator and :strategist, so a player AGENT can call this directly — dropping the button from the UI would not close that path. `handle-upsert` is untouched (:update still uses it), so Phase 2 re-enables creation under the player's own authority by pointing :handler back at it.
(handle-generate-portrait payload)Request a portrait for the player's avatar → produces a pending portrait (may consume a provider image credit). Result folds back via avatar/succeeded.
Request a portrait for the player's avatar → produces a pending portrait (may consume a provider image credit). Result folds back via avatar/succeeded.
(handle-get payload)Fetch the full rich persona for the player's avatar (server-side use).
Fetch the full rich persona for the player's avatar (server-side use).
(handle-get-post-status payload)Check the player's current draft post on demand — a single synchronous check, NOT a polling loop. Video generation is asynchronous, so a caller (e.g. a player-facing "refresh" action) uses this to learn whether a prior avatar/publish-post or avatar/regenerate-post call has finished. Requires an existing draft post.
Check the player's current draft post on demand — a single synchronous check, NOT a polling loop. Video generation is asynchronous, so a caller (e.g. a player-facing "refresh" action) uses this to learn whether a prior avatar/publish-post or avatar/regenerate-post call has finished. Requires an existing draft post.
(handle-get-public payload)Fetch the embed-safe public profile shape for the player's avatar.
Fetch the embed-safe public profile shape for the player's avatar.
(handle-publish-post payload)Draft a new video post for the player's avatar from a script (:prompt). Requires an existing avatar. Sets :pending and emits an :avatar/publish-post effect — video generation is asynchronous, so this does NOT post anything externally yet and does not wait for the render to finish; follow with avatar/get-post-status to check on it. Replaces any prior draft post.
Draft a new video post for the player's avatar from a script (:prompt). Requires an existing avatar. Sets :pending and emits an :avatar/publish-post effect — video generation is asynchronous, so this does NOT post anything externally yet and does not wait for the render to finish; follow with avatar/get-post-status to check on it. Replaces any prior draft post.
(handle-query-avatar payload)Read the GM's local avatar mirror for the player (or :target) — status, ids, and cached urls. No provider call.
Read the GM's local avatar mirror for the player (or :target) — status, ids, and cached urls. No provider call.
(handle-regenerate-post payload)Redraft the player's current pending post, optionally guided by :feedback. Requires an existing draft post (call avatar/publish-post first).
Redraft the player's current pending post, optionally guided by :feedback. Requires an existing draft post (call avatar/publish-post first).
(handle-upsert payload)Create or update the player's mapped avatar persona (routes both avatar/create and avatar/update). Merges the submitted persona fields over any existing ones, sets the local mirror to :pending, and emits an :avatar/upsert effect carrying the full merged persona for the provider to write.
Create or update the player's mapped avatar persona (routes both avatar/create and avatar/update). Merges the submitted persona fields over any existing ones, sets the local mirror to :pending, and emits an :avatar/upsert effect carrying the full merged persona for the provider to write.
(validate-payload event-key payload)cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |