@auraindustry/aurajs 0.1.3 → 0.1.5

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 (108) hide show
  1. package/README.md +7 -0
  2. package/benchmarks/perf-thresholds.json +27 -0
  3. package/package.json +6 -1
  4. package/src/ai-guidance.mjs +302 -0
  5. package/src/authored-project.mjs +498 -2
  6. package/src/build-contract/capabilities.mjs +87 -1
  7. package/src/build-contract/constants.mjs +1 -0
  8. package/src/build-contract.mjs +2 -0
  9. package/src/bundler.mjs +143 -13
  10. package/src/cli.mjs +681 -13
  11. package/src/commands/packs.mjs +741 -0
  12. package/src/commands/project-authoring.mjs +128 -1
  13. package/src/conformance/cases/app-and-ui-runtime-cases.mjs +1 -2
  14. package/src/conformance/cases/core-runtime-cases.mjs +6 -2
  15. package/src/conformance/cases/scene3d-and-media-cases.mjs +238 -0
  16. package/src/conformance/cases/systems-and-gameplay-cases.mjs +265 -4
  17. package/src/conformance-mobile.mjs +166 -0
  18. package/src/conformance.mjs +89 -30
  19. package/src/evidence-bundle.mjs +242 -0
  20. package/src/headless-test/runtime-coordinator.mjs +186 -33
  21. package/src/headless-test.mjs +2 -0
  22. package/src/helpers/2d/index.mjs +183 -0
  23. package/src/helpers/index.mjs +26 -0
  24. package/src/helpers/starter-utils/adventure-objectives.js +102 -0
  25. package/src/helpers/starter-utils/adventure-world-2d.js +221 -0
  26. package/src/helpers/starter-utils/animation-2d.js +337 -0
  27. package/src/helpers/starter-utils/animation-packaging-2d.js +203 -0
  28. package/src/helpers/starter-utils/atlas-assets-2d.js +111 -0
  29. package/src/helpers/starter-utils/autoplay-debug-2d.js +215 -0
  30. package/src/helpers/starter-utils/avatar-3d.js +404 -0
  31. package/src/helpers/starter-utils/combat-feedback-2d.js +320 -0
  32. package/src/helpers/starter-utils/combat-runtime-2d.js +290 -0
  33. package/src/helpers/starter-utils/core.js +150 -0
  34. package/src/helpers/starter-utils/dialogue-2d.js +351 -0
  35. package/src/helpers/starter-utils/enemy-archetypes-2d.js +68 -0
  36. package/src/helpers/starter-utils/index.js +26 -0
  37. package/src/helpers/starter-utils/inventory-2d.js +268 -0
  38. package/src/helpers/starter-utils/journal-2d.js +267 -0
  39. package/src/helpers/starter-utils/platformer-3d.js +132 -0
  40. package/src/helpers/starter-utils/scene-audio-2d.js +236 -0
  41. package/src/helpers/starter-utils/streamed-world-2d.js +378 -0
  42. package/src/helpers/starter-utils/tilemap-nav-2d.js +499 -0
  43. package/src/helpers/starter-utils/tilemap-world-2d.js +205 -0
  44. package/src/helpers/starter-utils/triggers.js +662 -0
  45. package/src/helpers/starter-utils/tween-2d.js +615 -0
  46. package/src/helpers/starter-utils/wave-director.js +101 -0
  47. package/src/helpers/starter-utils/world-compositor-2d.js +253 -0
  48. package/src/helpers/starter-utils/world-persistence-2d.js +180 -0
  49. package/src/mobile/android/build.mjs +606 -0
  50. package/src/mobile/android/host-artifact.mjs +280 -0
  51. package/src/mobile/ios/build.mjs +1323 -0
  52. package/src/mobile/ios/host-artifact.mjs +819 -0
  53. package/src/mobile/shared/capabilities.mjs +174 -0
  54. package/src/packs/catalog.mjs +259 -0
  55. package/src/perf-benchmark-runner.mjs +17 -12
  56. package/src/perf-benchmark.mjs +408 -4
  57. package/src/publish-command.mjs +303 -6
  58. package/src/replay-runtime.mjs +257 -0
  59. package/src/scaffold/config.mjs +2 -0
  60. package/src/scaffold/fs.mjs +8 -1
  61. package/src/scaffold/project-docs.mjs +43 -1
  62. package/src/scaffold.mjs +4 -0
  63. package/src/session-runtime.mjs +4 -3
  64. package/src/web-conformance.mjs +0 -36
  65. package/templates/create/2d-adventure/config/gameplay/adventure.config.js +9 -6
  66. package/templates/create/2d-adventure/content/gameplay/dialogue.js +85 -0
  67. package/templates/create/2d-adventure/content/gameplay/world.js +32 -36
  68. package/templates/create/2d-adventure/content/gameplay/world.tilemap.json +273 -0
  69. package/templates/create/2d-adventure/docs/design/loop.md +4 -3
  70. package/templates/create/2d-adventure/prefabs/relic.prefab.js +10 -10
  71. package/templates/create/2d-adventure/prefabs/world.prefab.js +127 -74
  72. package/templates/create/2d-adventure/scenes/gameplay.scene.js +603 -112
  73. package/templates/create/2d-adventure/src/runtime/capabilities.js +16 -0
  74. package/templates/create/2d-adventure/ui/hud.screen.js +187 -4
  75. package/templates/create/2d-adventure/ui/journal.screen.js +183 -0
  76. package/templates/create/3d/scenes/gameplay.scene.js +30 -3
  77. package/templates/create/3d/src/runtime/capabilities.js +5 -0
  78. package/templates/create/3d/src/runtime/materials.js +10 -0
  79. package/templates/create/3d-adventure/scenes/gameplay.scene.js +30 -3
  80. package/templates/create/3d-adventure/src/runtime/capabilities.js +5 -0
  81. package/templates/create/3d-adventure/src/runtime/materials.js +11 -0
  82. package/templates/create/3d-collectathon/scenes/gameplay.scene.js +30 -3
  83. package/templates/create/3d-collectathon/src/runtime/capabilities.js +5 -0
  84. package/templates/create/3d-collectathon/src/runtime/materials.js +10 -0
  85. package/templates/create/shared/src/runtime/ui-forms.js +552 -0
  86. package/templates/create/shared/src/starter-utils/adventure-world-2d.js +221 -0
  87. package/templates/create/shared/src/starter-utils/animation-packaging-2d.js +203 -0
  88. package/templates/create/shared/src/starter-utils/atlas-assets-2d.js +111 -0
  89. package/templates/create/shared/src/starter-utils/autoplay-debug-2d.js +215 -0
  90. package/templates/create/shared/src/starter-utils/combat-runtime-2d.js +290 -0
  91. package/templates/create/shared/src/starter-utils/dialogue-2d.js +351 -0
  92. package/templates/create/shared/src/starter-utils/index.js +15 -1
  93. package/templates/create/shared/src/starter-utils/inventory-2d.js +268 -0
  94. package/templates/create/shared/src/starter-utils/journal-2d.js +267 -0
  95. package/templates/create/shared/src/starter-utils/scene-audio-2d.js +236 -0
  96. package/templates/create/shared/src/starter-utils/streamed-world-2d.js +378 -0
  97. package/templates/create/shared/src/starter-utils/tilemap-nav-2d.js +499 -0
  98. package/templates/create/shared/src/starter-utils/tilemap-world-2d.js +205 -0
  99. package/templates/create/shared/src/starter-utils/world-compositor-2d.js +253 -0
  100. package/templates/create/shared/src/starter-utils/world-persistence-2d.js +180 -0
  101. package/templates/create-bin/play.js +36 -7
  102. package/templates/skills/auramaxx/SKILL.md +46 -0
  103. package/templates/skills/auramaxx/project-requirements.md +68 -0
  104. package/templates/skills/auramaxx/starter-recipes.md +104 -0
  105. package/templates/skills/auramaxx/validation-checklist.md +49 -0
  106. package/templates/skills/aurajs/SKILL.md +0 -96
  107. package/templates/skills/aurajs/api-contract-3d.md +0 -7
  108. package/templates/skills/aurajs/api-contract.md +0 -7
@@ -9,12 +9,28 @@ function failWithReason(reasonCode, message) {
9
9
  export function assertRuntimeCapabilities() {
10
10
  const missing = [];
11
11
  if (!hasMethod(aura.window, 'getFPS')) missing.push('aura.window.getFPS');
12
+ if (!hasMethod(aura.window, 'getSize')) missing.push('aura.window.getSize');
12
13
  if (!hasMethod(aura.input, 'isKeyDown')) missing.push('aura.input.isKeyDown');
13
14
  if (!hasMethod(aura.input, 'isKeyPressed')) missing.push('aura.input.isKeyPressed');
14
15
  if (!hasMethod(aura.draw2d, 'clear')) missing.push('aura.draw2d.clear');
15
16
  if (!hasMethod(aura.draw2d, 'rect')) missing.push('aura.draw2d.rect');
16
17
  if (!hasMethod(aura.draw2d, 'text')) missing.push('aura.draw2d.text');
17
18
  if (!hasMethod(aura.draw2d, 'measureText')) missing.push('aura.draw2d.measureText');
19
+ if (!hasMethod(aura.tilemap, 'import')) missing.push('aura.tilemap.import');
20
+ if (!hasMethod(aura.tilemap, 'draw')) missing.push('aura.tilemap.draw');
21
+ if (!hasMethod(aura.tilemap, 'getInfo')) missing.push('aura.tilemap.getInfo');
22
+ if (!hasMethod(aura.tilemap, 'queryAABB')) missing.push('aura.tilemap.queryAABB');
23
+ if (!hasMethod(aura.tilemap, 'queryObjects')) missing.push('aura.tilemap.queryObjects');
24
+ if (!hasMethod(aura.tilemap, 'unload')) missing.push('aura.tilemap.unload');
25
+ if (!hasMethod(aura.ui, 'beginView')) missing.push('aura.ui.beginView');
26
+ if (!hasMethod(aura.ui, 'endView')) missing.push('aura.ui.endView');
27
+ if (!hasMethod(aura.ui, 'beginRow')) missing.push('aura.ui.beginRow');
28
+ if (!hasMethod(aura.ui, 'endRow')) missing.push('aura.ui.endRow');
29
+ if (!hasMethod(aura.ui, 'beginColumn')) missing.push('aura.ui.beginColumn');
30
+ if (!hasMethod(aura.ui, 'endColumn')) missing.push('aura.ui.endColumn');
31
+ if (!hasMethod(aura.ui, 'button')) missing.push('aura.ui.button');
32
+ if (!hasMethod(aura.ui, 'text')) missing.push('aura.ui.text');
33
+ if (!hasMethod(aura.ui, 'getViewState')) missing.push('aura.ui.getViewState');
18
34
  if (typeof aura.rgb !== 'function') missing.push('aura.rgb');
19
35
  if (typeof aura.rgba !== 'function') missing.push('aura.rgba');
20
36
  if (!aura.Color || !aura.Color.WHITE) missing.push('aura.Color.WHITE');
@@ -1,3 +1,5 @@
1
+ import { renderCollectionList, renderTabBar } from '../src/runtime/ui-forms.js';
2
+
1
3
  const hudScreen = {
2
4
  id: 'hud',
3
5
  kind: 'ui-screen',
@@ -10,10 +12,167 @@ export function createHudScreen() {
10
12
  return hudScreen;
11
13
  }
12
14
 
13
- export function drawAdventureHud(data = {}) {
15
+ function createAdventureHudUiSeed() {
16
+ return {
17
+ showControlsHint: true,
18
+ showInventory: false,
19
+ showJournal: false,
20
+ inventorySelectedCategoryId: null,
21
+ inventorySelectedItemId: null,
22
+ journalSelectedCategoryId: null,
23
+ journalSelectedEntryId: null,
24
+ dialogueSelectedChoiceId: null,
25
+ };
26
+ }
27
+
28
+ function ensureAdventureHudUiState(context = {}) {
29
+ if (typeof context.ensureUiState === 'function') {
30
+ return context.ensureUiState('adventureHud', createAdventureHudUiSeed());
31
+ }
32
+ const appState = context.appState && typeof context.appState === 'object' ? context.appState : (context.appState = {});
33
+ if (!appState.ui || typeof appState.ui !== 'object' || Array.isArray(appState.ui)) {
34
+ appState.ui = {};
35
+ }
36
+ if (!appState.ui.adventureHud || typeof appState.ui.adventureHud !== 'object' || Array.isArray(appState.ui.adventureHud)) {
37
+ appState.ui.adventureHud = createAdventureHudUiSeed();
38
+ }
39
+ return appState.ui.adventureHud;
40
+ }
41
+
42
+ function drawInventoryPanel(data = {}, context = {}) {
43
+ if (data.showInventory !== true) return;
44
+ const hudUiState = ensureAdventureHudUiState(context);
45
+ const inventory = data.inventory || {};
46
+ const size = aura.window?.getSize?.() || { width: 1280, height: 720 };
47
+ const panelWidth = Math.min(420, size.width - 36);
48
+ const panelHeight = Math.min(430, size.height - 34);
49
+ const panelX = size.width - panelWidth - 18;
50
+ const panelY = 16;
51
+
52
+ if (!hudUiState.inventorySelectedCategoryId && inventory.selectedCategoryId) {
53
+ hudUiState.inventorySelectedCategoryId = inventory.selectedCategoryId;
54
+ }
55
+ if (!hudUiState.inventorySelectedItemId && inventory.selectedItemId) {
56
+ hudUiState.inventorySelectedItemId = inventory.selectedItemId;
57
+ }
58
+
59
+ aura.ui.beginView({
60
+ id: 'adventure-inventory-root',
61
+ x: panelX,
62
+ y: panelY,
63
+ width: panelWidth,
64
+ height: panelHeight,
65
+ gap: 12,
66
+ padding: 16,
67
+ clip: true,
68
+ background: '#091117',
69
+ borderColor: '#34506d',
70
+ });
71
+
72
+ aura.ui.text('adventure-inventory-eyebrow', {
73
+ text: 'FIELD KIT',
74
+ size: 12,
75
+ color: '#7ec8ff',
76
+ });
77
+ aura.ui.text('adventure-inventory-title', {
78
+ text: 'Recovered Inventory',
79
+ size: 26,
80
+ color: '#eef7ff',
81
+ });
82
+ aura.ui.text('adventure-inventory-copy', {
83
+ text: data.inventoryHint || 'Inventory state is shared with the route HUD.',
84
+ size: 13,
85
+ color: '#c8d8e7',
86
+ });
87
+
88
+ const tabs = renderTabBar({
89
+ id: 'adventure-inventory-tabs',
90
+ value: hudUiState.inventorySelectedCategoryId || inventory.selectedCategoryId,
91
+ tabs: Array.isArray(inventory.categories)
92
+ ? inventory.categories.map((entry) => ({
93
+ id: entry.id,
94
+ label: `${entry.label} ${entry.count}`,
95
+ }))
96
+ : [],
97
+ });
98
+ if (tabs.ok && tabs.value) {
99
+ hudUiState.inventorySelectedCategoryId = tabs.value;
100
+ }
101
+
102
+ aura.ui.beginRow({
103
+ id: 'adventure-inventory-layout',
104
+ gap: 12,
105
+ width: 'fill',
106
+ });
107
+
108
+ aura.ui.beginColumn({
109
+ id: 'adventure-inventory-list-col',
110
+ width: 220,
111
+ gap: 10,
112
+ });
113
+ const list = renderCollectionList({
114
+ id: 'adventure-inventory-list',
115
+ value: hudUiState.inventorySelectedItemId || inventory.selectedItemId,
116
+ items: Array.isArray(inventory.items) ? inventory.items : [],
117
+ emptyText: 'Nothing recovered for this category yet.',
118
+ });
119
+ if (list.ok && list.value) {
120
+ hudUiState.inventorySelectedItemId = list.value;
121
+ }
122
+ aura.ui.endColumn();
123
+
124
+ const selectedItemId = hudUiState.inventorySelectedItemId || inventory.selectedItemId;
125
+ const selectedItem = (Array.isArray(inventory.items) ? inventory.items : []).find((entry) => entry.id === selectedItemId)
126
+ || (Array.isArray(inventory.items) ? inventory.items[0] : null)
127
+ || null;
128
+
129
+ aura.ui.beginColumn({
130
+ id: 'adventure-inventory-detail-col',
131
+ width: 'fill',
132
+ gap: 10,
133
+ padding: 12,
134
+ background: '#10202c',
135
+ borderColor: '#213a50',
136
+ });
137
+ aura.ui.text('adventure-inventory-detail-label', {
138
+ text: 'DETAIL',
139
+ size: 11,
140
+ color: '#84c3ef',
141
+ });
142
+ aura.ui.text('adventure-inventory-detail-title', {
143
+ text: selectedItem?.label || 'No item selected',
144
+ size: 18,
145
+ color: '#f4f8ff',
146
+ });
147
+ aura.ui.text('adventure-inventory-detail-badge', {
148
+ text: selectedItem?.badge ? `${selectedItem.badge}${selectedItem.quantity > 1 ? ` · x${selectedItem.quantity}` : ''}` : 'Starter-owned inventory view',
149
+ size: 12,
150
+ color: '#f0cf79',
151
+ });
152
+ aura.ui.text('adventure-inventory-detail-copy', {
153
+ text: selectedItem?.description || 'Pickups, keys, and field notes now travel through one shared collection lane.',
154
+ size: 13,
155
+ color: '#d5e1ee',
156
+ });
157
+ if (selectedItem?.detail) {
158
+ aura.ui.text('adventure-inventory-detail-note', {
159
+ text: selectedItem.detail,
160
+ size: 12,
161
+ color: '#a7bacd',
162
+ });
163
+ }
164
+ aura.ui.endColumn();
165
+
166
+ aura.ui.endRow();
167
+ aura.ui.endView();
168
+ }
169
+
170
+ export function drawAdventureHud(data = {}, context = {}) {
171
+ drawInventoryPanel(data, context);
172
+
14
173
  let nextY = 12;
15
174
  if (data.showControlsHint !== false) {
16
- aura.draw2d.text('Move: Arrows/WASD Interact: E or Enter', 12, nextY, {
175
+ aura.draw2d.text('Move: Arrows/WASD Interact: E or Enter Inventory: I or Tab Journal: J', 12, nextY, {
17
176
  color: aura.Color.WHITE,
18
177
  size: 14,
19
178
  align: 'left',
@@ -27,12 +186,20 @@ export function drawAdventureHud(data = {}) {
27
186
  align: 'left',
28
187
  });
29
188
  nextY += 22;
30
- aura.draw2d.text(`Beacons ${data.beaconCount ?? 0}/${data.beaconTarget ?? 0} FPS ${data.fps ?? '0'}`, 12, nextY, {
189
+ aura.draw2d.text(`${data.zoneLabel || 'Moon Archive'} Checkpoint ${data.checkpointLabel || 'Route Entry'} FPS ${data.fps ?? '0'}`, 12, nextY, {
31
190
  color: aura.Color.WHITE,
32
191
  size: 14,
33
192
  align: 'left',
34
193
  });
35
194
  nextY += 22;
195
+ if (data.objectiveText) {
196
+ aura.draw2d.text(data.objectiveText, 12, nextY, {
197
+ color: aura.rgb(0.76, 0.88, 1.0),
198
+ size: 13,
199
+ align: 'left',
200
+ });
201
+ nextY += 22;
202
+ }
36
203
 
37
204
  if (data.promptText) {
38
205
  aura.draw2d.text(data.promptText, 12, nextY, {
@@ -43,9 +210,25 @@ export function drawAdventureHud(data = {}) {
43
210
  nextY += 24;
44
211
  }
45
212
 
213
+ if (data.dialogueActive === true) {
214
+ aura.draw2d.text('Archive link active. Follow the overlay prompt to continue the conversation.', 12, nextY, {
215
+ color: aura.rgb(0.9, 0.86, 0.54),
216
+ size: 13,
217
+ align: 'left',
218
+ });
219
+ nextY += 22;
220
+ } else if (data.showJournal === true) {
221
+ aura.draw2d.text(data.journalHint || 'Journal open. Route intel is mirrored through the overlay screen.', 12, nextY, {
222
+ color: aura.rgb(0.78, 0.9, 1.0),
223
+ size: 13,
224
+ align: 'left',
225
+ });
226
+ nextY += 22;
227
+ }
228
+
46
229
  if (data.runComplete !== true) return;
47
230
 
48
- aura.draw2d.text('RUINS SURVEY COMPLETE', 12, nextY, {
231
+ aura.draw2d.text('ARCHIVE ROUTE SECURED', 12, nextY, {
49
232
  color: aura.rgb(0.58, 1.0, 0.74),
50
233
  size: 24,
51
234
  align: 'left',
@@ -0,0 +1,183 @@
1
+ import { renderDialoguePanel, renderJournalPane, renderTabBar } from '../src/runtime/ui-forms.js';
2
+
3
+ const journalScreen = {
4
+ id: 'journal',
5
+ kind: 'ui-screen',
6
+ role: 'overlay',
7
+ draw: drawAdventureJournalOverlay,
8
+ notes: ['This overlay proves the shared dialogue panel and shared journal pane without widening the starter scene list.'],
9
+ };
10
+
11
+ export function createJournalScreen() {
12
+ return journalScreen;
13
+ }
14
+
15
+ function createAdventureHudUiSeed() {
16
+ return {
17
+ showControlsHint: true,
18
+ showInventory: false,
19
+ showJournal: false,
20
+ inventorySelectedCategoryId: null,
21
+ inventorySelectedItemId: null,
22
+ journalSelectedCategoryId: null,
23
+ journalSelectedEntryId: null,
24
+ dialogueSelectedChoiceId: null,
25
+ };
26
+ }
27
+
28
+ function ensureAdventureHudUiState(context = {}) {
29
+ if (typeof context.ensureUiState === 'function') {
30
+ return context.ensureUiState('adventureHud', createAdventureHudUiSeed());
31
+ }
32
+ const appState = context.appState && typeof context.appState === 'object' ? context.appState : (context.appState = {});
33
+ if (!appState.ui || typeof appState.ui !== 'object' || Array.isArray(appState.ui)) {
34
+ appState.ui = {};
35
+ }
36
+ if (!appState.ui.adventureHud || typeof appState.ui.adventureHud !== 'object' || Array.isArray(appState.ui.adventureHud)) {
37
+ appState.ui.adventureHud = createAdventureHudUiSeed();
38
+ }
39
+ return appState.ui.adventureHud;
40
+ }
41
+
42
+ function beginOverlayView(id, size) {
43
+ aura.ui.beginView({
44
+ id,
45
+ x: 18,
46
+ y: 18,
47
+ width: Math.max(320, size.width - 36),
48
+ height: Math.max(280, size.height - 36),
49
+ gap: 12,
50
+ padding: 16,
51
+ clip: true,
52
+ background: '#071118',
53
+ borderColor: '#34506d',
54
+ });
55
+ }
56
+
57
+ function drawDialogueOverlay(data = {}, context = {}) {
58
+ const hudUiState = ensureAdventureHudUiState(context);
59
+ const size = aura.window?.getSize?.() || { width: 1280, height: 720 };
60
+ const dialogue = data.dialogue || {};
61
+ const line = dialogue.line || {};
62
+
63
+ beginOverlayView('adventure-dialogue-overlay', size);
64
+ aura.ui.text('adventure-dialogue-eyebrow', {
65
+ text: data.zoneLabel || 'Moon Archive',
66
+ size: 11,
67
+ color: '#7ec8ff',
68
+ });
69
+ aura.ui.text('adventure-dialogue-title', {
70
+ text: data.title || dialogue.title || 'Dialogue',
71
+ size: 24,
72
+ color: '#eef7ff',
73
+ });
74
+ if (data.controlsText) {
75
+ aura.ui.text('adventure-dialogue-controls', {
76
+ text: data.controlsText,
77
+ size: 12,
78
+ color: '#c8d8e7',
79
+ });
80
+ }
81
+
82
+ const panel = renderDialoguePanel({
83
+ id: 'adventure-dialogue-panel',
84
+ label: 'CONVERSATION',
85
+ speaker: line.speaker || 'Archive Link',
86
+ title: dialogue.nodeLabel || dialogue.title || 'Dialogue',
87
+ text: line.text || 'Connection established.',
88
+ note: dialogue.awaitingChoice === true
89
+ ? 'Choose a response to continue the route briefing.'
90
+ : 'Advance the briefing to continue.',
91
+ value: hudUiState.dialogueSelectedChoiceId || dialogue.selectedChoiceId || null,
92
+ choices: Array.isArray(dialogue.choices)
93
+ ? dialogue.choices.map((entry) => ({
94
+ id: entry.id,
95
+ label: entry.label,
96
+ description: entry.detail,
97
+ disabled: entry.disabled === true,
98
+ }))
99
+ : [],
100
+ emptyText: 'Press E, Enter, or Space to continue.',
101
+ });
102
+ if (panel.ok && panel.value) {
103
+ hudUiState.dialogueSelectedChoiceId = panel.value;
104
+ }
105
+ aura.ui.endView();
106
+ }
107
+
108
+ function drawJournalOverlay(data = {}, context = {}) {
109
+ const hudUiState = ensureAdventureHudUiState(context);
110
+ const size = aura.window?.getSize?.() || { width: 1280, height: 720 };
111
+ const journal = data.journal || {};
112
+
113
+ beginOverlayView('adventure-journal-overlay', size);
114
+ aura.ui.text('adventure-journal-eyebrow', {
115
+ text: data.zoneLabel || 'Moon Archive',
116
+ size: 11,
117
+ color: '#7ec8ff',
118
+ });
119
+ aura.ui.text('adventure-journal-title', {
120
+ text: 'Route Journal',
121
+ size: 24,
122
+ color: '#eef7ff',
123
+ });
124
+ if (data.objectiveText) {
125
+ aura.ui.text('adventure-journal-objective', {
126
+ text: data.objectiveText,
127
+ size: 13,
128
+ color: '#c8d8e7',
129
+ });
130
+ }
131
+ if (data.controlsText) {
132
+ aura.ui.text('adventure-journal-controls', {
133
+ text: data.controlsText,
134
+ size: 12,
135
+ color: '#9db2cb',
136
+ });
137
+ }
138
+
139
+ if (!hudUiState.journalSelectedCategoryId && journal.selectedCategoryId) {
140
+ hudUiState.journalSelectedCategoryId = journal.selectedCategoryId;
141
+ }
142
+ if (!hudUiState.journalSelectedEntryId && journal.selectedEntryId) {
143
+ hudUiState.journalSelectedEntryId = journal.selectedEntryId;
144
+ }
145
+
146
+ const tabs = renderTabBar({
147
+ id: 'adventure-journal-tabs',
148
+ value: hudUiState.journalSelectedCategoryId || journal.selectedCategoryId,
149
+ tabs: Array.isArray(journal.categories)
150
+ ? journal.categories.map((entry) => ({
151
+ id: entry.id,
152
+ label: `${entry.label} ${entry.count}`,
153
+ }))
154
+ : [],
155
+ });
156
+ if (tabs.ok && tabs.value) {
157
+ hudUiState.journalSelectedCategoryId = tabs.value;
158
+ }
159
+
160
+ const pane = renderJournalPane({
161
+ id: 'adventure-journal-pane',
162
+ label: 'ROUTE RECORD',
163
+ description: 'Shared starter-owned journal state now tracks route notes and archive intel.',
164
+ value: hudUiState.journalSelectedEntryId || journal.selectedEntryId,
165
+ entries: Array.isArray(journal.activeEntries) ? journal.activeEntries : [],
166
+ emptyText: 'No route entries are active for this section yet.',
167
+ detailEmptyText: 'Select a route record to inspect its current state.',
168
+ });
169
+ if (pane.ok && pane.value) {
170
+ hudUiState.journalSelectedEntryId = pane.value;
171
+ }
172
+ aura.ui.endView();
173
+ }
174
+
175
+ export function drawAdventureJournalOverlay(data = {}, context = {}) {
176
+ if (data.mode === 'dialogue') {
177
+ drawDialogueOverlay(data, context);
178
+ return;
179
+ }
180
+ drawJournalOverlay(data, context);
181
+ }
182
+
183
+ export default journalScreen;
@@ -82,6 +82,34 @@ export function createGameplayScene(context = {}) {
82
82
  let playerVisual = null;
83
83
  let sceneState = createPlatformerRunState();
84
84
 
85
+ function configureSceneLook() {
86
+ aura.light.ambient({ r: 0.92, g: 0.96, b: 1.0 }, 0.16);
87
+ aura.light.hemisphere(
88
+ { r: 0.42, g: 0.56, b: 0.78 },
89
+ { r: 0.14, g: 0.11, b: 0.08 },
90
+ 0.3,
91
+ { x: 0, y: 1, z: 0 },
92
+ );
93
+ aura.light.directional({ x: 0.58, y: -1.0, z: -0.32 }, { r: 1.0, g: 0.97, b: 0.9 }, 1.05);
94
+ aura.light.spot(
95
+ { x: 8.5, y: 6.5, z: 8.5 },
96
+ { x: -0.45, y: -1.0, z: -0.25 },
97
+ { r: 0.45, g: 0.78, b: 1.0 },
98
+ 1.35,
99
+ 28,
100
+ 0.72,
101
+ );
102
+ aura.draw3d.setFog({
103
+ mode: 'exp2',
104
+ color: { r: 0.06, g: 0.09, b: 0.13 },
105
+ density: 0.018,
106
+ });
107
+ aura.draw3d.setOcclusionCulling({ enabled: true, conservative: true });
108
+ aura.draw3d.setPostFXPass('bloom', { strength: 0.28, radius: 0.5, threshold: 0.74 });
109
+ aura.draw3d.setPostFXPass('vignette', { strength: 0.12, radius: 0.94 });
110
+ aura.draw3d.setPostFXPass('fxaa', { strength: 1.0 });
111
+ }
112
+
85
113
  function syncSessionState() {
86
114
  platformerSession.lastSceneId = 'gameplay';
87
115
  platformerSession.bestScore = Math.max(Number(platformerSession.bestScore || 0), sceneState.score);
@@ -230,8 +258,7 @@ export function createGameplayScene(context = {}) {
230
258
  materials = createPlatformerMaterials();
231
259
  playerVisual = loadPlayerAvatarVisual();
232
260
 
233
- aura.light.ambient({ r: 1, g: 1, b: 1 }, 0.22);
234
- aura.light.directional({ x: 0.6, y: -1.0, z: -0.4 }, { r: 1, g: 1, b: 1 }, 1.0);
261
+ configureSceneLook();
235
262
  aura.camera3d.perspective(62, 0.1, 140);
236
263
 
237
264
  resetRun();
@@ -273,7 +300,7 @@ export function createGameplayScene(context = {}) {
273
300
  context.clearHudScreen?.();
274
301
  },
275
302
  draw() {
276
- aura.draw3d.clear3d({ r: 0.06, g: 0.08, b: 0.12 });
303
+ aura.draw3d.clear3d({ r: 0.045, g: 0.06, b: 0.09 });
277
304
  drawPlatformerCourse({
278
305
  mesh: boxMesh,
279
306
  floorMaterial: materials.floor,
@@ -11,7 +11,9 @@ export function assertRuntimeCapabilities() {
11
11
  if (!hasMethod(aura.mesh, 'createBox')) missing.push('aura.mesh.createBox');
12
12
  if (!hasMethod(aura.material, 'create')) missing.push('aura.material.create');
13
13
  if (!hasMethod(aura.light, 'ambient')) missing.push('aura.light.ambient');
14
+ if (!hasMethod(aura.light, 'hemisphere')) missing.push('aura.light.hemisphere');
14
15
  if (!hasMethod(aura.light, 'directional')) missing.push('aura.light.directional');
16
+ if (!hasMethod(aura.light, 'spot')) missing.push('aura.light.spot');
15
17
  if (!hasMethod(aura.camera3d, 'perspective')) missing.push('aura.camera3d.perspective');
16
18
  if (!hasMethod(aura.camera3d, 'setPosition')) missing.push('aura.camera3d.setPosition');
17
19
  if (!hasMethod(aura.camera3d, 'lookAt')) missing.push('aura.camera3d.lookAt');
@@ -33,6 +35,9 @@ export function assertRuntimeCapabilities() {
33
35
  if (!hasMethod(aura.scene3d, 'submitRenderBindings')) missing.push('aura.scene3d.submitRenderBindings');
34
36
  if (!hasMethod(aura.draw3d, 'clear3d')) missing.push('aura.draw3d.clear3d');
35
37
  if (!hasMethod(aura.draw3d, 'drawMesh')) missing.push('aura.draw3d.drawMesh');
38
+ if (!hasMethod(aura.draw3d, 'setFog')) missing.push('aura.draw3d.setFog');
39
+ if (!hasMethod(aura.draw3d, 'setOcclusionCulling')) missing.push('aura.draw3d.setOcclusionCulling');
40
+ if (!hasMethod(aura.draw3d, 'setPostFXPass')) missing.push('aura.draw3d.setPostFXPass');
36
41
  if (!hasMethod(aura.draw2d, 'text')) missing.push('aura.draw2d.text');
37
42
  if (!hasMethod(aura.draw2d, 'measureText')) missing.push('aura.draw2d.measureText');
38
43
  if (typeof aura.rgb !== 'function') missing.push('aura.rgb');
@@ -12,23 +12,33 @@ export function createPlatformerMaterials() {
12
12
  }),
13
13
  player: aura.material.create({
14
14
  color: { r: 0.98, g: 0.52, b: 0.26, a: 1.0 },
15
+ emissive: { r: 0.08, g: 0.03, b: 0.01 },
15
16
  metallic: 0.25,
16
17
  roughness: 0.35,
18
+ sheenColor: { r: 0.16, g: 0.1, b: 0.08 },
19
+ sheenRoughness: 0.46,
17
20
  }),
18
21
  pickup: aura.material.create({
19
22
  color: { r: 0.95, g: 0.9, b: 0.3, a: 1.0 },
23
+ emissive: { r: 0.42, g: 0.34, b: 0.08 },
20
24
  metallic: 0.65,
21
25
  roughness: 0.25,
22
26
  }),
23
27
  checkpoint: aura.material.create({
24
28
  color: { r: 0.36, g: 0.9, b: 1.0, a: 1.0 },
29
+ emissive: { r: 0.05, g: 0.22, b: 0.26 },
25
30
  metallic: 0.45,
26
31
  roughness: 0.28,
32
+ sheenColor: { r: 0.14, g: 0.2, b: 0.24 },
33
+ sheenRoughness: 0.22,
27
34
  }),
28
35
  goal: aura.material.create({
29
36
  color: { r: 0.5, g: 1.0, b: 0.64, a: 1.0 },
37
+ emissive: { r: 0.08, g: 0.24, b: 0.12 },
30
38
  metallic: 0.35,
31
39
  roughness: 0.35,
40
+ sheenColor: { r: 0.16, g: 0.22, b: 0.18 },
41
+ sheenRoughness: 0.28,
32
42
  }),
33
43
  };
34
44
  }
@@ -110,6 +110,34 @@ export function createGameplayScene(context = {}) {
110
110
  let playerVisual = null;
111
111
  let sceneState = createAdventureRunState();
112
112
 
113
+ function configureSceneLook() {
114
+ aura.light.ambient({ r: 0.9, g: 0.95, b: 1.0 }, 0.14);
115
+ aura.light.hemisphere(
116
+ { r: 0.26, g: 0.38, b: 0.56 },
117
+ { r: 0.08, g: 0.07, b: 0.06 },
118
+ 0.34,
119
+ { x: 0, y: 1, z: 0 },
120
+ );
121
+ aura.light.directional({ x: 0.42, y: -1.0, z: -0.24 }, { r: 1.0, g: 0.95, b: 0.9 }, 0.96);
122
+ aura.light.spot(
123
+ { x: 0.5, y: 8.5, z: 7.5 },
124
+ { x: -0.08, y: -1.0, z: -0.34 },
125
+ { r: 0.54, g: 0.92, b: 1.0 },
126
+ 1.4,
127
+ 34,
128
+ 0.7,
129
+ );
130
+ aura.draw3d.setFog({
131
+ mode: 'exp2',
132
+ color: { r: 0.035, g: 0.05, b: 0.075 },
133
+ density: 0.021,
134
+ });
135
+ aura.draw3d.setOcclusionCulling({ enabled: true, conservative: true });
136
+ aura.draw3d.setPostFXPass('bloom', { strength: 0.34, radius: 0.56, threshold: 0.7 });
137
+ aura.draw3d.setPostFXPass('vignette', { strength: 0.18, radius: 0.9 });
138
+ aura.draw3d.setPostFXPass('fxaa', { strength: 1.0 });
139
+ }
140
+
113
141
  function relicCount() {
114
142
  return countCompletedObjectives(sceneState.relics);
115
143
  }
@@ -280,8 +308,7 @@ export function createGameplayScene(context = {}) {
280
308
  materials = createAdventureMaterials();
281
309
  playerVisual = loadPlayerAvatarVisual();
282
310
 
283
- aura.light.ambient({ r: 1, g: 1, b: 1 }, 0.23);
284
- aura.light.directional({ x: 0.55, y: -1.0, z: -0.35 }, { r: 1, g: 1, b: 1 }, 1.0);
311
+ configureSceneLook();
285
312
  aura.camera3d.perspective(62, 0.1, 160);
286
313
 
287
314
  resetRun();
@@ -332,7 +359,7 @@ export function createGameplayScene(context = {}) {
332
359
  },
333
360
 
334
361
  draw() {
335
- aura.draw3d.clear3d({ r: 0.05, g: 0.07, b: 0.11 });
362
+ aura.draw3d.clear3d({ r: 0.03, g: 0.045, b: 0.07 });
336
363
  drawAdventureCourse({
337
364
  mesh: boxMesh,
338
365
  floorMaterial: materials.floor,
@@ -12,7 +12,9 @@ export function assertRuntimeCapabilities() {
12
12
  if (!hasMethod(aura.mesh, 'createBox')) missing.push('aura.mesh.createBox');
13
13
  if (!hasMethod(aura.material, 'create')) missing.push('aura.material.create');
14
14
  if (!hasMethod(aura.light, 'ambient')) missing.push('aura.light.ambient');
15
+ if (!hasMethod(aura.light, 'hemisphere')) missing.push('aura.light.hemisphere');
15
16
  if (!hasMethod(aura.light, 'directional')) missing.push('aura.light.directional');
17
+ if (!hasMethod(aura.light, 'spot')) missing.push('aura.light.spot');
16
18
  if (!hasMethod(aura.camera3d, 'perspective')) missing.push('aura.camera3d.perspective');
17
19
  if (!hasMethod(aura.camera3d, 'setPosition')) missing.push('aura.camera3d.setPosition');
18
20
  if (!hasMethod(aura.camera3d, 'lookAt')) missing.push('aura.camera3d.lookAt');
@@ -34,6 +36,9 @@ export function assertRuntimeCapabilities() {
34
36
  if (!hasMethod(aura.scene3d, 'submitRenderBindings')) missing.push('aura.scene3d.submitRenderBindings');
35
37
  if (!hasMethod(aura.draw3d, 'clear3d')) missing.push('aura.draw3d.clear3d');
36
38
  if (!hasMethod(aura.draw3d, 'drawMesh')) missing.push('aura.draw3d.drawMesh');
39
+ if (!hasMethod(aura.draw3d, 'setFog')) missing.push('aura.draw3d.setFog');
40
+ if (!hasMethod(aura.draw3d, 'setOcclusionCulling')) missing.push('aura.draw3d.setOcclusionCulling');
41
+ if (!hasMethod(aura.draw3d, 'setPostFXPass')) missing.push('aura.draw3d.setPostFXPass');
37
42
  if (!hasMethod(aura.draw2d, 'rect')) missing.push('aura.draw2d.rect');
38
43
  if (!hasMethod(aura.draw2d, 'text')) missing.push('aura.draw2d.text');
39
44
  if (!hasMethod(aura.draw2d, 'measureText')) missing.push('aura.draw2d.measureText');
@@ -12,6 +12,7 @@ export function createAdventureMaterials() {
12
12
  }),
13
13
  relic: aura.material.create({
14
14
  color: { r: 0.98, g: 0.9, b: 0.38, a: 1.0 },
15
+ emissive: { r: 0.5, g: 0.38, b: 0.1 },
15
16
  metallic: 0.7,
16
17
  roughness: 0.24,
17
18
  }),
@@ -19,21 +20,31 @@ export function createAdventureMaterials() {
19
20
  color: { r: 0.3, g: 0.44, b: 0.66, a: 1.0 },
20
21
  metallic: 0.26,
21
22
  roughness: 0.36,
23
+ sheenColor: { r: 0.12, g: 0.16, b: 0.22 },
24
+ sheenRoughness: 0.26,
22
25
  }),
23
26
  beaconLit: aura.material.create({
24
27
  color: { r: 0.58, g: 1.0, b: 0.74, a: 1.0 },
28
+ emissive: { r: 0.12, g: 0.34, b: 0.18 },
25
29
  metallic: 0.48,
26
30
  roughness: 0.24,
31
+ sheenColor: { r: 0.16, g: 0.22, b: 0.18 },
32
+ sheenRoughness: 0.2,
27
33
  }),
28
34
  goalLocked: aura.material.create({
29
35
  color: { r: 0.24, g: 0.28, b: 0.34, a: 1.0 },
30
36
  metallic: 0.12,
31
37
  roughness: 0.44,
38
+ sheenColor: { r: 0.08, g: 0.1, b: 0.12 },
39
+ sheenRoughness: 0.34,
32
40
  }),
33
41
  goalReady: aura.material.create({
34
42
  color: { r: 0.72, g: 1.0, b: 0.82, a: 1.0 },
43
+ emissive: { r: 0.12, g: 0.28, b: 0.18 },
35
44
  metallic: 0.34,
36
45
  roughness: 0.28,
46
+ sheenColor: { r: 0.16, g: 0.22, b: 0.18 },
47
+ sheenRoughness: 0.24,
37
48
  }),
38
49
  };
39
50
  }