Factions
Players enroll in MUD, ONI or Ustur. Read the faction that an existing
Profile joined with getFactionForProfile:
import { getFactionForProfile } from '@aephia/atlas-kit/factions';
const enrollment = await getFactionForProfile(ctx, profileAddress);console.log(enrollment.faction, enrollment.factionId);Player enrollment and NPC factions
Section titled “Player enrollment and NPC factions”A Profile’s enrollment and a Game’s dynamic faction registry are different things. Enrollment records the player’s MUD/ONI/Ustur choice. The dynamic registry describes factions used by other game systems, including NPCs such as Jorvik (ID 4). Inspecting an NPC faction does not make it a player-enrollment option.
getFactionForProfile(ctx, profileAddress)reads a player’s enrollment.getFaction(ctx, factionId)reads a Game-scoped dynamic faction record.getFleetCombatStatus(ctx, fleetAddress)from the combat entry exposesparticipant.kind; an NPC participant retains its numericfactionId. This remains useful even when its dynamic registry record is unavailable.
Keep the NPC ID when inspecting Fleet state and combat activity. Do not infer player membership from a Fleet’s owner Profile, treat every faction ID as a playable choice, or require a registry record merely to recognize an NPC. NPC action planning remains subject to each action’s documented authority and preconditions; faction inspection grants no authority to act for that NPC.
Optional enrollment
Section titled “Optional enrollment”Use maybeGetFactionForProfile(ctx, profileAddress) when the Profile may not
have enrolled yet. It returns undefined only when its canonical enrollment is
absent. A present record exposes profile, faction, and factionId;
faction is unaligned, mud, oni, or ustur. Invalid owners, malformed
bytes, and wrong Profile relationships are errors, not missing enrollment.
Use getFactionForProfile when enrollment must already exist. After a confirmed
write, read it with { refresh: true } and verify both the Profile and selected
faction. Reads never choose a faction or create an account.
Dynamic registry, diplomacy and standing
Section titled “Dynamic registry, diplomacy and standing”The faction entry also covers dynamic faction identity, economics, diplomacy,
standing, treasuries, asset ownership and King-system ownership. These reads do
not replace player enrollment. maybeGetFactionStanding returns undefined
when no standing is recorded; getFaction asserts that a registry record exists
and reports ACCOUNT_NOT_FOUND if it does not.
Recorded example — z.ink PTR, 2026-08-30. The example below remains runnable against the documentation’s isolated historical faction scenario, using dynamic faction ID 4. Its registry record was removed on 2026-09-09. It is not a current PTR availability promise or a player-enrollment example. Live documentation checks still execute this example as archived replay, separately from current player reads. For your own deployment, provide an existing dynamic faction ID.
import { getFaction, getFactionRelations, maybeGetFactionStanding,} from '@aephia/atlas-kit/factions';
const faction = await getFaction(ctx, factionId);const relations = await getFactionRelations(ctx);const standing = await maybeGetFactionStanding(ctx, profileAddress, factionId);console.log(faction.factionId, relations, standing);First enrollment
Section titled “First enrollment”planChooseFaction from @aephia/atlas-kit/factions/actions plans first
enrollment into mud, oni, or ustur. It rejects an existing enrollment
account, including an existing unaligned account. Reuse a valid enrollment;
faction switching and repair of existing accounts are outside this planner.
Illustrative: supply a configured context, an existing Profile address, and its authorized wallet address. Use the actual Profile key index (shown as zero here). The result is an inert Plan; this snippet does not sign or submit.
import { planChooseFaction } from '@aephia/atlas-kit/factions/actions';import type { PlanAuthorization } from '@aephia/atlas-kit/factions/actions';
const authorization: PlanAuthorization = { profile: profileAddress, authority: walletAddress, keyIndex: 0,};
const plan = await planChooseFaction(ctx, { faction: 'ustur', authorization,});console.log(plan.describe());The Profile authority signs this instruction. There is no separate payer: the program funds the new account from the Profile account’s own on-chain balance, preserving the Profile’s rent reserve. A funded authority wallet does not replace that balance. The planner validates the current Rent account and observed Profile funding; it does not transfer funds or top up the Profile. Transaction fees remain separate and execution requires an explicit fee payer.
Inspect the Plan’s signers, writable accounts, funding description, and preconditions, then simulate before requesting signatures. The account must remain absent and validated prerequisite state must remain unchanged. Profile permissions and certificate authorization ultimately remain chain-authoritative; local validation is not proof that every delegated certificate path is accepted. When delegation requires a certificate, its account must exist before the planner returns a Plan. A missing account produces a remedy to select an existing certificate or a matching direct Profile key. An unused certificate supplied with valid direct authority remains ignored. Profile authority, Rent pricing and certificate guards identify their respective roles and explain how to replan.
After confirmed execution, load the enrollment again with a refresh read. A simulation or submitted signature alone does not establish enrollment. The PTR evidence uses unsigned simulations, without live account creation or token movement.
Region presentation metadata
Section titled “Region presentation metadata”Classification: off-chain/editor-authored color is editor-local; live Region
presentation is chain-derived from owner and safety. The official map
editor’s inspected 2026-09-13
createNewRegion producer
reads a color picker and stores its value as color in regionDefinitions.
The export code
serializes those definitions alongside the systems in mapData. This directly
establishes an editor source, not a canonical C4 palette or a chain-addressed
payload. The reported 69 Regions in the dated 2026-06-09 export are consumer
evidence, not a schema or a verified deployment mapping.
The checked @staratlas/[email protected] generated Region type and
RegionTracker account codecs contain ownership, safety/risk, XP, geometry,
connections, systems and research requirements, but no color or Region content
reference. Region is nested in RegionTracker, not a separately addressable
account. Faction.contentUriHash belongs to FactionAccount, whose generated
comment describes an off-chain manifest hash for cosmetics, blueprints and
dialogue; neither that hash nor its homeRegion field proves a Region palette
relationship. The checked @staratlas/[email protected] Faction
type is an alignment enum, not another metadata account.
The deployed C4 client inspected 2026-09-13 uses drawRegions and
getFactionColorFromOwner to choose Region fill/stroke color from chain
Region.owner, using a fixed faction palette. Safety/risk status governs baseline
opacity; hover, selection and zoom add client-side styling. It draws borders
from the chain Region geometry, not the editor’s authored palette.
For live-game-style presentation, use TerritoryRegionSummary.owner and
TerritoryRegionSummary.safety, which already project the governing chain
fields. Also use TerritoryRegionSummary.risk when matching the client’s
low-risk styling: low-risk Regions, or safe aligned Regions, receive that style.
Choose presentation styles in your application; do not join editor IDs
to chain Region IDs to reproduce the live renderer. Editor timestamp string IDs
and chain u16 IDs are different namespaces. Custom editor palettes remain
application-owned authoring data, not SDK-owned canonical Region metadata.
There is no proven Region-scoped content reference supplying authored color.
The checked schema does not prove universal on-chain absence; it does expose
the owner/safety inputs used by the inspected live renderer. No separate implementation issue is needed:
those inputs are already exposed, and no new stored color or canonical payload
was discovered. TerritoryRegionSummary gains no color/content fields, and the
SDK does not fetch or vendor editor exports.
The dated provenance record contains the deployed bundle URL, SHA-256, renderer anchors, editor-source hashes and codec boundaries. See also the #436 chain-audit correction: editor-only evidence previously missed chain-derived visual semantics. Star and Celestial Body findings remain separate from this Region conclusion.
Gotchas
Section titled “Gotchas”Keep player alignment and NPC identity separate. Enrollment ID 0 means
unaligned. For a Fleet, inspect its explicit participant kind and retain an
NPC participant’s numeric faction ID; do not infer NPC identity from a player
alignment value or its owner Profile.
Standing is per profile, not per character. It belongs to the wider Star Atlas identity rather than to the SAGE character.
Relations are between factions, not players. Diplomacy describes the factions’ stances toward each other.
Reference
Section titled “Reference”factions— every export in this entryfactions/actions— enrollment plannerloyalty— contributing to a faction over an epochidentity— the profile standing attaches to