Component Options / Activity
State & Affordance
Affordance attributes declare what a component invites you to do with it, before you commit to doing it. The attribute is read across the runtime — haptics, brace gestures, the region rail, and the cauldron all consult it — but only one value currently changes behavior on its own.
Affordance is a force on the presence field
Affordance does not own a look. It states how much presence a component is asking for, and that request is multiplied into a shared field alongside every other module making the same kind of claim — region, charge, locality, machinability. The field resolves once, at the renderer, and the result is spent on edge definition and lift.
Its own axis
Affordance writes --spw-salience-affordance, not the shared salience property. That matters: the older feeders all declare --spw-architecture-salience directly, so two of them on one element do not stack — the cascade picks a winner. A separate axis lets affordance multiply with charge and region on the same element.
Composition, not paint
Twelve values, one renderer. Adding a thirteenth value — or a whole new module — is a one-line declaration with a default of 1. Nothing new gets painted, and no selector has to win a specificity fight to be heard.
Where JavaScript still branches
tune keeps a second, older life in the runtime: tuning-discovery.js and module-catalog-enhancement.js select on it, and page-region-rail.js tests for it and writes it back onto rail links so a tunable region earns a sigil. Those tests are exact-match, so a stacked value like read tune registers with the CSS field but not with the rail.
This panel carries data-spw-affordance="tune" — the strongest request in the vocabulary. The panels in the next section each carry their own value, so the section below is not an illustration of the scale. It is the scale.
The twelve values in use
Counts are occurrences in the site's HTML. The long tail is not dead weight — it is where the surface is still deciding what it wants to be.
read 359
Reference material. The component expects to be taken in, not operated. By far the default across topic and editorial surfaces.
orient 78
Hero blocks and primary navigation. Anchors page flow and gives the reader a firm return point inside a long scroll.
inspect 69
Invites a closer look — deeper metadata, traces, structural guidelines. Pairs naturally with the console and field-guide features.
navigate 58
Moves you somewhere else. navigation-spells.js uses navigate ground replay as its default affordance for links that do not declare one.
tune 33
Holds live controls. The one value the runtime acts on — see above.
act 17
Commits something. Distinct from tune: tuning adjusts a value in place, acting takes a step that has a consequence.
practice 10
Repeatable exercise. The component expects to be run more than once, and expects you to get better at it.
revisit 8
Built for return rather than first contact. Assumes you have been here and are coming back with context.
reward 4
Gives something back for the interaction — a collectable, an unlock, a acknowledgement that the effort registered.
reflect 4
Asks for consideration rather than input. No correct answer to submit.
choose 4
Presents alternatives that are genuinely exclusive. Picking one forecloses the others.
learn 3
Instructional intent. The component is trying to leave you able to do something you could not do before.
Affordance stacks
The attribute is space-separated, not single-valued. navigation-spells.js assigns navigate ground replay as a three-part default, and brace-gestures.js trims and splits whatever it finds. A component that both reads and rewards can say so:
<article data-spw-affordance="read reward">
Because only tune is matched exactly by page-region-rail.js, a stacked value containing tune alongside others will not register as tunable on the region rail. If a component needs the rail, tune must stand alone. That asymmetry is a real edge in the current implementation, not a convention.