action-forms
A dialog that asks the player something and hands an answer back is an action form: `openForm(Form, input)` from anywhere, awaited, null when the player walks away. An NPC is one folder under `src/ove
SKILL.md.claude/skills/action-forms/SKILL.md
GitHubA question is a promise. src/components/forms holds the forms, the stack they
open on and the one FormHost the app draws them in.
Forms
- A form is
defineForm({ title, prompt, view }). The view draws only its own content and itsDialogActions; the frame (nameplate, the line under it) is whoever opened it. It ends withsubmit(answer)orcancel(), and its way out saysleave. openForm(Form, input)opens it over whatever is up and resolves with the answer, or null. Only the top frame shows, so a form opened from inside another dialog's flow never fights it for the closing click.- A form that needs a record declares the resource and reads it in a child
under its own
Suspensewith a fallback, so a conversation's line stays up while it loads. - Reach for the generic ones before writing a new one:
choose/choiceForm,PickCatchForm,PickItemForm,PickMoveForm,PickBoxForm,TeachMoveForm.
NPCs
- One folder per role under
src/overworld/npcs.index.tsiscreateNpc(Npc.X, { name, description, quote, spent, sprites, visit, wanders, shop, interact: () => import('./interact') }), andinteract.tsxbeside it is the script. Add the folder to theRecordinsrc/overworld/npcs/index.ts. interactstays a loader. The server and world generation read the definitions, and a static import would hand them every form and picker the script asks through.wandersputs a role in the wandering roll, which is world generation: a new wanderer moves who stands on every existing cell, so it is a deliberate change with its test updated.- A script is
(visit) => Promise<void>. It talks throughvisit.say,visit.askandvisit.form, reads the purse and bag throughvisit.gold/bag/carrying, and reports arrivals withvisit.notify. Roles that share one script (the shops) pointinteractat it. - A null from a step is the player declining; the script decides whether that ends it or steps back. A player who walks away ends the script where it stands, so no step needs to check.
- A once-a-window NPC (
visitin its definition) says itsspentline instead of running the script when the server has already served the player. - The script is presentation. Everything it changes goes through a server function that derives the NPC again from the cell and refuses on its own.