@almadar/std 16.183.0 → 16.185.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/behaviors/lolo/ui/core/.hand-authored.json +4 -0
  2. package/behaviors/lolo/ui/core/atoms/std-browse.lolo +11 -0
  3. package/behaviors/lolo/ui/core/atoms/std-related.lolo +86 -9
  4. package/behaviors/lolo/ui/core/atoms/std-rich-editor.lolo +368 -1
  5. package/behaviors/lolo/ui/core/atoms/std-tag-taxonomy.lolo +62 -2
  6. package/behaviors/lolo/ui/core/atoms/std-thread.lolo +43 -2
  7. package/behaviors/lolo/ui/core/atoms/std-tree.lolo +247 -0
  8. package/behaviors/lolo/ui/core/atoms/std-version-history.lolo +110 -2
  9. package/behaviors/lolo/ui/core/molecules/ui-file-tree.lolo +18 -2
  10. package/behaviors/lolo/ui/core/organisms/ui-detail-panel.lolo +12 -2
  11. package/behaviors/lolo/ui/core/organisms/ui-form-section.lolo +2 -2
  12. package/behaviors/lolo/ui/core/organisms/ui-form.lolo +2 -2
  13. package/behaviors/lolo/ui/game/atoms/std-tutorial-autodemo.lolo +136 -0
  14. package/behaviors/lolo/ui/game/atoms/std-tutorial-overlay.lolo +41 -8
  15. package/behaviors/lolo/ui/learning/atoms/ui-math-canvas.lolo +3 -3
  16. package/behaviors/registry/ui/core/atoms/std-browse.orb +17 -0
  17. package/behaviors/registry/ui/core/atoms/std-related.orb +256 -3
  18. package/behaviors/registry/ui/core/atoms/std-rich-editor.orb +898 -1
  19. package/behaviors/registry/ui/core/atoms/std-tag-taxonomy.orb +240 -8
  20. package/behaviors/registry/ui/core/atoms/std-thread.orb +254 -4
  21. package/behaviors/registry/ui/core/atoms/std-tree.orb +656 -0
  22. package/behaviors/registry/ui/core/atoms/std-version-history.orb +479 -6
  23. package/behaviors/registry/ui/core/molecules/ui-file-tree.orb +43 -19
  24. package/behaviors/registry/ui/core/organisms/ui-detail-panel.orb +37 -3
  25. package/behaviors/registry/ui/core/organisms/ui-form-section.orb +8 -2
  26. package/behaviors/registry/ui/core/organisms/ui-form.orb +8 -2
  27. package/behaviors/registry/ui/game/atoms/std-tutorial-autodemo.orb +732 -0
  28. package/behaviors/registry/ui/game/atoms/std-tutorial-overlay.orb +305 -153
  29. package/behaviors/registry/ui/learning/atoms/ui-math-canvas.orb +26 -0
  30. package/dist/behaviors/exports-reader.js +5132 -2398
  31. package/dist/behaviors/functions/index.d.ts +261 -44
  32. package/dist/behaviors/functions/index.js +5118 -2396
  33. package/dist/behaviors/index.d.ts +1 -1
  34. package/dist/behaviors/index.js +5133 -2399
  35. package/dist/behaviors/query.js +5132 -2398
  36. package/dist/behaviors-embeddings.hash.json +3 -3
  37. package/dist/behaviors-embeddings.json +310 -302
  38. package/dist/behaviors-registry.json +820 -35
  39. package/dist/index.d.ts +1 -1
  40. package/dist/index.js +5133 -2399
  41. package/dist/knob-embeddings.hash.json +3 -3
  42. package/dist/knob-embeddings.json +1 -1
  43. package/dist/registry/factory-signatures.json +1 -1
  44. package/package.json +2 -2
@@ -9,6 +9,12 @@ orbital FileTreeOrbital {
9
9
  size : number
10
10
  language : string
11
11
  }
12
+ type FileTreeItemsItem = {
13
+ id : string!
14
+ label : string!
15
+ parentId : string
16
+ icon : string
17
+ }
12
18
 
13
19
  entity FileTreeItem [runtime] {
14
20
  id : string!
@@ -21,8 +27,10 @@ orbital FileTreeOrbital {
21
27
  INIT -> idle
22
28
  (render-ui main {
23
29
  tree: @config.tree
30
+ items: @config.items
24
31
  selectedPath: @config.selectedPath
25
32
  onFileSelect: @config.onFileSelect
33
+ onNodeSelect: @config.onNodeSelect
26
34
  className: @config.className
27
35
  indent: @config.indent
28
36
  type: file-tree
@@ -38,9 +46,13 @@ orbital FileTreeOrbital {
38
46
  }
39
47
 
40
48
  config {
41
- tree : [FileTreeTreeItem] = [{ name: "Name", path: "Path", type: file, children: [], size: 1, language: "Language" }, { name: "Name 2", path: "Path 2", type: dir, children: [], size: 2, language: "Language 2" }]
49
+ tree : [FileTreeTreeItem] = []
42
50
  @label "Tree"
43
- @description "The tree data"
51
+ @description "The tree data (pre-nested). Ignored when `items` is provided."
52
+ @tier "presentation"
53
+ items : [FileTreeItemsItem] = []
54
+ @label "Items"
55
+ @description "Flat node list, nested by `parentId` at render time — takes precedence over `tree` when provided. A `parentId` with no matching row renders that node as a root rather than dropping it."
44
56
  @tier "presentation"
45
57
  selectedPath : string
46
58
  @label "Selected Path"
@@ -50,6 +62,10 @@ orbital FileTreeOrbital {
50
62
  @label "On File Select"
51
63
  @description "Called when a file is clicked"
52
64
  @tier "presentation"
65
+ onNodeSelect : string = ""
66
+ @label "On Node Select"
67
+ @description "Called when a node is clicked, in flat `items` mode; carries the selected node's id. Presence-gated: binding this prop is what turns on the click-to-select affordance, mirroring Badge's `onRemove`."
68
+ @tier "presentation"
53
69
  className : string
54
70
  @label "Class Name"
55
71
  @description "CSS class"
@@ -41,7 +41,11 @@ orbital DetailPanelOrbital {
41
41
  header : string
42
42
  type : string
43
43
  values : [string]
44
- relation : string
44
+ relation : DetailPanelFieldsItemRelation
45
+ }
46
+ type DetailPanelFieldsItemRelation = {
47
+ entity : string!
48
+ cardinality : "one" | "many" | "one-to-many" | "many-to-one" | "many-to-many"
45
49
  }
46
50
  type DetailPanelRelationsDataValueItem = {
47
51
  value : string!
@@ -74,6 +78,7 @@ orbital DetailPanelOrbital {
74
78
  selectedIds: @config.selectedIds
75
79
  entity: @entity
76
80
  title: @config.title
81
+ onTitleCommit: @config.onTitleCommit
77
82
  subtitle: @config.subtitle
78
83
  status: @config.status
79
84
  avatar: @config.avatar
@@ -109,6 +114,7 @@ orbital DetailPanelOrbital {
109
114
  selectedIds: @config.selectedIds
110
115
  entity: @payload.data
111
116
  title: @config.title
117
+ onTitleCommit: @config.onTitleCommit
112
118
  subtitle: @config.subtitle
113
119
  status: @config.status
114
120
  avatar: @config.avatar
@@ -188,6 +194,10 @@ orbital DetailPanelOrbital {
188
194
  @label "Title"
189
195
  @description "title prop"
190
196
  @tier "presentation"
197
+ onTitleCommit : string = ""
198
+ @label "On Title Commit"
199
+ @description "When bound, the title becomes editable in place: clicking it swaps the heading for an input, Enter or blur commits, Escape reverts. Receives the committed title and the record's id so the host can persist a partial update. Unbound, the title stays a plain heading."
200
+ @tier "presentation"
191
201
  subtitle : string
192
202
  @label "Subtitle"
193
203
  @description "subtitle prop"
@@ -224,7 +234,7 @@ orbital DetailPanelOrbital {
224
234
  @label "Slide Over"
225
235
  @description "slideOver prop"
226
236
  @tier "presentation"
227
- fields : [DetailPanelFieldsItem] = [{ key: "Key", header: "Header", type: "Type", values: ["Item", "Item 2"], relation: "Relation" }, { key: "Key 2", header: "Header 2", type: "Type 2", values: ["Item", "Item 2"], relation: "Relation 2" }]
237
+ fields : [DetailPanelFieldsItem] = [{ key: "Key", header: "Header", type: "Type", values: ["Item", "Item 2"], relation: { entity: "Entity", cardinality: one } }, { key: "Key 2", header: "Header 2", type: "Type 2", values: ["Item", "Item 2"], relation: { entity: "Entity 2", cardinality: many } }]
228
238
  @label "Fields"
229
239
  @description "Fields to display - accepts string[], {key, header}[], or DetailField[]"
230
240
  @tier "presentation"
@@ -29,7 +29,7 @@ orbital FormSectionOrbital {
29
29
  type FormSectionFieldsItemRelation = {
30
30
  entity : string!
31
31
  displayField : string
32
- cardinality : "one" | "many"
32
+ cardinality : "one" | "many" | "one-to-many" | "many-to-one" | "many-to-many"
33
33
  }
34
34
  type FormSectionFieldsItemValidation = {
35
35
  enum : [string]
@@ -108,7 +108,7 @@ orbital FormSectionOrbital {
108
108
  type FormSectionSectionsItemFieldsItemRelation = {
109
109
  entity : string!
110
110
  displayField : string
111
- cardinality : "one" | "many"
111
+ cardinality : "one" | "many" | "one-to-many" | "many-to-one" | "many-to-many"
112
112
  }
113
113
  type FormSectionSectionsItemFieldsItemValidation = {
114
114
  enum : [string]
@@ -29,7 +29,7 @@ orbital FormOrbital {
29
29
  type FormFieldsItemRelation = {
30
30
  entity : string!
31
31
  displayField : string
32
- cardinality : "one" | "many"
32
+ cardinality : "one" | "many" | "one-to-many" | "many-to-one" | "many-to-many"
33
33
  }
34
34
  type FormFieldsItemValidation = {
35
35
  enum : [string]
@@ -108,7 +108,7 @@ orbital FormOrbital {
108
108
  type FormSectionsItemFieldsItemRelation = {
109
109
  entity : string!
110
110
  displayField : string
111
- cardinality : "one" | "many"
111
+ cardinality : "one" | "many" | "one-to-many" | "many-to-one" | "many-to-many"
112
112
  }
113
113
  type FormSectionsItemFieldsItemValidation = {
114
114
  enum : [string]
@@ -0,0 +1,136 @@
1
+ app std-tutorial-autodemo "1.0.0"
2
+ "Generic scripted input-replay atom: the demo half of a tutorial. Holds one or more named cue scripts (each an ordered list of { at, event, arg } rows where at is a millisecond offset and event is LEFT/RIGHT/JUMP/STOP); listens for TUTORIAL_DEMO_START { demoId } (from std-tutorial-overlay's demoId step) and plays the matching script on a 32ms clock, emitting the semantic DEMO_LEFT / DEMO_RIGHT / DEMO_JUMP / DEMO_STOP events the host board maps onto its own movement. TUTORIAL_DEMO_STOP, DEMO_CANCEL (real user input), or exhausting the cue list end the demo and emit DEMO_STOP so the character stops moving. Renders a small Demo badge while playing. Domain-agnostic: the demo never emits board events (OW_*, etc.) — the organism maps DEMO_* to its own steering, so a demo cannot self-cancel through the board's input path."
3
+ orbital TutorialAutoDemoOrbital {
4
+ type DemoCue = {
5
+ at : number!
6
+ event : string!
7
+ arg : number
8
+ }
9
+ type DemoScript = {
10
+ id : string!
11
+ cues : [DemoCue]!
12
+ }
13
+
14
+ entity AutoDemoData [runtime] {
15
+ id : string!
16
+ playing : boolean = false
17
+ scriptId : string = ""
18
+ elapsed : number = 0
19
+ cueIndex : number = 0
20
+ }
21
+
22
+ trait AutoDemo -> @rebindable AutoDemoData [interaction, instance] {
23
+ initial: idle
24
+
25
+ state idle {
26
+ INIT -> idle
27
+ (render-ui hud-top null)
28
+
29
+ TUTORIAL_DEMO_START -> playing
30
+ (set @entity.scriptId @payload.demoId)
31
+ (set @entity.elapsed 0)
32
+ (set @entity.cueIndex 0)
33
+ (set @entity.playing true)
34
+ (render-ui hud-top {
35
+ type: badge
36
+ label: "Demo"
37
+ variant: "info"
38
+ })
39
+
40
+ TUTORIAL_DEMO_STOP -> idle
41
+ (render-ui hud-top null)
42
+
43
+ DEMO_CANCEL -> idle
44
+ (render-ui hud-top null)
45
+ }
46
+
47
+ state playing {
48
+ TUTORIAL_DEMO_START -> playing
49
+ (set @entity.scriptId @payload.demoId)
50
+ (set @entity.elapsed 0)
51
+ (set @entity.cueIndex 0)
52
+ (render-ui hud-top {
53
+ type: badge
54
+ label: "Demo"
55
+ variant: "info"
56
+ })
57
+
58
+ TUTORIAL_DEMO_STOP -> idle
59
+ (set @entity.playing false)
60
+ (render-ui hud-top null)
61
+ (emit DEMO_STOP {})
62
+
63
+ DEMO_CANCEL -> idle
64
+ (set @entity.playing false)
65
+ (render-ui hud-top null)
66
+ (emit DEMO_STOP {})
67
+ }
68
+
69
+ ticks {
70
+ demoTick every 32ms when (== @entity.playing true)
71
+ (set @entity.elapsed (+ @entity.elapsed 32))
72
+ (let ((scriptMatch (array/filter @config.scripts (fn s (== (object/get @s id) @entity.scriptId)))))
73
+ (let ((cueList (if (> (array/len @scriptMatch) 0) (object/get (array/first @scriptMatch) cues []) [])))
74
+ (let ((cue (if (< @entity.cueIndex (array/len @cueList)) (array/nth @cueList @entity.cueIndex) { at: 999999, event: "" })))
75
+ (do
76
+ (if (<= (object/get @cue at 0) @entity.elapsed)
77
+ (do
78
+ (set @entity.cueIndex (+ @entity.cueIndex 1))
79
+ (if (== (object/get @cue event "") "LEFT") (emit DEMO_LEFT {}) null)
80
+ (if (== (object/get @cue event "") "RIGHT") (emit DEMO_RIGHT {}) null)
81
+ (if (== (object/get @cue event "") "JUMP") (emit DEMO_JUMP {}) null)
82
+ (if (== (object/get @cue event "") "STOP") (emit DEMO_STOP {}) null))
83
+ null)
84
+ (if (>= @entity.cueIndex (array/len @cueList))
85
+ (do
86
+ (set @entity.playing false)
87
+ (render-ui hud-top null)
88
+ (emit DEMO_STOP {}))
89
+ null)))))
90
+ }
91
+
92
+ listens {
93
+ TUTORIAL_DEMO_START {
94
+ demoId : string!
95
+ }
96
+ @description "A tutorial step carrying a demoId was shown (std-tutorial-overlay); begin playing the cue script whose id matches demoId."
97
+ @tier "domain"
98
+ TUTORIAL_DEMO_STOP {
99
+ }
100
+ @description "The tutorial left a demo step or was dismissed; stop the demo and release control."
101
+ @tier "domain"
102
+ DEMO_CANCEL {
103
+ }
104
+ @description "Real user input was received by the host board; stop the demo immediately and hand control back to the player."
105
+ @tier "domain"
106
+ }
107
+
108
+ emits {
109
+ DEMO_LEFT -> external {
110
+ }
111
+ @description "Scripted run-left cue; the host board maps this to its own steer-left."
112
+ @tier "domain"
113
+ DEMO_RIGHT -> external {
114
+ }
115
+ @description "Scripted run-right cue; the host board maps this to its own steer-right."
116
+ @tier "domain"
117
+ DEMO_JUMP -> external {
118
+ }
119
+ @description "Scripted jump cue; the host board maps this to its own jump."
120
+ @tier "domain"
121
+ DEMO_STOP -> external {
122
+ }
123
+ @description "Scripted stop cue (or demo end/cancel); the host board maps this to stop movement."
124
+ @tier "domain"
125
+ }
126
+
127
+ config {
128
+ scripts : [DemoScript] = []
129
+ @label "Scripts"
130
+ @description "Named cue scripts keyed by the tutorial step's demoId; each cue fires its event after `at` milliseconds of the demo clock."
131
+ @tier "domain"
132
+ }
133
+ }
134
+
135
+ page "/tutorial-autodemo" as TutorialAutoDemoPage -> AutoDemo
136
+ }
@@ -1,12 +1,11 @@
1
1
  app std-tutorial-overlay "1.0.0"
2
- "Tutorial modal with media steps for game boards and learning shells: a paged overlay — title, an animated GIF/clip showing exactly how the mechanic is done, one line of body copy, a step counter, and Back / Next / Skip — composed entirely from registered render types (stack + text + image + button) into the overlay slot, so no new UI component is needed. autoShow opens it on INIT for first-time players; a board's help button re-opens it any time via SHOW (which rewinds to step one). DISMISS (or finishing the last step) marks the run done, clears the overlay, and emits TUTORIAL_DONE so the board can unpause or log. Steps are pure config — a board teaches a new mechanic by adding one { id, title, body, media } row."
2
+ "Tutorial modal with live-demo steps for game boards and learning shells: a paged overlay — title, a live previewTrait frame playing the mechanic via std-tutorial-autodemo (a bare game canvas, no shell chrome), one line of body copy, a step counter, and Back / Next / Skip — composed entirely from registered render types (stack + text + button + trait frame) into the overlay slot, so no new UI component is needed. autoShow opens it on INIT for first-time players; a board's help button re-opens it any time via SHOW (which rewinds to step one). DISMISS (or finishing the last step) marks the run done, clears the overlay, and emits TUTORIAL_DONE so the board can unpause or log. Steps are pure config — a board teaches a new mechanic by adding one { id, title, body, demoId } row plus a previewTrait binding."
3
3
  orbital TutorialOverlayOrbital {
4
4
  type TutorialStep = {
5
5
  id : string!
6
6
  title : string!
7
7
  body : string
8
- media : string
9
- mediaAlt : string
8
+ demoId : string
10
9
  }
11
10
 
12
11
  entity TutorialState [runtime, shared] {
@@ -15,6 +14,15 @@ orbital TutorialOverlayOrbital {
15
14
  done : boolean = false
16
15
  }
17
16
 
17
+ trait TutorialEmptyPreview -> TutorialState [interaction, instance] {
18
+ initial: idle
19
+
20
+ state idle {
21
+ INIT -> idle
22
+ (render-ui overlay null)
23
+ }
24
+ }
25
+
18
26
  trait TutorialOverlay -> @rebindable TutorialState [interaction, instance] {
19
27
  initial: hidden
20
28
 
@@ -32,7 +40,7 @@ orbital TutorialOverlayOrbital {
32
40
  className: "bg-card text-card-foreground border border-border rounded-lg shadow-lg p-6 max-w-md mx-auto mt-16"
33
41
  children: [
34
42
  { type: typography, content: (object/get (array/nth @config.steps 0) title), variant: "h4", weight: "bold" }
35
- { type: atlas-image, asset: { url: (object/get (array/nth @config.steps 0) media), name: (object/get (array/nth @config.steps 0) id), category: "tutorial" }, fit: "contain", alt: (object/get (array/nth @config.steps 0) mediaAlt), className: "rounded-md" }
43
+ @config.previewTrait
36
44
  { type: typography, content: (object/get (array/nth @config.steps 0) body), variant: "body" }
37
45
  { type: typography, content: (str/concat "1 / " (array/len @config.steps)), variant: "caption", align: "center" }
38
46
  { type: stack, direction: horizontal, justify: "center", className: "pt-2", children: [
@@ -41,6 +49,8 @@ orbital TutorialOverlayOrbital {
41
49
  ] }
42
50
  ]
43
51
  })
52
+ (when (!= (object/get (array/nth @config.steps 0) demoId "") "")
53
+ (do (emit TUTORIAL_DEMO_START { demoId: (object/get (array/nth @config.steps 0) demoId "") })))
44
54
 
45
55
  SHOW -> showing
46
56
  (set @entity.step 0)
@@ -50,7 +60,7 @@ orbital TutorialOverlayOrbital {
50
60
  className: "bg-card text-card-foreground border border-border rounded-lg shadow-lg p-6 max-w-md mx-auto mt-16"
51
61
  children: [
52
62
  { type: typography, content: (object/get (array/nth @config.steps 0) title), variant: "h4", weight: "bold" }
53
- { type: atlas-image, asset: { url: (object/get (array/nth @config.steps 0) media), name: (object/get (array/nth @config.steps 0) id), category: "tutorial" }, fit: "contain", alt: (object/get (array/nth @config.steps 0) mediaAlt), className: "rounded-md" }
63
+ @config.previewTrait
54
64
  { type: typography, content: (object/get (array/nth @config.steps 0) body), variant: "body" }
55
65
  { type: typography, content: (str/concat "1 / " (array/len @config.steps)), variant: "caption", align: "center" }
56
66
  { type: stack, direction: horizontal, justify: "center", className: "pt-2", children: [
@@ -59,6 +69,8 @@ orbital TutorialOverlayOrbital {
59
69
  ] }
60
70
  ]
61
71
  })
72
+ (when (!= (object/get (array/nth @config.steps 0) demoId "") "")
73
+ (do (emit TUTORIAL_DEMO_START { demoId: (object/get (array/nth @config.steps 0) demoId "") })))
62
74
  }
63
75
 
64
76
  state showing {
@@ -70,7 +82,7 @@ orbital TutorialOverlayOrbital {
70
82
  className: "bg-card text-card-foreground border border-border rounded-lg shadow-lg p-6 max-w-md mx-auto mt-16"
71
83
  children: [
72
84
  { type: typography, content: (object/get (array/nth @config.steps @entity.step) title), variant: "h4", weight: "bold" }
73
- { type: atlas-image, asset: { url: (object/get (array/nth @config.steps @entity.step) media), name: (object/get (array/nth @config.steps @entity.step) id), category: "tutorial" }, fit: "contain", alt: (object/get (array/nth @config.steps @entity.step) mediaAlt), className: "rounded-md" }
85
+ @config.previewTrait
74
86
  { type: typography, content: (object/get (array/nth @config.steps @entity.step) body), variant: "body" }
75
87
  { type: typography, content: (str/concat (+ @entity.step 1) " / " (array/len @config.steps)), variant: "caption", align: "center" }
76
88
  { type: stack, direction: horizontal, justify: "center", className: "pt-2", children: [
@@ -80,10 +92,14 @@ orbital TutorialOverlayOrbital {
80
92
  ] }
81
93
  ]
82
94
  })
95
+ (emit TUTORIAL_DEMO_STOP {})
96
+ (when (!= (object/get (array/nth @config.steps @entity.step) demoId "") "")
97
+ (do (emit TUTORIAL_DEMO_START { demoId: (object/get (array/nth @config.steps @entity.step) demoId "") })))
83
98
 
84
99
  TUT_NEXT -> hidden when (>= (+ @entity.step 1) (array/len @config.steps))
85
100
  (set @entity.done true)
86
101
  (render-ui overlay null)
102
+ (emit TUTORIAL_DEMO_STOP {})
87
103
  (emit TUTORIAL_DONE { id: "tutorial" })
88
104
 
89
105
  TUT_BACK -> showing when (> @entity.step 0)
@@ -94,7 +110,7 @@ orbital TutorialOverlayOrbital {
94
110
  className: "bg-card text-card-foreground border border-border rounded-lg shadow-lg p-6 max-w-md mx-auto mt-16"
95
111
  children: [
96
112
  { type: typography, content: (object/get (array/nth @config.steps @entity.step) title), variant: "h4", weight: "bold" }
97
- { type: atlas-image, asset: { url: (object/get (array/nth @config.steps @entity.step) media), name: (object/get (array/nth @config.steps @entity.step) id), category: "tutorial" }, fit: "contain", alt: (object/get (array/nth @config.steps @entity.step) mediaAlt), className: "rounded-md" }
113
+ @config.previewTrait
98
114
  { type: typography, content: (object/get (array/nth @config.steps @entity.step) body), variant: "body" }
99
115
  { type: typography, content: (str/concat (+ @entity.step 1) " / " (array/len @config.steps)), variant: "caption", align: "center" }
100
116
  { type: stack, direction: horizontal, justify: "center", className: "pt-2", children: [
@@ -104,10 +120,14 @@ orbital TutorialOverlayOrbital {
104
120
  ] }
105
121
  ]
106
122
  })
123
+ (emit TUTORIAL_DEMO_STOP {})
124
+ (when (!= (object/get (array/nth @config.steps @entity.step) demoId "") "")
125
+ (do (emit TUTORIAL_DEMO_START { demoId: (object/get (array/nth @config.steps @entity.step) demoId "") })))
107
126
 
108
127
  TUT_DISMISS -> hidden
109
128
  (set @entity.done true)
110
129
  (render-ui overlay null)
130
+ (emit TUTORIAL_DEMO_STOP {})
111
131
  (emit TUTORIAL_DONE { id: "tutorial" })
112
132
  }
113
133
 
@@ -142,6 +162,15 @@ orbital TutorialOverlayOrbital {
142
162
  }
143
163
  @description "The tutorial was finished or skipped; boards unpause or log completion."
144
164
  @tier "domain"
165
+ TUTORIAL_DEMO_START -> external {
166
+ demoId : string!
167
+ }
168
+ @description "Emitted when a tutorial step carrying a demoId is shown; the composed std-tutorial-autodemo atom plays that scripted demo."
169
+ @tier "domain"
170
+ TUTORIAL_DEMO_STOP -> external {
171
+ }
172
+ @description "Emitted when the tutorial leaves a demo step (next/back) or is dismissed/finished; the autodemo atom stops and releases control."
173
+ @tier "domain"
145
174
  }
146
175
 
147
176
  listens {
@@ -151,7 +180,11 @@ orbital TutorialOverlayOrbital {
151
180
  config {
152
181
  steps : [TutorialStep] = []
153
182
  @label "Steps"
154
- @description "One row per tutorial page: title, one line of body copy, and media — the URL of an animated GIF/clip showing exactly how the mechanic is performed (recorded from real gameplay)."
183
+ @description "One row per tutorial page: title, one line of body copy, and an optional demoId that plays a scripted live demo (std-tutorial-autodemo) for the mechanic being taught."
184
+ @tier "presentation"
185
+ previewTrait : trait = @trait.TutorialEmptyPreview
186
+ @label "Preview trait"
187
+ @description "Trait rendered in the media position of the modal — the live, demo-driven preview of the mechanic (a bare game canvas, no shell chrome). '@trait.TutorialEmptyPreview' leaves the slot blank. Override with '@trait.<TraitName>' to show a board's live frame."
155
188
  @tier "presentation"
156
189
  autoShow : boolean = true
157
190
  @label "Auto Show"
@@ -307,15 +307,15 @@ orbital MathCanvasOrbital {
307
307
  @tier "presentation"
308
308
  backgroundColor : string
309
309
  @label "Background Color"
310
- @description "Canvas fill color; accepts theme-token refs like var(--color-background, transparent) — resolved against the active theme at draw time. Default transparent."
310
+ @description "Canvas fill color; `var(--token, fallback)` strings resolve against the active theme. Default transparent."
311
311
  @tier "presentation"
312
312
  gridColor : string = "var(--color-border, #9ca3af)"
313
313
  @label "Grid Color"
314
- @description "Grid line color; theme-token aware (defaults to the active theme's border color at 35% opacity, falling back to neutral gray)."
314
+ @description "Grid line color; resolves theme tokens (default `var(--color-border, #9ca3af)`)."
315
315
  @tier "presentation"
316
316
  axisColor : string = "var(--color-muted-foreground, #374151)"
317
317
  @label "Axis Color"
318
- @description "Axis line color; theme-token aware (defaults to the active theme's muted-foreground, falling back to slate)."
318
+ @description "Axis line color; resolves theme tokens (default `var(--color-muted-foreground, #374151)`)."
319
319
  @tier "presentation"
320
320
  showTickLabels : boolean = false
321
321
  @label "Show Tick Labels"
@@ -945,6 +945,17 @@
945
945
  "tier": "internal",
946
946
  "type": "string"
947
947
  },
948
+ "include": {
949
+ "default": [],
950
+ "description": "Entity relation field names to hydrate on fetch (e.g. a `tag : Category` field named `tag`), so grid columns can use dot-paths like tag.name. Empty = no hydration, the default.",
951
+ "items": {
952
+ "type": "string"
953
+ },
954
+ "label": "Which relation fields to hydrate?",
955
+ "synonyms": "relation hydration, populate relations, joined fields, hydrate relations",
956
+ "tier": "internal",
957
+ "type": "[string]"
958
+ },
948
959
  "initialFilterField": {
949
960
  "default": "",
950
961
  "description": "Name the field the INITIAL load filters on, paired with initialFilterValue. This is the detail half of a list-detail pair: a thread that must wait for a conversation to be picked sets the field to its parent key and leaves the value blank, so the first load matches nothing and the empty state shows instead of every record in the table. REFETCH_FILTER then supplies the real selection. Left blank the first load is unfiltered, which is the default.",
@@ -1727,6 +1738,7 @@
1727
1738
  ]
1728
1739
  ]
1729
1740
  ],
1741
+ "include": "@config.include",
1730
1742
  "limit": "@config.pageSize",
1731
1743
  "offset": 0.0
1732
1744
  }
@@ -1888,6 +1900,7 @@
1888
1900
  ]
1889
1901
  ]
1890
1902
  ],
1903
+ "include": "@config.include",
1891
1904
  "limit": "@config.pageSize",
1892
1905
  "offset": 0.0
1893
1906
  }
@@ -1945,6 +1958,7 @@
1945
1958
  ]
1946
1959
  ]
1947
1960
  ],
1961
+ "include": "@config.include",
1948
1962
  "limit": "@config.pageSize",
1949
1963
  "offset": 0.0
1950
1964
  }
@@ -2002,6 +2016,7 @@
2002
2016
  ]
2003
2017
  ]
2004
2018
  ],
2019
+ "include": "@config.include",
2005
2020
  "limit": "@config.pageSize",
2006
2021
  "offset": 0.0
2007
2022
  }
@@ -2039,6 +2054,7 @@
2039
2054
  "@user.id"
2040
2055
  ]
2041
2056
  ],
2057
+ "include": "@config.include",
2042
2058
  "limit": "@config.pageSize",
2043
2059
  "offset": [
2044
2060
  "*",
@@ -2218,6 +2234,7 @@
2218
2234
  ]
2219
2235
  ]
2220
2236
  ],
2237
+ "include": "@config.include",
2221
2238
  "limit": "@config.pageSize",
2222
2239
  "offset": 0.0
2223
2240
  }