@almadar/std 16.188.0 → 16.189.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.
- package/behaviors/lolo/ui/core/.hand-authored.json +0 -4
- package/behaviors/lolo/ui/core/atoms/std-calendar.lolo +20 -8
- package/behaviors/lolo/ui/core/atoms/std-record-detail.lolo +428 -26
- package/behaviors/lolo/ui/core/atoms/std-related.lolo +5 -1
- package/behaviors/lolo/ui/core/atoms/std-version-history.lolo +1 -1
- package/behaviors/lolo/ui/core/molecules/ui-document-details.lolo +80 -0
- package/behaviors/lolo/ui/core/molecules/ui-document-panel.lolo +213 -0
- package/behaviors/lolo/ui/core/molecules/{ui-rich-block-editor.lolo → ui-rich-text-editor.lolo} +25 -25
- package/behaviors/lolo/ui/game/atoms/std-choice-gate.lolo +100 -0
- package/behaviors/lolo/ui/game/atoms/std-coef-pad.lolo +114 -0
- package/behaviors/lolo/ui/game/atoms/std-curve-fog.lolo +50 -0
- package/behaviors/lolo/ui/game/atoms/std-pad-lock.lolo +5 -1
- package/behaviors/lolo/ui/game/atoms/std-platformer-body.lolo +29 -3
- package/behaviors/lolo/ui/game/atoms/std-zone-card.lolo +95 -0
- package/behaviors/lolo/ui/game/organisms/std-platformer-board-2d.lolo +9 -0
- package/behaviors/registry/ui/core/atoms/std-calendar.orb +51 -27
- package/behaviors/registry/ui/core/atoms/std-record-detail.orb +2399 -180
- package/behaviors/registry/ui/core/atoms/std-related.orb +23 -1
- package/behaviors/registry/ui/core/atoms/std-version-history.orb +1 -1
- package/behaviors/registry/ui/core/molecules/ui-document-details.orb +342 -0
- package/behaviors/registry/ui/core/molecules/ui-document-panel.orb +655 -0
- package/behaviors/registry/ui/core/molecules/{ui-rich-block-editor.orb → ui-rich-text-editor.orb} +84 -97
- package/behaviors/registry/ui/game/atoms/std-choice-gate.orb +855 -0
- package/behaviors/registry/ui/game/atoms/std-coef-pad.orb +928 -0
- package/behaviors/registry/ui/game/atoms/std-curve-fog.orb +337 -0
- package/behaviors/registry/ui/game/atoms/std-pad-lock.orb +31 -1
- package/behaviors/registry/ui/game/atoms/std-platformer-body.orb +847 -401
- package/behaviors/registry/ui/game/atoms/std-zone-card.orb +642 -0
- package/behaviors/registry/ui/game/organisms/std-platformer-board-2d.orb +38 -6
- package/dist/behaviors/exports-reader.js +6491 -6163
- package/dist/behaviors/functions/index.d.ts +669 -300
- package/dist/behaviors/functions/index.js +6469 -6152
- package/dist/behaviors/index.d.ts +1 -1
- package/dist/behaviors/index.js +6492 -6164
- package/dist/behaviors/query.js +6491 -6163
- package/dist/behaviors-embeddings.hash.json +3 -3
- package/dist/behaviors-embeddings.json +367 -375
- package/dist/behaviors-registry.json +4104 -2597
- package/dist/index.d.ts +1 -1
- package/dist/index.js +6492 -6164
- package/dist/knob-embeddings.hash.json +3 -3
- package/dist/knob-embeddings.json +1 -1
- package/dist/registry/factory-signatures.json +1 -1
- package/package.json +4 -4
- package/behaviors/lolo/ui/core/atoms/std-rich-editor.lolo +0 -790
- package/behaviors/registry/ui/core/atoms/std-rich-editor.orb +0 -2225
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
app ui-document-details "1.0.0"
|
|
2
|
+
"DocumentDetails — the document's metadata as a compact settings card for the rail beside a DocumentPanel, each property committing in place. — UI factory (1:1 with the @almadar/ui document-details pattern)."
|
|
3
|
+
;; @capabilities "document settings, page details, post settings sidebar, metadata panel, document properties, publish settings"
|
|
4
|
+
orbital DocumentDetailsOrbital {
|
|
5
|
+
type DocumentDetailsLoaded = Event { data : [DocumentDetailsItem] } "DocumentDetails rows finished loading; payload.data holds the collection"
|
|
6
|
+
type DocumentDetailsFieldsItem = {
|
|
7
|
+
name : string
|
|
8
|
+
key : string
|
|
9
|
+
label : string
|
|
10
|
+
header : string
|
|
11
|
+
icon : icon
|
|
12
|
+
kind : "text" | "boolean" | "select" | "readonly"
|
|
13
|
+
options : [string]
|
|
14
|
+
format : "date" | "currency" | "number" | "boolean" | "percent"
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
entity DocumentDetailsItem [runtime] {
|
|
18
|
+
id : string!
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
trait DocumentDetailsRender -> @rebindable DocumentDetailsItem [interaction, instance] {
|
|
22
|
+
initial: idle
|
|
23
|
+
|
|
24
|
+
state idle {
|
|
25
|
+
INIT -> idle
|
|
26
|
+
(fetch DocumentDetailsItem { emit: { success: DocumentDetailsLoaded } })
|
|
27
|
+
(render-ui main {
|
|
28
|
+
entity: @entity
|
|
29
|
+
fields: @config.fields
|
|
30
|
+
metaCommitEvent: @config.metaCommitEvent
|
|
31
|
+
title: @config.title
|
|
32
|
+
className: @config.className
|
|
33
|
+
type: document-details
|
|
34
|
+
})
|
|
35
|
+
DocumentDetailsLoaded -> idle
|
|
36
|
+
(render-ui main {
|
|
37
|
+
entity: @payload.data
|
|
38
|
+
fields: @config.fields
|
|
39
|
+
metaCommitEvent: @config.metaCommitEvent
|
|
40
|
+
title: @config.title
|
|
41
|
+
className: @config.className
|
|
42
|
+
type: document-details
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
emits {
|
|
47
|
+
@config.metaCommitEvent -> external {
|
|
48
|
+
id : string!
|
|
49
|
+
patch : object!
|
|
50
|
+
}
|
|
51
|
+
@description "Emitted when a property commits: { id, patch } — patch carries the id plus the one changed field, ready for a partial persist update."
|
|
52
|
+
@tier "essential"
|
|
53
|
+
DocumentDetailsLoaded
|
|
54
|
+
@description "DocumentDetails rows finished loading; payload.data holds the collection."
|
|
55
|
+
@synonyms "loaded, fetched, retrieved"
|
|
56
|
+
@tier "essential"
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
config {
|
|
60
|
+
fields : [DocumentDetailsFieldsItem] = []
|
|
61
|
+
@label "Fields"
|
|
62
|
+
@description "The properties shown; empty renders nothing."
|
|
63
|
+
@tier "presentation"
|
|
64
|
+
metaCommitEvent : string = "META_COMMIT"
|
|
65
|
+
@label "Meta Commit Event"
|
|
66
|
+
@description "Emitted when a property commits: { id, patch } — patch carries the id plus the one changed field, ready for a partial persist update."
|
|
67
|
+
@tier "presentation"
|
|
68
|
+
title : string
|
|
69
|
+
@label "Title"
|
|
70
|
+
@description "Card heading (defaults to the localized 'Details')"
|
|
71
|
+
@tier "presentation"
|
|
72
|
+
className : string
|
|
73
|
+
@label "Class Name"
|
|
74
|
+
@description "className prop"
|
|
75
|
+
@tier "presentation"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
page "/document-details" as DocumentDetailsPage -> DocumentDetailsRender
|
|
80
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
app ui-document-panel "1.0.0"
|
|
2
|
+
"DocumentPanel — a record rendered as one continuous document: editable title over the rich-text body, editing controls tucked into the header corner. — UI factory (1:1 with the @almadar/ui document-panel pattern)."
|
|
3
|
+
;; @capabilities "document page, note editor, wiki page, article editor, writing surface, rich text document, content editing canvas"
|
|
4
|
+
orbital DocumentPanelOrbital {
|
|
5
|
+
type DocumentPanelLoaded = Event { data : [DocumentPanelItem] } "DocumentPanel rows finished loading; payload.data holds the collection"
|
|
6
|
+
type DocumentPanelActionsItem = {
|
|
7
|
+
label : string!
|
|
8
|
+
event : string
|
|
9
|
+
icon : icon
|
|
10
|
+
variant : "primary" | "secondary" | "ghost" | "danger"
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
entity DocumentPanelItem [runtime] {
|
|
14
|
+
id : string!
|
|
15
|
+
title : string
|
|
16
|
+
value : string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
trait DocumentPanelRender -> @rebindable DocumentPanelItem [interaction, instance] {
|
|
20
|
+
initial: idle
|
|
21
|
+
|
|
22
|
+
state idle {
|
|
23
|
+
INIT -> idle
|
|
24
|
+
(fetch DocumentPanelItem { emit: { success: DocumentPanelLoaded } })
|
|
25
|
+
(set @entity.title @config.title)
|
|
26
|
+
(set @entity.value @config.value)
|
|
27
|
+
(render-ui main {
|
|
28
|
+
entity: @entity
|
|
29
|
+
title: @entity.title
|
|
30
|
+
subtitle: @config.subtitle
|
|
31
|
+
value: @entity.value
|
|
32
|
+
actions: @config.actions
|
|
33
|
+
maxInlineActions: @config.maxInlineActions
|
|
34
|
+
editing: @config.editing
|
|
35
|
+
titleCommitEvent: @config.titleCommitEvent
|
|
36
|
+
contentChangeEvent: @config.contentChangeEvent
|
|
37
|
+
editEvent: @config.editEvent
|
|
38
|
+
doneEvent: @config.doneEvent
|
|
39
|
+
editLabel: @config.editLabel
|
|
40
|
+
doneLabel: @config.doneLabel
|
|
41
|
+
autosaveHint: @config.autosaveHint
|
|
42
|
+
placeholder: @config.placeholder
|
|
43
|
+
className: @config.className
|
|
44
|
+
type: document-panel
|
|
45
|
+
})
|
|
46
|
+
DocumentPanelLoaded -> idle
|
|
47
|
+
(render-ui main {
|
|
48
|
+
entity: @payload.data
|
|
49
|
+
title: @entity.title
|
|
50
|
+
subtitle: @config.subtitle
|
|
51
|
+
value: @entity.value
|
|
52
|
+
actions: @config.actions
|
|
53
|
+
maxInlineActions: @config.maxInlineActions
|
|
54
|
+
editing: @config.editing
|
|
55
|
+
titleCommitEvent: @config.titleCommitEvent
|
|
56
|
+
contentChangeEvent: @config.contentChangeEvent
|
|
57
|
+
editEvent: @config.editEvent
|
|
58
|
+
doneEvent: @config.doneEvent
|
|
59
|
+
editLabel: @config.editLabel
|
|
60
|
+
doneLabel: @config.doneLabel
|
|
61
|
+
autosaveHint: @config.autosaveHint
|
|
62
|
+
placeholder: @config.placeholder
|
|
63
|
+
className: @config.className
|
|
64
|
+
type: document-panel
|
|
65
|
+
})
|
|
66
|
+
TITLE_COMMIT -> idle
|
|
67
|
+
(set @entity.title ?title)
|
|
68
|
+
(render-ui main {
|
|
69
|
+
entity: @entity
|
|
70
|
+
title: @entity.title
|
|
71
|
+
subtitle: @config.subtitle
|
|
72
|
+
value: @entity.value
|
|
73
|
+
actions: @config.actions
|
|
74
|
+
maxInlineActions: @config.maxInlineActions
|
|
75
|
+
editing: @config.editing
|
|
76
|
+
titleCommitEvent: @config.titleCommitEvent
|
|
77
|
+
contentChangeEvent: @config.contentChangeEvent
|
|
78
|
+
editEvent: @config.editEvent
|
|
79
|
+
doneEvent: @config.doneEvent
|
|
80
|
+
editLabel: @config.editLabel
|
|
81
|
+
doneLabel: @config.doneLabel
|
|
82
|
+
autosaveHint: @config.autosaveHint
|
|
83
|
+
placeholder: @config.placeholder
|
|
84
|
+
className: @config.className
|
|
85
|
+
type: document-panel
|
|
86
|
+
})
|
|
87
|
+
CONTENT_CHANGE -> idle
|
|
88
|
+
(set @entity.value ?value)
|
|
89
|
+
(render-ui main {
|
|
90
|
+
entity: @entity
|
|
91
|
+
title: @entity.title
|
|
92
|
+
subtitle: @config.subtitle
|
|
93
|
+
value: @entity.value
|
|
94
|
+
actions: @config.actions
|
|
95
|
+
maxInlineActions: @config.maxInlineActions
|
|
96
|
+
editing: @config.editing
|
|
97
|
+
titleCommitEvent: @config.titleCommitEvent
|
|
98
|
+
contentChangeEvent: @config.contentChangeEvent
|
|
99
|
+
editEvent: @config.editEvent
|
|
100
|
+
doneEvent: @config.doneEvent
|
|
101
|
+
editLabel: @config.editLabel
|
|
102
|
+
doneLabel: @config.doneLabel
|
|
103
|
+
autosaveHint: @config.autosaveHint
|
|
104
|
+
placeholder: @config.placeholder
|
|
105
|
+
className: @config.className
|
|
106
|
+
type: document-panel
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
emits {
|
|
111
|
+
@config.titleCommitEvent -> external {
|
|
112
|
+
title : string!
|
|
113
|
+
id : string!
|
|
114
|
+
}
|
|
115
|
+
@description "Emitted when the title commits: { title, id }"
|
|
116
|
+
@tier "essential"
|
|
117
|
+
@config.contentChangeEvent -> external {
|
|
118
|
+
value : string!
|
|
119
|
+
}
|
|
120
|
+
@description "Forwarded to the embedded RichTextEditor's autosave stream: { value }"
|
|
121
|
+
@tier "essential"
|
|
122
|
+
@config.editEvent -> external {
|
|
123
|
+
id : string!
|
|
124
|
+
}
|
|
125
|
+
@description "Emitted by the header Edit affordance and a click on the read body: { id }"
|
|
126
|
+
@tier "essential"
|
|
127
|
+
@config.doneEvent -> external {
|
|
128
|
+
id : string!
|
|
129
|
+
}
|
|
130
|
+
@description "Emitted by the Done button that ends the editing session: { id }"
|
|
131
|
+
@tier "essential"
|
|
132
|
+
DocumentPanelLoaded
|
|
133
|
+
@description "DocumentPanel rows finished loading; payload.data holds the collection."
|
|
134
|
+
@synonyms "loaded, fetched, retrieved"
|
|
135
|
+
@tier "essential"
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
listens {
|
|
139
|
+
TITLE_COMMIT {
|
|
140
|
+
title : string!
|
|
141
|
+
id : string!
|
|
142
|
+
}
|
|
143
|
+
CONTENT_CHANGE {
|
|
144
|
+
value : string!
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
config {
|
|
149
|
+
title : string
|
|
150
|
+
@label "Title"
|
|
151
|
+
@description "Document title (falls back to 'Untitled' for a blank draft)"
|
|
152
|
+
@tier "presentation"
|
|
153
|
+
subtitle : string
|
|
154
|
+
@label "Subtitle"
|
|
155
|
+
@description "Muted byline under the title; hidden when empty"
|
|
156
|
+
@tier "presentation"
|
|
157
|
+
value : string
|
|
158
|
+
@label "Value"
|
|
159
|
+
@description "The document body as rich-text HTML"
|
|
160
|
+
@tier "presentation"
|
|
161
|
+
actions : [DocumentPanelActionsItem] = []
|
|
162
|
+
@label "Actions"
|
|
163
|
+
@description "Header actions (settings, history, …). At most one explicit primary stays inline; the rest live under a single '⋯' menu — the title owns its row."
|
|
164
|
+
@tier "presentation"
|
|
165
|
+
maxInlineActions : number
|
|
166
|
+
@label "Max Inline Actions"
|
|
167
|
+
@description "0 collapses even the primary action into the menu"
|
|
168
|
+
@tier "presentation"
|
|
169
|
+
editing : boolean = false
|
|
170
|
+
@label "Editing"
|
|
171
|
+
@description "false = read surface with click-to-edit body; true = live editor"
|
|
172
|
+
@tier "presentation"
|
|
173
|
+
titleCommitEvent : string = "TITLE_COMMIT"
|
|
174
|
+
@label "Title Commit Event"
|
|
175
|
+
@description "Emitted when the title commits: { title, id }"
|
|
176
|
+
@tier "presentation"
|
|
177
|
+
contentChangeEvent : string = "CONTENT_CHANGE"
|
|
178
|
+
@label "Content Change Event"
|
|
179
|
+
@description "Forwarded to the embedded RichTextEditor's autosave stream: { value }"
|
|
180
|
+
@tier "presentation"
|
|
181
|
+
editEvent : string = "EDIT"
|
|
182
|
+
@label "Edit Event"
|
|
183
|
+
@description "Emitted by the header Edit affordance and a click on the read body: { id }"
|
|
184
|
+
@tier "presentation"
|
|
185
|
+
doneEvent : string = "DONE"
|
|
186
|
+
@label "Done Event"
|
|
187
|
+
@description "Emitted by the Done button that ends the editing session: { id }"
|
|
188
|
+
@tier "presentation"
|
|
189
|
+
editLabel : string
|
|
190
|
+
@label "Edit Label"
|
|
191
|
+
@description "editLabel prop"
|
|
192
|
+
@tier "presentation"
|
|
193
|
+
doneLabel : string
|
|
194
|
+
@label "Done Label"
|
|
195
|
+
@description "doneLabel prop"
|
|
196
|
+
@tier "presentation"
|
|
197
|
+
autosaveHint : string
|
|
198
|
+
@label "Autosave Hint"
|
|
199
|
+
@description "Muted caption beside Done telling the author work persists on its own"
|
|
200
|
+
@tier "presentation"
|
|
201
|
+
placeholder : string
|
|
202
|
+
@label "Placeholder"
|
|
203
|
+
@description "Placeholder for an empty body"
|
|
204
|
+
@tier "presentation"
|
|
205
|
+
className : string
|
|
206
|
+
@label "Class Name"
|
|
207
|
+
@description "className prop"
|
|
208
|
+
@tier "presentation"
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
page "/document-panel" as DocumentPanelPage -> DocumentPanelRender
|
|
213
|
+
}
|
package/behaviors/lolo/ui/core/molecules/{ui-rich-block-editor.lolo → ui-rich-text-editor.lolo}
RENAMED
|
@@ -1,56 +1,60 @@
|
|
|
1
|
-
app ui-rich-
|
|
2
|
-
"
|
|
3
|
-
orbital
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
entity RichBlockEditorItem [runtime] {
|
|
1
|
+
app ui-rich-text-editor "1.0.0"
|
|
2
|
+
"RichTextEditor — UI factory (1:1 with the @almadar/ui rich-text-editor pattern)."
|
|
3
|
+
orbital RichTextEditorOrbital {
|
|
4
|
+
entity RichTextEditorItem [runtime] {
|
|
7
5
|
id : string!
|
|
6
|
+
value : string
|
|
8
7
|
}
|
|
9
8
|
|
|
10
|
-
trait
|
|
9
|
+
trait RichTextEditorRender -> @rebindable RichTextEditorItem [interaction, instance] {
|
|
11
10
|
initial: idle
|
|
12
11
|
|
|
13
12
|
state idle {
|
|
14
13
|
INIT -> idle
|
|
15
|
-
(
|
|
14
|
+
(set @entity.value @config.value)
|
|
16
15
|
(render-ui main {
|
|
17
|
-
|
|
16
|
+
value: @entity.value
|
|
18
17
|
onChange: @config.onChange
|
|
19
18
|
changeEvent: @config.changeEvent
|
|
20
19
|
readOnly: @config.readOnly
|
|
21
20
|
placeholder: @config.placeholder
|
|
22
|
-
enableBlocks: @config.enableBlocks
|
|
23
21
|
showToolbar: @config.showToolbar
|
|
24
22
|
className: @config.className
|
|
25
|
-
type: rich-
|
|
23
|
+
type: rich-text-editor
|
|
26
24
|
})
|
|
27
|
-
|
|
25
|
+
CHANGE -> idle
|
|
26
|
+
(set @entity.value ?value)
|
|
28
27
|
(render-ui main {
|
|
29
|
-
|
|
28
|
+
value: @entity.value
|
|
30
29
|
onChange: @config.onChange
|
|
31
30
|
changeEvent: @config.changeEvent
|
|
32
31
|
readOnly: @config.readOnly
|
|
33
32
|
placeholder: @config.placeholder
|
|
34
|
-
enableBlocks: @config.enableBlocks
|
|
35
33
|
showToolbar: @config.showToolbar
|
|
36
34
|
className: @config.className
|
|
37
|
-
type: rich-
|
|
35
|
+
type: rich-text-editor
|
|
38
36
|
})
|
|
39
37
|
}
|
|
40
38
|
|
|
41
39
|
emits {
|
|
42
40
|
@config.onChange -> external {
|
|
43
|
-
|
|
41
|
+
value : string
|
|
44
42
|
}
|
|
45
43
|
@description "onChange prop"
|
|
46
44
|
@tier "essential"
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
listens {
|
|
48
|
+
CHANGE {
|
|
49
|
+
value : string
|
|
50
|
+
}
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
config {
|
|
54
|
+
value : string
|
|
55
|
+
@label "Value"
|
|
56
|
+
@description "The rich text content as HTML. Sanitized before rendering and on every change."
|
|
57
|
+
@tier "presentation"
|
|
54
58
|
onChange : string = "CHANGE"
|
|
55
59
|
@label "On Change"
|
|
56
60
|
@description "onChange prop"
|
|
@@ -67,10 +71,6 @@ orbital RichBlockEditorOrbital {
|
|
|
67
71
|
@label "Placeholder"
|
|
68
72
|
@description "placeholder prop"
|
|
69
73
|
@tier "presentation"
|
|
70
|
-
enableBlocks : boolean = true
|
|
71
|
-
@label "Enable Blocks"
|
|
72
|
-
@description "Opt-in to the Notion-style block authoring chrome (insert toolbar, per-row +/menu gutter, turn-into menu). Off by default: the editor renders as a plain rich text surface that edits block content inline without any add-block affordances."
|
|
73
|
-
@tier "presentation"
|
|
74
74
|
showToolbar : boolean = true
|
|
75
75
|
@label "Show Toolbar"
|
|
76
76
|
@description "showToolbar prop"
|
|
@@ -82,5 +82,5 @@ orbital RichBlockEditorOrbital {
|
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
page "/rich-
|
|
85
|
+
page "/rich-text-editor" as RichTextEditorPage -> RichTextEditorRender
|
|
86
86
|
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
app std-choice-gate "1.0.0"
|
|
2
|
+
"Headless choice-gate mechanic for side-view boards: a gate of N labeled option platforms where progress stops until the player commits to an answer. Listens BODY_MOVED and judges a gate when the player stands grounded on one of its option platforms (|dx| <= reachX of the option center, |dy| <= reachY of the gate's option plane — the pad-lock touch pattern): the correct option stamps the gate solved + chosen on the shared entity and emits CHOICE_CORRECT once (a solved gate never judges again, so the path stays open); a wrong option emits CHOICE_WRONG carrying the gate id, the chosen optionId, and the option's world position, so the board can bounce the player back and float the gate's hint (the board owns the bounce — the atom only reports). RESTART unsolves every gate. Renders nothing; boards draw the option platforms and labels from the shared entity (the render authority)."
|
|
3
|
+
orbital ChoiceGateOrbital {
|
|
4
|
+
type ChoiceOption = {
|
|
5
|
+
id : string!
|
|
6
|
+
dx : number!
|
|
7
|
+
label : string!
|
|
8
|
+
correct : boolean!
|
|
9
|
+
}
|
|
10
|
+
type ChoiceGate = {
|
|
11
|
+
id : string!
|
|
12
|
+
x : number!
|
|
13
|
+
y : number!
|
|
14
|
+
hint : string
|
|
15
|
+
options : [ChoiceOption]!
|
|
16
|
+
solved : boolean
|
|
17
|
+
chosen : string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
entity ChoiceGateData [runtime, shared] {
|
|
21
|
+
id : string!
|
|
22
|
+
choices : [ChoiceGate] = []
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
trait ChoiceGate -> @rebindable ChoiceGateData [lifecycle] {
|
|
26
|
+
initial: active
|
|
27
|
+
|
|
28
|
+
state active {
|
|
29
|
+
INIT -> active
|
|
30
|
+
(set @entity.choices (array/map @config.gates (fn g (object/merge @g { solved: false, chosen: "" }))))
|
|
31
|
+
|
|
32
|
+
BODY_MOVED -> active when @config.running
|
|
33
|
+
(let ((touch (array/filter @entity.choices (fn g
|
|
34
|
+
(and (== (object/get @g solved) false)
|
|
35
|
+
(> (array/len (array/filter (object/get @g options) (fn o
|
|
36
|
+
(and (== @payload.grounded true)
|
|
37
|
+
(and (<= (math/abs (- @payload.x (+ (object/get @g x) (object/get @o dx)))) @config.reachX)
|
|
38
|
+
(<= (math/abs (- @payload.y (object/get @g y))) @config.reachY)))))) 0))))))
|
|
39
|
+
(if (> (array/len @touch) 0)
|
|
40
|
+
(let ((g (array/first @touch)))
|
|
41
|
+
(let ((o (array/first (array/filter (object/get @g options) (fn oo
|
|
42
|
+
(and (== @payload.grounded true)
|
|
43
|
+
(and (<= (math/abs (- @payload.x (+ (object/get @g x) (object/get @oo dx)))) @config.reachX)
|
|
44
|
+
(<= (math/abs (- @payload.y (object/get @g y))) @config.reachY))))))))
|
|
45
|
+
(if (== (object/get @o correct) true)
|
|
46
|
+
(do
|
|
47
|
+
(set @entity.choices (array/map @entity.choices (fn c (if (== (object/get @c id) (object/get @g id)) (object/merge @c { solved: true, chosen: (object/get @o id) }) @c))))
|
|
48
|
+
(emit CHOICE_CORRECT { id: (object/get @g id), x: (object/get @g x), y: (object/get @g y) }))
|
|
49
|
+
(emit CHOICE_WRONG { id: (object/get @g id), optionId: (object/get @o id), x: (+ (object/get @g x) (object/get @o dx)), y: (object/get @g y) }))))
|
|
50
|
+
null))
|
|
51
|
+
|
|
52
|
+
RESTART -> active
|
|
53
|
+
(set @entity.choices (array/map @config.gates (fn g (object/merge @g { solved: false, chosen: "" }))))
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
emits {
|
|
57
|
+
CHOICE_CORRECT -> external {
|
|
58
|
+
id : string!
|
|
59
|
+
x : number!
|
|
60
|
+
y : number!
|
|
61
|
+
}
|
|
62
|
+
@description "The player landed grounded on the gate's correct option; fires once per gate (solved gates stop judging). Carries the gate center so boards can burst the unlock there."
|
|
63
|
+
@tier "domain"
|
|
64
|
+
CHOICE_WRONG -> external {
|
|
65
|
+
id : string!
|
|
66
|
+
optionId : string!
|
|
67
|
+
x : number!
|
|
68
|
+
y : number!
|
|
69
|
+
}
|
|
70
|
+
@description "The player landed grounded on a wrong option; carries the gate id, the chosen optionId, and the option's world position so boards can bounce the player back to the approach and float the gate's hint."
|
|
71
|
+
@tier "domain"
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
listens {
|
|
75
|
+
BODY_MOVED { x : number!, y : number!, vx : number!, vy : number!, grounded : boolean!, skating : boolean!, speed : number! }
|
|
76
|
+
RESTART { id : string }
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
config {
|
|
80
|
+
running : boolean = true
|
|
81
|
+
@label "Running"
|
|
82
|
+
@description "When true, BODY_MOVED judges option landings; toggle to freeze every gate as-is."
|
|
83
|
+
@tier "domain"
|
|
84
|
+
gates : [ChoiceGate] = []
|
|
85
|
+
@label "Choice Gates"
|
|
86
|
+
@description "One row per gate: id, gate center (x, y — y is the option-platform surface the judge tests against), the hint floated on a wrong answer, and the options: id, dx offset from the gate center, the label drawn above the platform, and correct. solved/chosen are stamped at runtime."
|
|
87
|
+
@tier "domain"
|
|
88
|
+
reachX : number = 0.7
|
|
89
|
+
@label "Reach X"
|
|
90
|
+
@description "Horizontal tolerance (world units) around an option platform's center when testing a landing (approximates the body's half-width plus a step)."
|
|
91
|
+
@tier "domain"
|
|
92
|
+
reachY : number = 1.2
|
|
93
|
+
@label "Reach Y"
|
|
94
|
+
@description "Vertical tolerance (world units) around the gate's option plane when testing a landing (covers small hops onto the platform surface)."
|
|
95
|
+
@tier "domain"
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
page "/choice-gate" as ChoiceGatePage -> ChoiceGate
|
|
100
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
app std-coef-pad "1.0.0"
|
|
2
|
+
"Headless coefficient-pad mechanic for graph-riding boards: floor pads that reshape the road the player is riding (y = a·f(x−h) + k). Listens BODY_MOVED and, when the player stands grounded on an unapplied pad (|dx| <= reachX, |dy| <= reachY of the pad center — the pad-lock touch pattern), stamps the pad applied on the shared entity and emits COEF_PAD_APPLIED carrying the pad position AND its mod (x0, x1, a, h, k), so the board can append the mod to the body authority's curveMods (std-platformer-body with curveModsEnabled) and hop the player onto the reshaped surface. When every pad is applied it emits COEF_PAD_SET_COMPLETED once. RESTART un-applies every pad (the board clears curveMods alongside — the pad reports, the board owns the road). Renders nothing; boards draw the pads and read applied from the shared entity (the render authority)."
|
|
3
|
+
orbital CoefPadOrbital {
|
|
4
|
+
type CoefMod = {
|
|
5
|
+
x0 : number!
|
|
6
|
+
x1 : number!
|
|
7
|
+
a : number!
|
|
8
|
+
h : number!
|
|
9
|
+
k : number!
|
|
10
|
+
}
|
|
11
|
+
type CoefModSample = {
|
|
12
|
+
x : number!
|
|
13
|
+
y : number!
|
|
14
|
+
}
|
|
15
|
+
type CoefPad = {
|
|
16
|
+
id : string!
|
|
17
|
+
x : number!
|
|
18
|
+
y : number!
|
|
19
|
+
mod : CoefMod!
|
|
20
|
+
glyph : string
|
|
21
|
+
hint : string
|
|
22
|
+
hop : boolean
|
|
23
|
+
samples : [CoefModSample]
|
|
24
|
+
applied : boolean
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
entity CoefPadData [runtime, shared] {
|
|
28
|
+
id : string!
|
|
29
|
+
coefPads : [CoefPad] = []
|
|
30
|
+
coefCompleted : boolean = false
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
trait CoefPadLock -> @rebindable CoefPadData [lifecycle] {
|
|
34
|
+
initial: active
|
|
35
|
+
|
|
36
|
+
state active {
|
|
37
|
+
INIT -> active
|
|
38
|
+
(set @entity.coefPads (array/map @config.coefPads (fn p (object/merge @p { applied: false }))))
|
|
39
|
+
(set @entity.coefCompleted false)
|
|
40
|
+
|
|
41
|
+
BODY_MOVED -> active when @config.running
|
|
42
|
+
(let ((touch (array/filter @entity.coefPads (fn p
|
|
43
|
+
(and (== (object/get @p applied) false)
|
|
44
|
+
(and (== @payload.grounded true)
|
|
45
|
+
(and (<= (math/abs (- @payload.x (object/get @p x))) @config.reachX)
|
|
46
|
+
(<= (math/abs (- @payload.y (object/get @p y))) @config.reachY))))))))
|
|
47
|
+
(if (> (array/len @touch) 0)
|
|
48
|
+
(let ((p (array/first @touch)))
|
|
49
|
+
(let ((m (object/get @p mod)))
|
|
50
|
+
(let ((remaining (array/len (array/filter @entity.coefPads (fn c (and (== (object/get @c applied) false) (!= (object/get @c id) (object/get @p id))))))))
|
|
51
|
+
(do
|
|
52
|
+
(set @entity.coefPads (array/map @entity.coefPads (fn c (if (== (object/get @c id) (object/get @p id)) (object/merge @c { applied: true }) @c))))
|
|
53
|
+
(emit COEF_PAD_APPLIED { id: (object/get @p id), x: (object/get @p x), y: (object/get @p y), x0: (object/get @m x0), x1: (object/get @m x1), a: (object/get @m a), h: (object/get @m h), k: (object/get @m k), hint: (object/get @p hint), hop: (object/get @p hop), samples: (object/get @p samples) })
|
|
54
|
+
(if (and (== @entity.coefCompleted false) (== @remaining 0))
|
|
55
|
+
(do
|
|
56
|
+
(set @entity.coefCompleted true)
|
|
57
|
+
(emit COEF_PAD_SET_COMPLETED {}))
|
|
58
|
+
null)))))
|
|
59
|
+
null))
|
|
60
|
+
|
|
61
|
+
RESTART -> active
|
|
62
|
+
(set @entity.coefPads (array/map @config.coefPads (fn p (object/merge @p { applied: false }))))
|
|
63
|
+
(set @entity.coefCompleted false)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
emits {
|
|
67
|
+
COEF_PAD_APPLIED -> external {
|
|
68
|
+
id : string!
|
|
69
|
+
x : number!
|
|
70
|
+
y : number!
|
|
71
|
+
x0 : number!
|
|
72
|
+
x1 : number!
|
|
73
|
+
a : number!
|
|
74
|
+
h : number!
|
|
75
|
+
k : number!
|
|
76
|
+
hint : string
|
|
77
|
+
hop : boolean
|
|
78
|
+
samples : [CoefModSample]
|
|
79
|
+
}
|
|
80
|
+
@description "The player stood on an unapplied coefficient pad; carries the pad position and the full mod (x0, x1, a, h, k) so the board appends it to the body authority's curveMods and hops the player onto the reshaped road. Fires once per pad per run."
|
|
81
|
+
@tier "domain"
|
|
82
|
+
COEF_PAD_SET_COMPLETED -> external {
|
|
83
|
+
}
|
|
84
|
+
@description "Every coefficient pad in the set is applied; fires once per run. Boards layer the completion fx and dismiss the zone card."
|
|
85
|
+
@tier "domain"
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
listens {
|
|
89
|
+
BODY_MOVED { x : number!, y : number!, vx : number!, vy : number!, grounded : boolean!, skating : boolean!, speed : number! }
|
|
90
|
+
RESTART { id : string }
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
config {
|
|
94
|
+
running : boolean = true
|
|
95
|
+
@label "Running"
|
|
96
|
+
@description "When true, BODY_MOVED applies touched pads; toggle to freeze every pad as-is."
|
|
97
|
+
@tier "domain"
|
|
98
|
+
coefPads : [CoefPad] = []
|
|
99
|
+
@label "Coefficient Pads"
|
|
100
|
+
@description "One row per pad: id, center (x, y in world units), the mod applied to the road while inside x0..x1 (a scales slope+height, h shifts horizontally, k lifts), and the hint floated on apply, and hop (true = the board teleports the player onto the reshaped surface — use when the mod steps the road far from the pad; false = the skate snap carries the player, preserving speed). applied is stamped at runtime."
|
|
101
|
+
@tier "domain"
|
|
102
|
+
reachX : number = 0.7
|
|
103
|
+
@label "Reach X"
|
|
104
|
+
@description "Horizontal tolerance (world units) around a pad's center when testing player contact (approximates the body's half-width plus a step)."
|
|
105
|
+
@tier "domain"
|
|
106
|
+
reachY : number = 1.2
|
|
107
|
+
@label "Reach Y"
|
|
108
|
+
@description "Vertical tolerance (world units) around a pad's center when testing player contact (covers riding the surface the pad sits on)."
|
|
109
|
+
@tier "domain"
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
page "/coef-pad" as CoefPadPage -> CoefPadLock
|
|
114
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
app std-curve-fog "1.0.0"
|
|
2
|
+
"Headless prediction-fog mechanic for graph-riding boards: in configured world regions the road ahead is only partially REVEALED — the atom listens BODY_MOVED and stamps fogX (the reveal horizon = player x + the region's lookAhead) onto the shared entity, and the board's render layer clips or ghosts every road sample past it, so the player must commit to jumps before the landing is visible and internalize where the function GOES (blowup, flattening, slow growth, divergence). Outside every region fogX sits at a large sentinel, i.e. fully revealed. Physics is untouched: the collider keeps the whole curve — the fog is purely visual. Renders nothing; boards clip their own curve/region samples against @entity.fogX (the render authority)."
|
|
3
|
+
orbital CurveFogOrbital {
|
|
4
|
+
type CurveFogRegion = {
|
|
5
|
+
x0 : number!
|
|
6
|
+
x1 : number!
|
|
7
|
+
lookAhead : number!
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
entity CurveFogData [runtime, shared] {
|
|
11
|
+
id : string!
|
|
12
|
+
fogX : number = 99999
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
trait CurveFog -> @rebindable CurveFogData [lifecycle] {
|
|
16
|
+
initial: active
|
|
17
|
+
|
|
18
|
+
state active {
|
|
19
|
+
INIT -> active
|
|
20
|
+
(set @entity.fogX 99999)
|
|
21
|
+
|
|
22
|
+
BODY_MOVED -> active when @config.running
|
|
23
|
+
(let ((rmatch (array/filter @config.regions (fn r (and (>= @payload.x (object/get @r x0)) (< @payload.x (object/get @r x1)))))))
|
|
24
|
+
(if (> (array/len @rmatch) 0)
|
|
25
|
+
(set @entity.fogX (+ @payload.x (object/get (array/first @rmatch) lookAhead)))
|
|
26
|
+
(set @entity.fogX 99999)))
|
|
27
|
+
|
|
28
|
+
RESTART -> active
|
|
29
|
+
(set @entity.fogX 99999)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
listens {
|
|
33
|
+
BODY_MOVED { x : number!, y : number!, vx : number!, vy : number!, grounded : boolean!, skating : boolean!, speed : number! }
|
|
34
|
+
RESTART { id : string }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
config {
|
|
38
|
+
running : boolean = true
|
|
39
|
+
@label "Running"
|
|
40
|
+
@description "When true, BODY_MOVED tracks the reveal horizon; toggle to freeze the fog where it is."
|
|
41
|
+
@tier "domain"
|
|
42
|
+
regions : [CurveFogRegion] = []
|
|
43
|
+
@label "Fog Regions"
|
|
44
|
+
@description "One row per fogged world span: x-range (x0..x1) and lookAhead — how far past the player the road stays revealed while inside. Small values force prediction (blowups), large values suit slow tail lessons. Empty list = no fog anywhere."
|
|
45
|
+
@tier "domain"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
page "/curve-fog" as CurveFogPage -> CurveFog
|
|
50
|
+
}
|