@helix3/helix-cli 0.1.5-helix3.33 → 0.1.6-helix3.34
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/package.json +1 -1
- package/vendor/ability-manifest.mjs +331 -6
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// @helix/humanoid-character@0.2.
|
|
1
|
+
// @helix/humanoid-character@0.2.7 — ability.json validator (frozen C3 contract).
|
|
2
2
|
// Generated by emit-schemas; vendored by @hypersoniclabs/helix-cli. Do not edit; changes require ability-v2.
|
|
3
3
|
|
|
4
4
|
// src/core/config/paths.ts
|
|
@@ -34,6 +34,318 @@ function nearestKey(key, candidates) {
|
|
|
34
34
|
return best !== void 0 && bestDist <= Math.max(2, Math.floor(key.length * 0.4)) ? best : void 0;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
// src/core/input/gamepadStandard.ts
|
|
38
|
+
var StandardButton = {
|
|
39
|
+
faceDown: 0,
|
|
40
|
+
faceRight: 1,
|
|
41
|
+
faceLeft: 2,
|
|
42
|
+
faceUp: 3,
|
|
43
|
+
bumperL: 4,
|
|
44
|
+
bumperR: 5,
|
|
45
|
+
triggerL: 6,
|
|
46
|
+
triggerR: 7,
|
|
47
|
+
select: 8,
|
|
48
|
+
start: 9,
|
|
49
|
+
stickL: 10,
|
|
50
|
+
stickR: 11,
|
|
51
|
+
dpadUp: 12,
|
|
52
|
+
dpadDown: 13,
|
|
53
|
+
dpadLeft: 14,
|
|
54
|
+
dpadRight: 15
|
|
55
|
+
};
|
|
56
|
+
var StandardAxis = {
|
|
57
|
+
leftStick: [0, 1],
|
|
58
|
+
rightStick: [2, 3]
|
|
59
|
+
};
|
|
60
|
+
var BUTTON_NAMES = Object.keys(StandardButton);
|
|
61
|
+
var AXIS_NAMES = Object.keys(StandardAxis);
|
|
62
|
+
|
|
63
|
+
// src/core/input/standardActions.ts
|
|
64
|
+
var STANDARD_ACTIONS = [
|
|
65
|
+
// ---- character / gameplay ----
|
|
66
|
+
{
|
|
67
|
+
id: "move",
|
|
68
|
+
kind: "vec2",
|
|
69
|
+
domain: "character",
|
|
70
|
+
context: "gameplay",
|
|
71
|
+
bindings: { composite: { up: ["KeyW"], down: ["KeyS"], left: ["KeyA"], right: ["KeyD"] }, stick: "leftStick" },
|
|
72
|
+
label: "Move",
|
|
73
|
+
description: "Planar movement (vec2; WASD composite or left stick)",
|
|
74
|
+
touch: "stick"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: "look",
|
|
78
|
+
kind: "vec2",
|
|
79
|
+
domain: "character",
|
|
80
|
+
context: "gameplay",
|
|
81
|
+
bindings: { stick: "rightStick" },
|
|
82
|
+
label: "Look",
|
|
83
|
+
description: "Camera look (pointer delta or right stick). First-person pointer lock auto-acquires on the T toggle and re-acquires on a canvas click (Esc releases); third-person and touch use unlocked drag",
|
|
84
|
+
touch: "drag"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
id: "jump",
|
|
88
|
+
kind: "button",
|
|
89
|
+
domain: "character",
|
|
90
|
+
context: "gameplay",
|
|
91
|
+
bindings: { keys: ["Space"], pad: "faceDown" },
|
|
92
|
+
label: "Jump",
|
|
93
|
+
description: "Jump (when grounded)",
|
|
94
|
+
touch: "button"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
id: "sprint",
|
|
98
|
+
kind: "button",
|
|
99
|
+
domain: "character",
|
|
100
|
+
context: "gameplay",
|
|
101
|
+
bindings: { keys: ["ShiftLeft", "ShiftRight"], pad: "stickL" },
|
|
102
|
+
label: "Sprint",
|
|
103
|
+
description: "Sprint-tier speed while held (touch: auto by stick magnitude)",
|
|
104
|
+
touch: "none"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
// AltLeft is the browser-safe primary (Ctrl+W closes the tab and cannot be prevented);
|
|
108
|
+
// Ctrl stays bound for fullscreen/wrapped builds where the genre convention applies.
|
|
109
|
+
id: "walk",
|
|
110
|
+
kind: "button",
|
|
111
|
+
domain: "character",
|
|
112
|
+
context: "gameplay",
|
|
113
|
+
bindings: { keys: ["AltLeft", "ControlLeft", "ControlRight"] },
|
|
114
|
+
label: "Walk",
|
|
115
|
+
description: "Force walk-tier speed while held",
|
|
116
|
+
touch: "none"
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
id: "crouch",
|
|
120
|
+
kind: "toggle",
|
|
121
|
+
domain: "character",
|
|
122
|
+
context: "gameplay",
|
|
123
|
+
bindings: { keys: ["KeyC"], pad: "faceRight" },
|
|
124
|
+
label: "Crouch",
|
|
125
|
+
description: "Toggle crouch",
|
|
126
|
+
touch: "button"
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
id: "primary",
|
|
130
|
+
kind: "button",
|
|
131
|
+
domain: "character",
|
|
132
|
+
context: "gameplay",
|
|
133
|
+
bindings: { mouseButtons: [0], pad: "triggerR" },
|
|
134
|
+
label: "Primary",
|
|
135
|
+
description: "Primary use/fire (abilities bind this instead of minting a private fire action)",
|
|
136
|
+
touch: "button"
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
id: "secondary",
|
|
140
|
+
kind: "button",
|
|
141
|
+
domain: "character",
|
|
142
|
+
context: "gameplay",
|
|
143
|
+
bindings: { mouseButtons: [2], pad: "triggerL" },
|
|
144
|
+
label: "Aim / secondary",
|
|
145
|
+
description: "Secondary use \u2014 the character system will drive aim-down-sights from this id",
|
|
146
|
+
touch: "button"
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
id: "interact",
|
|
150
|
+
kind: "button",
|
|
151
|
+
domain: "character",
|
|
152
|
+
context: "gameplay",
|
|
153
|
+
bindings: { keys: ["KeyE"], pad: "faceLeft" },
|
|
154
|
+
label: "Interact",
|
|
155
|
+
description: "Contextual world interaction (doors, pickups, NPCs)",
|
|
156
|
+
touch: "button"
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
id: "reload",
|
|
160
|
+
kind: "button",
|
|
161
|
+
domain: "character",
|
|
162
|
+
context: "gameplay",
|
|
163
|
+
bindings: { keys: ["KeyR"], pad: "faceUp" },
|
|
164
|
+
label: "Reload",
|
|
165
|
+
description: "Reload / secondary contextual action",
|
|
166
|
+
touch: "button"
|
|
167
|
+
},
|
|
168
|
+
// Direct slot select is keyboard-only (digits); the gamepad cycles via equipPrev/equipNext instead.
|
|
169
|
+
...Array.from({ length: 9 }, (_, i) => ({
|
|
170
|
+
id: `ability${i + 1}`,
|
|
171
|
+
kind: "button",
|
|
172
|
+
domain: "character",
|
|
173
|
+
context: "gameplay",
|
|
174
|
+
bindings: { keys: [`Digit${i + 1}`] },
|
|
175
|
+
label: `Ability ${i + 1}`,
|
|
176
|
+
description: `Ability/item slot ${i + 1} (direct select; pad players cycle with equipPrev/equipNext)`,
|
|
177
|
+
touch: "radial"
|
|
178
|
+
})),
|
|
179
|
+
{
|
|
180
|
+
id: "equipNext",
|
|
181
|
+
kind: "button",
|
|
182
|
+
domain: "character",
|
|
183
|
+
context: "gameplay",
|
|
184
|
+
bindings: { keys: ["BracketRight"], pad: "bumperR" },
|
|
185
|
+
label: "Next equip",
|
|
186
|
+
description: "Cycle the active ability/equip slot forward (1-9). Slot state is game-side \u2014 worlds/abilities consume this",
|
|
187
|
+
touch: "none"
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
id: "equipPrev",
|
|
191
|
+
kind: "button",
|
|
192
|
+
domain: "character",
|
|
193
|
+
context: "gameplay",
|
|
194
|
+
bindings: { keys: ["BracketLeft"], pad: "bumperL" },
|
|
195
|
+
label: "Previous equip",
|
|
196
|
+
description: "Cycle the active ability/equip slot back (1-9). Slot state is game-side \u2014 worlds/abilities consume this",
|
|
197
|
+
touch: "none"
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
id: "melee",
|
|
201
|
+
kind: "button",
|
|
202
|
+
domain: "character",
|
|
203
|
+
context: "gameplay",
|
|
204
|
+
bindings: { keys: ["KeyV"], pad: "stickR" },
|
|
205
|
+
label: "Melee",
|
|
206
|
+
description: "Melee strike. No built-in behavior \u2014 worlds/abilities consume it",
|
|
207
|
+
touch: "button"
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
id: "emote",
|
|
211
|
+
kind: "button",
|
|
212
|
+
domain: "character",
|
|
213
|
+
context: "gameplay",
|
|
214
|
+
bindings: { keys: ["KeyG"], pad: "dpadDown" },
|
|
215
|
+
label: "Emote",
|
|
216
|
+
description: "Emote/gesture. No built-in behavior yet \u2014 reserved for the future emote system",
|
|
217
|
+
touch: "button"
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
id: "zoom",
|
|
221
|
+
kind: "delta",
|
|
222
|
+
domain: "character",
|
|
223
|
+
context: "gameplay",
|
|
224
|
+
bindings: { wheel: "y", deltaRate: 1200, withModifier: { stick: "rightStick" } },
|
|
225
|
+
label: "Zoom",
|
|
226
|
+
description: "Camera zoom delta (wheel px; pinch on touch; hold modifier + right stick on pad \u2014 forward zooms in). Positive = zoom out",
|
|
227
|
+
touch: "pinch"
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
id: "modifier",
|
|
231
|
+
kind: "button",
|
|
232
|
+
domain: "character",
|
|
233
|
+
context: "gameplay",
|
|
234
|
+
bindings: { pad: "dpadRight" },
|
|
235
|
+
label: "Modifier",
|
|
236
|
+
description: "Held chord layer: while down, withModifier bindings resolve (zoom on the right stick) and their sources go quiet for their normal owners",
|
|
237
|
+
touch: "hold"
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
id: "cameraMode",
|
|
241
|
+
kind: "button",
|
|
242
|
+
domain: "character",
|
|
243
|
+
context: "gameplay",
|
|
244
|
+
bindings: { keys: ["KeyT"], pad: "dpadLeft" },
|
|
245
|
+
label: "Camera",
|
|
246
|
+
description: "Cycle the camera: first-person \u2192 third-person \u2192 shoulder right \u2192 shoulder left. allowModeToggle gates the FP\u2194TP legs, allowShoulderSwap the shoulder legs; all-gated = inert",
|
|
247
|
+
touch: "button"
|
|
248
|
+
},
|
|
249
|
+
// ---- world / system (worlds opt in via registerStandardActions) ----
|
|
250
|
+
{
|
|
251
|
+
// Not Escape — the SDK owns Escape (tablet overlay) and pointer-lock exit rides it at browser level.
|
|
252
|
+
id: "pause",
|
|
253
|
+
kind: "button",
|
|
254
|
+
domain: "world",
|
|
255
|
+
context: "gameplay",
|
|
256
|
+
bindings: { keys: ["KeyP"], pad: "start" },
|
|
257
|
+
label: "Pause",
|
|
258
|
+
description: "Open the pause/system menu",
|
|
259
|
+
touch: "button"
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
id: "inventory",
|
|
263
|
+
kind: "button",
|
|
264
|
+
domain: "world",
|
|
265
|
+
context: "gameplay",
|
|
266
|
+
bindings: { keys: ["Tab", "KeyI"], pad: "select" },
|
|
267
|
+
label: "Inventory",
|
|
268
|
+
description: "Open the inventory (worlds push the menu context)",
|
|
269
|
+
touch: "button"
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
id: "map",
|
|
273
|
+
kind: "button",
|
|
274
|
+
domain: "world",
|
|
275
|
+
context: "gameplay",
|
|
276
|
+
bindings: { keys: ["KeyM"] },
|
|
277
|
+
label: "Map",
|
|
278
|
+
description: "Toggle the map/overview",
|
|
279
|
+
touch: "button"
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
// Keyboard PTT stays SDK-side (the reserved KeyB / pttKey listener — pointer-lock focus lives in
|
|
283
|
+
// the iframe); this action is the pad/touch leg. attachVoice registers it and forwards to setPttDown.
|
|
284
|
+
id: "voicePTT",
|
|
285
|
+
kind: "button",
|
|
286
|
+
domain: "world",
|
|
287
|
+
context: "global",
|
|
288
|
+
bindings: { withModifier: { pad: "bumperR" } },
|
|
289
|
+
label: "Push to talk",
|
|
290
|
+
description: "Hold to talk in PTT voice mode (modifier + right bumper on pad; keyboard uses the SDK pttKey, default B). Global context \u2014 keeps working under menus. Auto-registered when the world attaches voice",
|
|
291
|
+
touch: "hold"
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
id: "confirm",
|
|
295
|
+
kind: "button",
|
|
296
|
+
domain: "world",
|
|
297
|
+
context: "menu",
|
|
298
|
+
bindings: { keys: ["Enter", "Space"], pad: "faceDown" },
|
|
299
|
+
label: "Confirm",
|
|
300
|
+
description: "Accept the focused menu item",
|
|
301
|
+
touch: "tap"
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
id: "cancel",
|
|
305
|
+
kind: "button",
|
|
306
|
+
domain: "world",
|
|
307
|
+
context: "menu",
|
|
308
|
+
bindings: { keys: ["Backspace"], pad: "faceRight" },
|
|
309
|
+
label: "Cancel",
|
|
310
|
+
description: "Back out of the current menu level",
|
|
311
|
+
touch: "button"
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
// Right stick: 'look' is gameplay-context so the stick is free in menus — the "look becomes
|
|
315
|
+
// navigate" handoff, mirroring how pointer lock releases when a menu opens.
|
|
316
|
+
id: "uiNavigate",
|
|
317
|
+
kind: "vec2",
|
|
318
|
+
domain: "world",
|
|
319
|
+
context: "menu",
|
|
320
|
+
bindings: { composite: { up: ["ArrowUp"], down: ["ArrowDown"], left: ["ArrowLeft"], right: ["ArrowRight"] }, stick: "rightStick" },
|
|
321
|
+
label: "Navigate",
|
|
322
|
+
description: "Move the menu focus",
|
|
323
|
+
touch: "swipe"
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
id: "tabPrev",
|
|
327
|
+
kind: "button",
|
|
328
|
+
domain: "world",
|
|
329
|
+
context: "menu",
|
|
330
|
+
bindings: { keys: ["KeyQ"], pad: "bumperL" },
|
|
331
|
+
label: "Previous tab",
|
|
332
|
+
description: "Cycle menu tabs left",
|
|
333
|
+
touch: "swipe"
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
id: "tabNext",
|
|
337
|
+
kind: "button",
|
|
338
|
+
domain: "world",
|
|
339
|
+
context: "menu",
|
|
340
|
+
bindings: { keys: ["KeyE"], pad: "bumperR" },
|
|
341
|
+
label: "Next tab",
|
|
342
|
+
description: "Cycle menu tabs right",
|
|
343
|
+
touch: "swipe"
|
|
344
|
+
}
|
|
345
|
+
];
|
|
346
|
+
var byId = new Map(STANDARD_ACTIONS.map((a) => [a.id, a]));
|
|
347
|
+
var STANDARD_CHARACTER_ACTION_IDS = STANDARD_ACTIONS.filter((a) => a.domain === "character").map((a) => a.id);
|
|
348
|
+
|
|
37
349
|
// src/bundle/abilityManifest.ts
|
|
38
350
|
var ABILITY_ID_PATTERN = "^[a-z0-9](?:[a-z0-9-]{1,48})[a-z0-9]$";
|
|
39
351
|
var SEMVER_PATTERN = "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-[0-9A-Za-z.-]+)?$";
|
|
@@ -243,15 +555,22 @@ function validateAbilityManifest(value) {
|
|
|
243
555
|
issues.push({ path, message: `must be an object (got ${typeName(action)})` });
|
|
244
556
|
return;
|
|
245
557
|
}
|
|
246
|
-
const
|
|
558
|
+
const isStandard = typeof action.id === "string" && STANDARD_CHARACTER_ACTION_IDS.includes(action.id);
|
|
559
|
+
const actionId = isStandard ? action.id : checkQualifiedName(action.id, `${path}.id`, issues, id, "action");
|
|
247
560
|
if (actionId !== void 0) {
|
|
248
561
|
if (actionIds.includes(actionId)) issues.push({ path: `${path}.id`, message: `duplicate action id '${actionId}'` });
|
|
249
562
|
actionIds.push(actionId);
|
|
250
563
|
}
|
|
564
|
+
if (isStandard && action.kind !== void 0) {
|
|
565
|
+
issues.push({ path: `${path}.kind`, message: `standard action '${actionId}' takes its kind from the platform registry \u2014 omit kind` });
|
|
566
|
+
}
|
|
567
|
+
if (isStandard && action.defaultBinding !== void 0) {
|
|
568
|
+
issues.push({ path: `${path}.defaultBinding`, message: `standard action '${actionId}' takes its bindings from the platform registry \u2014 omit defaultBinding` });
|
|
569
|
+
}
|
|
251
570
|
if (action.kind !== void 0 && (typeof action.kind !== "string" || !["button", "toggle", "vec2"].includes(action.kind))) {
|
|
252
571
|
issues.push({ path: `${path}.kind`, message: "must be one of: button, toggle, vec2" });
|
|
253
572
|
}
|
|
254
|
-
if (action.defaultBinding !== void 0) checkBindings(action.defaultBinding, `${path}.defaultBinding`, issues);
|
|
573
|
+
if (!isStandard && action.defaultBinding !== void 0) checkBindings(action.defaultBinding, `${path}.defaultBinding`, issues);
|
|
255
574
|
for (const key of Object.keys(action)) {
|
|
256
575
|
if (!["id", "kind", "defaultBinding"].includes(key)) issues.push({ path: `${path}.${key}`, message: "unknown field (allowed: id, kind, defaultBinding)" });
|
|
257
576
|
}
|
|
@@ -371,7 +690,10 @@ var ABILITY_V1_JSON_SCHEMA = {
|
|
|
371
690
|
required: ["schemaVersion", "id", "version", "title", "system", "activation", "configSchema", "entry"],
|
|
372
691
|
properties: {
|
|
373
692
|
$schema: { type: "string", description: "Editor convenience \u2014 ignored by the validator." },
|
|
374
|
-
schemaVersion: {
|
|
693
|
+
schemaVersion: {
|
|
694
|
+
const: 1,
|
|
695
|
+
description: "Payload schema version. Post-freeze changes bump this (ability-v2), never edit v1. One deliberate pre-public exception (2026-07-20): bare STANDARD character action ids became legal in `actions` \u2014 a backward-compatible loosening (every previously-valid manifest still validates). The freeze is absolute once the platform is public."
|
|
696
|
+
},
|
|
375
697
|
id: {
|
|
376
698
|
type: "string",
|
|
377
699
|
pattern: ABILITY_ID_PATTERN,
|
|
@@ -459,7 +781,10 @@ var ABILITY_V1_JSON_SCHEMA = {
|
|
|
459
781
|
additionalProperties: false,
|
|
460
782
|
required: ["id"],
|
|
461
783
|
properties: {
|
|
462
|
-
id: {
|
|
784
|
+
id: {
|
|
785
|
+
type: "string",
|
|
786
|
+
description: "Qualified action id '<abilityId>.<action>' (e.g. 'fly.toggle') \u2014 or a bare STANDARD character action id (e.g. 'primary', 'reload'): the platform registry then owns kind + bindings, so omit both fields."
|
|
787
|
+
},
|
|
463
788
|
kind: { enum: ["button", "toggle", "vec2"], default: "button", description: "Action kind (mirrors the system input service)." },
|
|
464
789
|
defaultBinding: {
|
|
465
790
|
type: "object",
|
|
@@ -526,7 +851,7 @@ var ABILITY_V1_JSON_SCHEMA = {
|
|
|
526
851
|
|
|
527
852
|
// src/core/identity.ts
|
|
528
853
|
var SYSTEM_ID = "humanoid-character";
|
|
529
|
-
var SYSTEM_VERSION = "0.2.
|
|
854
|
+
var SYSTEM_VERSION = "0.2.7";
|
|
530
855
|
var SKELETON_STANDARD = "helix-humanoid@1";
|
|
531
856
|
var SYSTEM_IDENTITY = { id: SYSTEM_ID, version: SYSTEM_VERSION, skeleton: SKELETON_STANDARD };
|
|
532
857
|
export {
|