@helix3/helix-cli 0.1.11-helix3.50 → 0.1.13-helix3.100
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/README.md +264 -3
- package/assets/item-def-sounds/Common/A_DryShot.ogg +0 -0
- package/assets/item-def-sounds/Common/A_LMG_CloseCoverA.ogg +0 -0
- package/assets/item-def-sounds/Common/A_LMG_CloseCoverB.ogg +0 -0
- package/assets/item-def-sounds/Common/A_LMG_InsertMag.ogg +0 -0
- package/assets/item-def-sounds/Common/A_LMG_RemoveMag.ogg +0 -0
- package/assets/item-def-sounds/Common/A_Pistol_InsertMag_001.ogg +0 -0
- package/assets/item-def-sounds/Common/A_Pistol_InsertMag_002.ogg +0 -0
- package/assets/item-def-sounds/Common/A_Pistol_InsertMag_003.ogg +0 -0
- package/assets/item-def-sounds/Common/A_Pistol_RemoveMag_001.ogg +0 -0
- package/assets/item-def-sounds/Common/A_Pistol_RemoveMag_002.ogg +0 -0
- package/assets/item-def-sounds/Common/A_Pistol_RemoveMag_003.ogg +0 -0
- package/assets/item-def-sounds/Common/A_Rifle_ChargingHandle_001.ogg +0 -0
- package/assets/item-def-sounds/Common/A_Rifle_ChargingHandle_002.ogg +0 -0
- package/assets/item-def-sounds/Common/A_Rifle_ChargingHandle_003.ogg +0 -0
- package/assets/item-def-sounds/Common/A_Rifle_InsertMag_001.ogg +0 -0
- package/assets/item-def-sounds/Common/A_Rifle_InsertMag_002.ogg +0 -0
- package/assets/item-def-sounds/Common/A_Rifle_InsertMag_003.ogg +0 -0
- package/assets/item-def-sounds/Common/A_Rifle_RemoveMag_001.ogg +0 -0
- package/assets/item-def-sounds/Common/A_Rifle_RemoveMag_002.ogg +0 -0
- package/assets/item-def-sounds/Common/A_Rifle_RemoveMag_003.ogg +0 -0
- package/assets/item-def-sounds/Common/A_SMG_ChargingHandle_001.ogg +0 -0
- package/assets/item-def-sounds/Common/A_SMG_ChargingHandle_002.ogg +0 -0
- package/assets/item-def-sounds/Common/A_SMG_ChargingHandle_003.ogg +0 -0
- package/assets/item-def-sounds/Common/A_Sniper_ChargingHandle.ogg +0 -0
- package/assets/item-def-sounds/Common/A_Sniper_RemoveMag_001.ogg +0 -0
- package/assets/item-def-sounds/Common/A_Sniper_RemoveMag_002.ogg +0 -0
- package/assets/item-def-sounds/Common/A_Sniper_RemoveMag_003.ogg +0 -0
- package/assets/item-def-sounds/LMG/A_LWS-32_Shot_001.ogg +0 -0
- package/assets/item-def-sounds/LMG/A_LWS-32_Shot_002.ogg +0 -0
- package/assets/item-def-sounds/LMG/A_LWS-32_Shot_003.ogg +0 -0
- package/assets/item-def-sounds/Pistol/A_Gaston_Shot_001.ogg +0 -0
- package/assets/item-def-sounds/Pistol/A_Gaston_Shot_002.ogg +0 -0
- package/assets/item-def-sounds/Pistol/A_Gaston_Shot_003.ogg +0 -0
- package/assets/item-def-sounds/Rifle/A_KAL_Shot_001.ogg +0 -0
- package/assets/item-def-sounds/Rifle/A_KAL_Shot_002.ogg +0 -0
- package/assets/item-def-sounds/Rifle/A_KAL_Shot_003.ogg +0 -0
- package/assets/item-def-sounds/SMG/A_Bison_InsertMag.ogg +0 -0
- package/assets/item-def-sounds/SMG/A_Bison_RemoveMag.ogg +0 -0
- package/assets/item-def-sounds/SMG/A_Bison_Shot_001.ogg +0 -0
- package/assets/item-def-sounds/SMG/A_Bison_Shot_002.ogg +0 -0
- package/assets/item-def-sounds/SMG/A_Bison_Shot_003.ogg +0 -0
- package/assets/item-def-sounds/Shotgun/A_DB-12_Shot_001.ogg +0 -0
- package/assets/item-def-sounds/Shotgun/A_DB-12_Shot_002.ogg +0 -0
- package/assets/item-def-sounds/Shotgun/A_DB-12_Shot_003.ogg +0 -0
- package/assets/item-def-sounds/Sniper/A_CS-446_Shot_001.ogg +0 -0
- package/assets/item-def-sounds/Sniper/A_CS-446_Shot_002.ogg +0 -0
- package/assets/item-def-sounds/Sniper/A_CS-446_Shot_003.ogg +0 -0
- package/dist/achievement.d.ts +123 -0
- package/dist/achievement.js +400 -0
- package/dist/achievement.js.map +1 -0
- package/dist/api.d.ts +2 -0
- package/dist/api.js +25 -0
- package/dist/api.js.map +1 -1
- package/dist/assets.d.ts +556 -0
- package/dist/assets.js +1085 -0
- package/dist/assets.js.map +1 -0
- package/dist/audioCommand.d.ts +65 -0
- package/dist/audioCommand.js +181 -0
- package/dist/audioCommand.js.map +1 -0
- package/dist/bundle.d.ts +6 -0
- package/dist/bundle.js +68 -5
- package/dist/bundle.js.map +1 -1
- package/dist/character/fbx.d.ts +6 -0
- package/dist/character/fbx.js +50 -0
- package/dist/character/fbx.js.map +1 -0
- package/dist/character/importCharacter.d.ts +18 -0
- package/dist/character/importCharacter.js +85 -10
- package/dist/character/importCharacter.js.map +1 -1
- package/dist/character/meshyToHelixMap.d.ts +10 -0
- package/dist/character/meshyToHelixMap.js +92 -1
- package/dist/character/meshyToHelixMap.js.map +1 -1
- package/dist/character/stages/retargetClip.d.ts +6 -2
- package/dist/character/stages/retargetClip.js +53 -14
- package/dist/character/stages/retargetClip.js.map +1 -1
- package/dist/config.js +17 -3
- package/dist/config.js.map +1 -1
- package/dist/currency.js +4 -1
- package/dist/currency.js.map +1 -1
- package/dist/dev/devServer.d.ts +53 -0
- package/dist/dev/devServer.js +228 -0
- package/dist/dev/devServer.js.map +1 -0
- package/dist/dev/shellPage.d.ts +3 -0
- package/dist/dev/shellPage.js +297 -0
- package/dist/dev/shellPage.js.map +1 -0
- package/dist/dev/state.d.ts +84 -0
- package/dist/dev/state.js +265 -0
- package/dist/dev/state.js.map +1 -0
- package/dist/distribution.d.ts +51 -0
- package/dist/distribution.js +110 -0
- package/dist/distribution.js.map +1 -0
- package/dist/gesture/inspect.d.ts +4 -0
- package/dist/gesture/inspect.js +40 -12
- package/dist/gesture/inspect.js.map +1 -1
- package/dist/gesture/worldRuntime.d.ts +5 -0
- package/dist/gesture/worldRuntime.js +19 -1
- package/dist/gesture/worldRuntime.js.map +1 -1
- package/dist/glb/glb-summary.d.ts +1 -1
- package/dist/glb/glb-summary.js +84 -34
- package/dist/glb/glb-summary.js.map +1 -1
- package/dist/index.js +2447 -55
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +16 -1
- package/dist/init.js +492 -47
- package/dist/init.js.map +1 -1
- package/dist/item.d.ts +153 -0
- package/dist/item.js +523 -0
- package/dist/item.js.map +1 -0
- package/dist/itemDef/gunConfigRules.d.ts +24 -0
- package/dist/itemDef/gunConfigRules.js +244 -0
- package/dist/itemDef/gunConfigRules.js.map +1 -0
- package/dist/itemDef/inspect.d.ts +18 -0
- package/dist/itemDef/inspect.js +119 -0
- package/dist/itemDef/inspect.js.map +1 -0
- package/dist/itemDef/publish.d.ts +38 -0
- package/dist/itemDef/publish.js +178 -0
- package/dist/itemDef/publish.js.map +1 -0
- package/dist/itemDef/scaffold.d.ts +28 -0
- package/dist/itemDef/scaffold.js +165 -0
- package/dist/itemDef/scaffold.js.map +1 -0
- package/dist/itemDef/tables.d.ts +56 -0
- package/dist/itemDef/tables.js +169 -0
- package/dist/itemDef/tables.js.map +1 -0
- package/dist/itemDef/validate.d.ts +16 -0
- package/dist/itemDef/validate.js +93 -0
- package/dist/itemDef/validate.js.map +1 -0
- package/dist/itemQuote.d.ts +7 -0
- package/dist/itemQuote.js +38 -0
- package/dist/itemQuote.js.map +1 -0
- package/dist/lib.d.ts +534 -2
- package/dist/lib.js +819 -10
- package/dist/lib.js.map +1 -1
- package/dist/money.d.ts +183 -0
- package/dist/money.js +299 -0
- package/dist/money.js.map +1 -0
- package/dist/product.d.ts +84 -0
- package/dist/product.js +285 -0
- package/dist/product.js.map +1 -0
- package/dist/screenshot/staticServe.d.ts +8 -1
- package/dist/screenshot/staticServe.js +27 -6
- package/dist/screenshot/staticServe.js.map +1 -1
- package/dist/source-archive.d.ts +91 -0
- package/dist/source-archive.js +296 -0
- package/dist/source-archive.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/verifySubPath.d.ts +32 -0
- package/dist/verifySubPath.js +214 -0
- package/dist/verifySubPath.js.map +1 -0
- package/dist/voiceCommand.d.ts +11 -0
- package/dist/voiceCommand.js +101 -0
- package/dist/voiceCommand.js.map +1 -0
- package/dist/world/analyze.d.ts +6 -1
- package/dist/world/analyze.js +94 -0
- package/dist/world/analyze.js.map +1 -1
- package/dist/world/baseline.js +7 -0
- package/dist/world/baseline.js.map +1 -1
- package/package.json +8 -3
- package/vendor/ability-manifest.mjs +4 -4
- package/vendor/audits/asset-credits.mjs +96 -0
- package/vendor/audits/check-loaders.mjs +80 -0
- package/vendor/audits/perf-gate.mjs +759 -0
- package/vendor/audits/prove-live.mjs +307 -0
- package/vendor/audits/source-audit.mjs +517 -0
- package/vendor/audits/world-audit.mjs +439 -0
- package/vendor/installed-index.mjs +1 -1
package/README.md
CHANGED
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
backend. It shares bundle validation with the server via `@hypersoniclabs/helix-manifest`, so "validate passed but
|
|
5
5
|
publish failed" can't happen for contract reasons.
|
|
6
6
|
|
|
7
|
+
## Architecture boundary
|
|
8
|
+
|
|
9
|
+
All creator feature and operational logic, validation, file mutation, network behavior, and tests
|
|
10
|
+
live here. MCP packages may expose transport schemas, resources, instructions, and thin delegation
|
|
11
|
+
to these commands, but must not reimplement this logic.
|
|
12
|
+
|
|
7
13
|
## Install
|
|
8
14
|
|
|
9
15
|
```bash
|
|
@@ -35,8 +41,24 @@ The token is stored in `~/.helix/credentials.json` (mode `600`). It's sent as
|
|
|
35
41
|
| `helix init <dir>` | Scaffold a minimal Three.js world (`helix.json` + `index.html` + `main.js`). |
|
|
36
42
|
| `helix install [--update]` | Resolve a world's `systems`/`abilities` pins (a v0.2 **or v0.3** manifest) → materialize the modules, the `three` import map, and `helix.runtime.ts`. |
|
|
37
43
|
| `helix validate [dir]` | Validate a bundle locally — the exact rules the server enforces. |
|
|
38
|
-
| `helix publish [dir]` | Validate → resolve/create the world → upload files → finalize → print the play URL. |
|
|
44
|
+
| `helix publish [dir] [--thumbnail <file>] [--upload-source] [--source-dir <path>]` | Validate → resolve/create the world → upload files → finalize → set the cover image → print the play URL. `--upload-source` additionally sends the project's source through a separate private channel so the world can be edited on the website later — **off by default**. |
|
|
39
45
|
| `helix list` | List your worlds. |
|
|
46
|
+
| `helix item list-slots [--json]` | Print the Character-Creator vocabulary a wearable declares: the cosmetic slot tags, and the genders. |
|
|
47
|
+
| `helix item publish <mesh.glb> --title <t> [--collectible-supply <n>] [initial distribution flags] [--dry-run\|--quote]` | Publish a Standard item by default, or one fixed-supply Collectible. The item definition is separate from acquisition routes. |
|
|
48
|
+
| `helix item distribution create\|list\|update\|disable …` | Manage Marketplace/World Claim or Buy routes without republishing the item or paying another publish fee. |
|
|
49
|
+
| `helix preview-video <slug> <youtube-url>` | Set or clear a published world's YouTube preview. |
|
|
50
|
+
| `helix thumbnail set <slug> <file>` | Upload a thumbnail or preview image through the CLI-owned media path. |
|
|
51
|
+
| `helix assets search\|get\|versions\|track\|install\|update` | Search the typed Vault with explainable ranking; inspect/manage annotations and immutable versions; install by durable ID with verified SHA-256 receipts. Material installs default to lean runtime KTX2 maps; use `--material-renditions source` for source PNGs or `all` for both families. |
|
|
52
|
+
| `helix assets start\|status\|generate\|resume` | Start or poll generation without duplicates. Props/characters use the main Dreamer path; standalone assets use the shared broker and report the auto-published `vaultAssetId`. `generate` and `resume` block waiting for the job (see `--timeout`/`--poll-interval` below). |
|
|
53
|
+
| `helix assets voices [--search <text>] [--category premade\|professional] [--page-size <n>] [--page-token <token>] [--json]` | Discover safe text-to-speech voices through the authenticated HELIX catalog, including language, labels, preview, default/recommended selection, and pagination. |
|
|
54
|
+
| `helix assets generate-image\|generate-material\|generate-audio\|generate-environment` | Run the supported standalone generation adapters. Material is a validated PBR bundle (1K default, explicit 2K); splats declare object/environment scope. Animation remains an explicit unavailable boundary. |
|
|
55
|
+
| `helix assets start-reference\|generate-reference` | Start or fully drive a character job from a local four-view PNG/JPEG/WebP. The backend validates and reuses the exact sheet; it skips image generation while preserving mesh, texture, rig, LOD, thumbnail, billing, and Vault publication. `generate-reference` blocks waiting for the job (see `--timeout`/`--poll-interval` below). |
|
|
56
|
+
| `helix assets generate\|generate-reference\|resume [--timeout <ms>] [--poll-interval <ms>]` | These three drive a Dreamer prop/character job to completion (concept → mesh → texture → rig → publish) and block until it finishes. `--timeout` bounds how long the CLI process waits before giving up (default **1200000ms / 20min**, unchanged if omitted); `--poll-interval` sets how often it checks job status while waiting (default **2000ms**). A timeout is a CLIENT-SIDE giveup, not a job failure — the Dreamer job keeps running server-side. The error prints the exact `helix assets resume <job-id>` command to check on or continue it; on a genuinely slow stage (e.g. mesh generation), rerun with a larger `--timeout`, or just poll separately with `helix assets status <job-id> --pipeline dreamer`. |
|
|
57
|
+
| `helix assets materials [--resolution <res>] [--human]` | Discover the small built-in material palette. `--resolution` keeps only materials carrying that texture resolution. |
|
|
58
|
+
| `helix assets material <id> [--resolution <res>] [--human]` | Resolve one material to its immutable map URLs at the resolution you pick (default: the pack's own default). |
|
|
59
|
+
| `helix assets credits\|check-loaders` | Render asset credits from provenance and reject models requiring unsupported loaders. |
|
|
60
|
+
| `helix character retarget-animation <clip.fbx\|clip.glb>` | Retarget a raw Mixamo/Meshy clip directly to `helix-humanoid@1`. FBX conversion is deterministic and runs inside the CLI; no hidden Blender/DCC pre-export is required. |
|
|
61
|
+
| `helix world audit\|source-audit\|perf-gate\|prove-live` | Run the blocking world QA, performance, and deployed-build identity gates. |
|
|
40
62
|
| `helix doctor [--project <dir>]` | Print the environment + whether the @helix toolchain (CLI/MCP/SDK/manifest) is current. |
|
|
41
63
|
|
|
42
64
|
## Publish flow
|
|
@@ -51,8 +73,247 @@ The token is stored in `~/.helix/credentials.json` (mode `600`). It's sent as
|
|
|
51
73
|
5. `POST /api/v1/instant-worlds/:id/builds/:buildId/finalize` → byte-exact verify, activate, publish.
|
|
52
74
|
6. `GET /api/v1/instant-worlds/:slug` → the play URL.
|
|
53
75
|
|
|
54
|
-
|
|
55
|
-
|
|
76
|
+
### Opt-in source upload
|
|
77
|
+
|
|
78
|
+
A published world ships only its **built bundle**, so there is nothing on the server to edit later.
|
|
79
|
+
`--upload-source` adds a second, separate upload that fixes that:
|
|
80
|
+
|
|
81
|
+
7. `POST /api/v1/instant-worlds/:id/source` → a presigned PUT into a **private** bucket (this call
|
|
82
|
+
also adopts the world into a project, which is the key its future workspace hangs from).
|
|
83
|
+
8. `helix-source.tar.gz` PUT with `cache-control: no-store`.
|
|
84
|
+
9. `POST /api/v1/instant-worlds/:id/source/finalize` → the server verifies the stored byte count
|
|
85
|
+
equals the declared one, then records the version.
|
|
86
|
+
|
|
87
|
+
- **Off by default.** Source is never sent unless you pass the flag. Not a prompt — an interactive
|
|
88
|
+
confirm would break CI and agent-driven publishes.
|
|
89
|
+
- **What goes in**: the project directory, honouring `.gitignore`, always excluding `node_modules`,
|
|
90
|
+
`.git`, `dist` and `.vite` — the same exclude set the website's own workspace checkpoints use.
|
|
91
|
+
- **Which directory**: `[dir]` is the BUILT bundle, so the source defaults to its parent. Override
|
|
92
|
+
with `--source-dir <path>`.
|
|
93
|
+
- **Never part of the build.** The bundle's content-type allowlist rejects archives, raw `.ts` is
|
|
94
|
+
excluded from a bundle by design, the bundle size budget is the playable budget, and every build
|
|
95
|
+
file lands on a public CDN path with a year-long immutable cache. Source uses its own private
|
|
96
|
+
channel for exactly that reason.
|
|
97
|
+
- **Limit**: 128 MiB compressed, checked locally before anything is uploaded.
|
|
98
|
+
|
|
99
|
+
The programmatic surface (`publishWorld`, `checkBundle`, `whoAmI`, …) is exported for other CLI
|
|
100
|
+
modules. Agent integrations should instruct or delegate to the `helix` commands above rather than
|
|
101
|
+
reimplementing operational behavior in a transport package.
|
|
102
|
+
|
|
103
|
+
## Vault lifecycle
|
|
104
|
+
|
|
105
|
+
Use the durable Vault UUID as the handle. Search results include independent lexical, hard-filter,
|
|
106
|
+
measured-performance, reuse, and availability explanations; they do not collapse those signals into
|
|
107
|
+
a made-up score. `helix assets install` resolves an immutable version, follows the `/download`
|
|
108
|
+
indirection, verifies its server checksum and byte count, installs related material maps, and writes
|
|
109
|
+
`public/helix.assets.json`. Material installs keep the descriptor and default to the runtime KTX2
|
|
110
|
+
map family only; choose source PNGs with `--material-renditions source`, or both families with
|
|
111
|
+
`--material-renditions all`. Reinstalling with a different selection removes the stale opposite
|
|
112
|
+
family. Non-material assets keep their existing related-artifact behavior. For a reproducible agent build, pass `--asset-version`,
|
|
113
|
+
`--checksum-sha256`, and `--size-bytes` together; a partial pin or any metadata/download mismatch
|
|
114
|
+
fails before a provenance receipt is written.
|
|
115
|
+
|
|
116
|
+
Generation is source-agnostic at the backend:
|
|
117
|
+
|
|
118
|
+
- `prop` and `character` start through the main Dreamer route because they use its verified
|
|
119
|
+
universal-item flow.
|
|
120
|
+
- `image`, `material`, `audio`, and `gaussian_splat` start through the shared asset route.
|
|
121
|
+
Gaussian splats must declare `object` or `environment` scope.
|
|
122
|
+
- `animation` fails locally with `CAPABILITY_UNAVAILABLE`; it never starts a chargeable job.
|
|
123
|
+
|
|
124
|
+
Run `helix assets status <job-id> --pipeline dreamer|asset` to poll an existing job. A successful
|
|
125
|
+
default-on generation reports `vaultAssetId` and `vaultAutoPublish: "published"`; an explicit
|
|
126
|
+
creator opt-out reports `"disabled"`.
|
|
127
|
+
|
|
128
|
+
For `.helix-scene.json`, the open Vault catalog is not the scene-local budget. Reuse a small
|
|
129
|
+
material palette and instance repeated assets. The canonical ceilings are:
|
|
130
|
+
|
|
131
|
+
| Profile | Unique materials | Draw calls | Decoded texture memory | Triangles | Particles |
|
|
132
|
+
| --- | ---: | ---: | ---: | ---: | ---: |
|
|
133
|
+
| mobile | 48 | 300 | 256 MiB | 750,000 | 5,000 |
|
|
134
|
+
| desktop | 128 | 1,200 | 1 GiB | 4,000,000 | 50,000 |
|
|
135
|
+
| cinematic | 256 | 4,000 | 4 GiB | 15,000,000 | 250,000 |
|
|
136
|
+
|
|
137
|
+
These are publish-contract ceilings, not frame-rate promises; world runtime QA still applies.
|
|
138
|
+
|
|
139
|
+
The lifecycle acceptance harness intentionally has no CLI-local demo. Point it
|
|
140
|
+
at a built world in `helix-web-demo-worlds` that consumes the published SDK and
|
|
141
|
+
humanoid runtime:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
npm run qa:vault-lifecycle -- \
|
|
145
|
+
--world-template /path/to/helix-web-demo-worlds/worlds/sdk-showcase
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Publishing is an explicit release-only action and additionally requires a new
|
|
149
|
+
approved slug:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
npm run qa:vault-lifecycle -- \
|
|
153
|
+
--world-template /path/to/helix-web-demo-worlds/worlds/sdk-showcase \
|
|
154
|
+
--publish --world-slug ch1146-vault-lifecycle-qa-<unique-suffix>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
The publish receipt requires one usage increment, one world association, and
|
|
158
|
+
an idempotent second publish with no additional increment.
|
|
159
|
+
|
|
160
|
+
### Audio generation
|
|
161
|
+
|
|
162
|
+
All three audio modes use the same authenticated Dreamer route and automatically publish the
|
|
163
|
+
completed MP3 to Vault. The command waits up to 30 minutes so a ten-minute music request has enough
|
|
164
|
+
time to render, ingest, and publish. It prints the durable `vaultAssetId`, measured Spark charge,
|
|
165
|
+
provider cost, and server-stamped `billingEvidence`. It does not download another local copy unless
|
|
166
|
+
`--output` is supplied.
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
# Sound effect
|
|
170
|
+
helix assets generate-audio "heavy metal door slamming shut" \
|
|
171
|
+
--mode sound_effect --duration-seconds 3 --prompt-influence 0.4 --output door.mp3
|
|
172
|
+
|
|
173
|
+
# Music
|
|
174
|
+
helix assets generate-audio "hopeful orchestral exploration theme" \
|
|
175
|
+
--mode music --duration-seconds 180 --force-instrumental
|
|
176
|
+
|
|
177
|
+
# Text to speech
|
|
178
|
+
helix assets voices --search narrator --page-size 10
|
|
179
|
+
helix assets generate-audio --mode text_to_speech \
|
|
180
|
+
--text "Welcome to HELIX." --voice-id <id-from-catalog> \
|
|
181
|
+
--language-code en --stability 0.5 --speaker-boost
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Use the opaque `--page-token` printed by a page to continue. Voice cloning and
|
|
185
|
+
voice administration are deliberately not exposed.
|
|
186
|
+
|
|
187
|
+
Use a deterministic four-view sheet when you already have approved FRONT, BACK,
|
|
188
|
+
LEFT, and RIGHT character art and do not want Dreamer to generate another image:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
helix assets generate-reference ./character-four-views.png \
|
|
192
|
+
"compact friendly service robot, game-ready humanoid proportions" \
|
|
193
|
+
--title "Service Robot" \
|
|
194
|
+
--target-polycount 12000
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
The reference endpoint is character-only. The file is image-guarded, normalized,
|
|
198
|
+
checksum-bound to the job, semantically validated, and mirrored before approval.
|
|
199
|
+
Retries reuse those same bytes and never invoke or charge the image provider.
|
|
200
|
+
|
|
201
|
+
## Material texture resolution
|
|
202
|
+
|
|
203
|
+
A platform material can ship more than one texture resolution. `--resolution` picks which one you
|
|
204
|
+
get; without it you get the pack's declared default, byte-for-byte what every earlier CLI returned.
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
helix assets material brick-block # the pack's default resolution
|
|
208
|
+
helix assets material brick-block --resolution 2k # the 2K variant's map URLs
|
|
209
|
+
helix assets material brick-block --resolution 2048 # same thing — numeric spelling
|
|
210
|
+
helix assets materials --resolution 2k --human # only materials that carry 2K
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Accepted values are the keys the catalog itself declares (`1k`, `2k`, …), case-insensitively, plus
|
|
214
|
+
the numeric aliases `1024`/`2048`, which map onto the variant authored at that pixel edge.
|
|
215
|
+
|
|
216
|
+
Both commands print JSON by default (agents and the MCP delegation parse it); `--human` prints a
|
|
217
|
+
readable summary instead. Either way the output states **which resolution was resolved and which
|
|
218
|
+
ones the material offers**, under `resolution`:
|
|
219
|
+
|
|
220
|
+
```jsonc
|
|
221
|
+
"resolution": {
|
|
222
|
+
"requested": "2k", "resolved": "2k", "pixels": 2048, "default": "1k",
|
|
223
|
+
"available": [{ "key": "1k", "pixels": 1024 }, { "key": "2k", "pixels": 2048 }],
|
|
224
|
+
"applicable": true
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Three rules make this safe to rely on:
|
|
229
|
+
|
|
230
|
+
- **No silent fallback, ever.** Asking for a resolution the material does not carry is an error that
|
|
231
|
+
names the ones it does. You never receive a different resolution than the one you asked for.
|
|
232
|
+
- **Old packs keep working.** A catalog with no `resolutions` block (`schemaVersion: 1`) is treated
|
|
233
|
+
as having exactly one resolution, keyed `default`, derived from its existing `maps`. Such a pack
|
|
234
|
+
never claims to be "1k" — it does not say how big its textures are, so neither do we.
|
|
235
|
+
- **Procedural materials are not an error.** `glass` and `procedural_water` carry no texture maps;
|
|
236
|
+
a resolution request against them is ignored and the output says so in `resolution.note`.
|
|
237
|
+
|
|
238
|
+
`helix assets install` has no resolution flag: Vault related-artifact roles are semantic
|
|
239
|
+
(`source.albedo`, `runtime.ktx2.normal`, `sky.backdrop`), never resolution-tagged, so a filter there
|
|
240
|
+
would filter nothing.
|
|
241
|
+
|
|
242
|
+
## Item publish flow
|
|
243
|
+
|
|
244
|
+
`helix item publish` creates an item definition. It defaults to **Standard**: unlimited issuance,
|
|
245
|
+
no public serial, and no resale. `--collectible-supply N` is the only edition selector: it fixes a
|
|
246
|
+
positive supply, assigns public serials, makes instances Marketplace-resellable, and reserves
|
|
247
|
+
serial `#1` for the creator. There are no separate tradable, serial, giftable, personal, or
|
|
248
|
+
discoverability switches.
|
|
249
|
+
|
|
250
|
+
1. Local validation, before anything leaves the machine: the `--kind`, the Character-Creator
|
|
251
|
+
`--slot` and `--gender` (**both required** for a wearable, exact-match), the title/slug/tag
|
|
252
|
+
limits, and the GLB container magic. `--dry-run` stops here and prints exactly what would be
|
|
253
|
+
sent.
|
|
254
|
+
|
|
255
|
+
`--kind` accepts `wearable`, `avatar`, `prop`, and `home` — `prop` and `home` are the current
|
|
256
|
+
product names (see helixgame.com) for what the API still calls `home_item` and `home_shell`; both
|
|
257
|
+
spellings work identically and `helix item publish --kind prop …` sends the exact same
|
|
258
|
+
`"kind":"home_item"` on the wire as `--kind home_item …` does. This is a CLI-vocabulary alias only —
|
|
259
|
+
it is unrelated to the backend's separate `prop` universal-item kind (art/collectible items).
|
|
260
|
+
2. `--quote` asks the server for the definition publish fee, the creator tier's included free-
|
|
261
|
+
Collectible units, excess issuance authorization cost, creator serial `#1`, price floor and
|
|
262
|
+
resale policy. It uploads nothing and charges nothing.
|
|
263
|
+
3. `POST /api/v1/universal-items/upload` — `multipart/form-data` with a `mesh` file part, an
|
|
264
|
+
optional `thumbnail` file part, and the metadata as ONE JSON string in `payload`.
|
|
265
|
+
4. The server verifies the mesh **inline** (triangles, texture edges, materials, and — for a
|
|
266
|
+
wearable — whether it is a skinned garment or a rigid socketed accessory) and returns the
|
|
267
|
+
created item together with the verification verdict and warnings.
|
|
268
|
+
|
|
269
|
+
Price, world, schedule and limits live on a separate distribution. Price `0` means a shell-
|
|
270
|
+
confirmed **Claim**; a positive price means **Buy** and must meet the server-owned floor. A world
|
|
271
|
+
route also has a stable key, which world code passes to
|
|
272
|
+
`Helix.marketplace.purchaseDistributionKey(key)`. `--max-per-player unlimited` explicitly clears a
|
|
273
|
+
cap; free Collectibles default to one per player when omitted. Distribution changes never republish
|
|
274
|
+
the definition.
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
# Standard, free Marketplace Claim
|
|
278
|
+
helix item publish ./postcard.glb --title "Harbor Postcard"
|
|
279
|
+
helix item distribution create <item-id> --channel marketplace --price-lix 0
|
|
280
|
+
|
|
281
|
+
# Standard, paid World Buy
|
|
282
|
+
helix item distribution create <item-id> --channel world --world fishing-cove \
|
|
283
|
+
--key fishing_rod --price-lix 250 --max-per-player unlimited
|
|
284
|
+
|
|
285
|
+
# Collectible, free World Claim (creator receives #1 from the 500 fixed units)
|
|
286
|
+
helix item publish ./trophy.glb --title "Season One Trophy" --collectible-supply 500 \
|
|
287
|
+
--distribution-channel world --distribution-price-lix 0 --world tournament \
|
|
288
|
+
--distribution-key season_one --max-per-player 1 --quote
|
|
289
|
+
# Review the quote, then run the same command without --quote to publish.
|
|
290
|
+
|
|
291
|
+
# Collectible, paid Marketplace Buy
|
|
292
|
+
helix item publish ./bluefin.glb --title "Legendary Bluefin" --collectible-supply 10000
|
|
293
|
+
helix item distribution create <item-id> --channel marketplace --price-lix 500 --max-claims 9000
|
|
294
|
+
|
|
295
|
+
helix item distribution update <distribution-id> --price-lix 600 --ends-at 2026-12-01T00:00:00Z
|
|
296
|
+
helix item distribution disable <distribution-id>
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Collectible resale uses Marketplace escrow. The creator royalty is fixed at 5%; the launch seller
|
|
300
|
+
platform fee is 10% for Free and 5% for Plus (future Gold 2.5%, Diamond 0%). The buyer pays no
|
|
301
|
+
surcharge, creator self-sale omits a redundant royalty leg, and self-purchase is prohibited.
|
|
302
|
+
Every acquisition has one 24-hour relisting cooldown. Basic requires email; Verified means a unique
|
|
303
|
+
verified mobile plus good standing and may resell immediately subject to that cooldown. Identity Verified
|
|
304
|
+
is reserved for later high-risk capability, and tooling accepts future Business Verified. Payout holds are
|
|
305
|
+
separate: 3 days base, risk-extendable up to 15 days.
|
|
306
|
+
|
|
307
|
+
The slot table in `src/item.ts` MIRRORS `helix-backend-api → src/universal-items/cc-wearable-slot.ts`,
|
|
308
|
+
and the gender list mirrors `src/universal-items/cc-gender.ts` the same way. They are a local fast
|
|
309
|
+
path so a typo costs no upload; the server remains the authority and its 400 lists every valid
|
|
310
|
+
value. Adding a slot or a gender means editing both, in the same PR wave.
|
|
311
|
+
|
|
312
|
+
`--gender` takes `male`, `female`, or `male,female`, and is **required** for `--kind wearable`.
|
|
313
|
+
There is no `both`/`unisex`/`all`: Unreal's cosmetics enum has exactly Male and Female, so a garment
|
|
314
|
+
that fits every body names both — one HELIX row with `{male, female}` is the web equivalent of
|
|
315
|
+
Unreal's two entries sharing one mesh. The field goes on the wire as `genders`; `ccGenders` is the
|
|
316
|
+
database column and the backend rejects it by name rather than dropping it in silence.
|
|
56
317
|
|
|
57
318
|
## Develop
|
|
58
319
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/** 2–80 chars, lowercase letters/digits/`_`/`-`, starting alphanumeric. */
|
|
2
|
+
export declare const ACHIEVEMENT_KEY_PATTERN: RegExp;
|
|
3
|
+
/**
|
|
4
|
+
* WHO may award the badge — the trust marker a player and the platform UI read.
|
|
5
|
+
* `platform` is first-party code only; it is in the list because the backend
|
|
6
|
+
* accepts it, not because a world should use it (see `assertUnlockModeForWorld`).
|
|
7
|
+
*/
|
|
8
|
+
export declare const ACHIEVEMENT_UNLOCK_MODES: readonly ["room", "criteria", "platform"];
|
|
9
|
+
export type AchievementUnlockMode = (typeof ACHIEVEMENT_UNLOCK_MODES)[number];
|
|
10
|
+
export declare const ACHIEVEMENT_CRITERIA_SIGNALS: readonly ["datastore", "iwp", "analytics", "playtime"];
|
|
11
|
+
export type AchievementCriteriaSignal = (typeof ACHIEVEMENT_CRITERIA_SIGNALS)[number];
|
|
12
|
+
export declare const ACHIEVEMENT_CRITERIA_OPS: readonly ["gte", "lte", "eq"];
|
|
13
|
+
export type AchievementCriteriaOp = (typeof ACHIEVEMENT_CRITERIA_OPS)[number];
|
|
14
|
+
export declare const ACHIEVEMENT_CRITERIA_METRICS: readonly ["count", "lix"];
|
|
15
|
+
export type AchievementCriteriaMetric = (typeof ACHIEVEMENT_CRITERIA_METRICS)[number];
|
|
16
|
+
/**
|
|
17
|
+
* The only two documents a `datastore` criteria may read, and WHICH ONE IS THE
|
|
18
|
+
* TRUST DECISION: `mp:player:{userId}` is the room's flushed persistent
|
|
19
|
+
* playerVars (room-only writable ⇒ server-authoritative), `player:{userId}` is
|
|
20
|
+
* the player's own client-written save (forgeable by its owner, accepted
|
|
21
|
+
* deliberately — it is how a single-player world unlocks anything).
|
|
22
|
+
*/
|
|
23
|
+
export declare const DATA_STORE_CRITERIA_KEY_TEMPLATES: readonly ["player:{userId}", "mp:player:{userId}"];
|
|
24
|
+
export type DataStoreCriteriaKeyTemplate = (typeof DATA_STORE_CRITERIA_KEY_TEMPLATES)[number];
|
|
25
|
+
/** A `datastore` criteria's `field`: a dot-path of letters, digits and underscores. */
|
|
26
|
+
export declare const DATA_STORE_CRITERIA_FIELD_PATTERN: RegExp;
|
|
27
|
+
/** Backend caps (`ACHIEVEMENT_ICON_MAX_BYTES` / `ACHIEVEMENT_MESH_MAX_BYTES` defaults). */
|
|
28
|
+
export declare const ACHIEVEMENT_ICON_MAX_BYTES: number;
|
|
29
|
+
export declare const ACHIEVEMENT_TROPHY_MAX_BYTES: number;
|
|
30
|
+
/** Smallest square an icon can be and still read as a graphic on a plaque. */
|
|
31
|
+
export declare const MIN_ICON_EDGE = 16;
|
|
32
|
+
/**
|
|
33
|
+
* Per-channel standard deviation below which the backend treats an image as one
|
|
34
|
+
* flat colour. Not zero — a real icon that has been through lossy encoding
|
|
35
|
+
* carries a little noise.
|
|
36
|
+
*/
|
|
37
|
+
export declare const MIN_ICON_STDDEV = 1;
|
|
38
|
+
export declare const isAchievementKey: (value: unknown) => value is string;
|
|
39
|
+
/** Content type for the required `image` part — the 2D badge graphic. */
|
|
40
|
+
export declare function iconContentTypeFromExtension(file: string): string;
|
|
41
|
+
/**
|
|
42
|
+
* What the backend's `assertValidAchievementIcon` checks, mirrored so a
|
|
43
|
+
* placeholder fails in a second instead of after an upload + a moderation pass.
|
|
44
|
+
* The two rejections are the two placeholders creators actually send: an image
|
|
45
|
+
* too small to read, and a single flat colour. Deliberately NOT a quality
|
|
46
|
+
* judgement — a two-tone glyph or a flat logo on a plate passes.
|
|
47
|
+
*/
|
|
48
|
+
export declare function assertIconLooksReal(bytes: Uint8Array, file: string): Promise<void>;
|
|
49
|
+
export type AchievementCriteria = {
|
|
50
|
+
signal: AchievementCriteriaSignal;
|
|
51
|
+
op: AchievementCriteriaOp;
|
|
52
|
+
value: number;
|
|
53
|
+
eventName?: string;
|
|
54
|
+
key?: DataStoreCriteriaKeyTemplate;
|
|
55
|
+
field?: string;
|
|
56
|
+
metric?: AchievementCriteriaMetric;
|
|
57
|
+
};
|
|
58
|
+
export type AchievementCriteriaInput = {
|
|
59
|
+
signal?: string;
|
|
60
|
+
op?: string;
|
|
61
|
+
value?: number;
|
|
62
|
+
eventName?: string;
|
|
63
|
+
key?: string;
|
|
64
|
+
field?: string;
|
|
65
|
+
metric?: string;
|
|
66
|
+
};
|
|
67
|
+
/** True when any criteria field was supplied — i.e. the caller means `criteria`. */
|
|
68
|
+
export declare function hasCriteriaInput(input: AchievementCriteriaInput | undefined): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Validate + normalize the criteria the way the backend's `normalizeCriteria`
|
|
71
|
+
* does, and throw the same failures. Returns the exact object sent as the
|
|
72
|
+
* multipart `criteria` JSON string — no key the caller did not set.
|
|
73
|
+
*/
|
|
74
|
+
export declare function buildAchievementCriteria(input: AchievementCriteriaInput): AchievementCriteria;
|
|
75
|
+
/** One-line human summary of a stored criteria — the `list` column and the register echo. */
|
|
76
|
+
export declare function formatAchievementCriteria(criteria: AchievementCriteria | null | undefined): string;
|
|
77
|
+
export type AchievementRegistrationInput = {
|
|
78
|
+
key: string;
|
|
79
|
+
name: string;
|
|
80
|
+
description?: string;
|
|
81
|
+
points?: number;
|
|
82
|
+
hidden?: boolean;
|
|
83
|
+
unlockMode?: string;
|
|
84
|
+
criteria?: AchievementCriteriaInput;
|
|
85
|
+
};
|
|
86
|
+
export type AchievementRegistrationFields = {
|
|
87
|
+
key: string;
|
|
88
|
+
name: string;
|
|
89
|
+
description?: string;
|
|
90
|
+
points?: number;
|
|
91
|
+
hidden?: boolean;
|
|
92
|
+
unlockMode: AchievementUnlockMode;
|
|
93
|
+
criteria?: AchievementCriteria;
|
|
94
|
+
};
|
|
95
|
+
export type AchievementRegistrationPlan = {
|
|
96
|
+
fields: AchievementRegistrationFields;
|
|
97
|
+
warnings: string[];
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Resolve the trust marker. The backend's DTO defaults to `platform` because the
|
|
101
|
+
* ADMIN path (worldId omitted) is the one that needs it; for a WORLD
|
|
102
|
+
* registration `platform` is a mislabel — nothing in a world is first-party
|
|
103
|
+
* code. So this CLI always sends an explicit mode: `criteria` when a condition
|
|
104
|
+
* was declared, otherwise `room`, the only thing a world can actually award
|
|
105
|
+
* (the `awardAchievement` rule effect).
|
|
106
|
+
*/
|
|
107
|
+
export declare function resolveUnlockMode(explicit: string | undefined, hasCriteria: boolean): AchievementUnlockMode;
|
|
108
|
+
/**
|
|
109
|
+
* Build the multipart text fields, applying every local rule first. Keys the
|
|
110
|
+
* caller did not set are OMITTED rather than sent empty — an empty description
|
|
111
|
+
* and no description are the same row, and sending "" would overwrite nothing
|
|
112
|
+
* while looking like intent.
|
|
113
|
+
*/
|
|
114
|
+
export declare function buildAchievementRegistration(input: AchievementRegistrationInput): AchievementRegistrationPlan;
|
|
115
|
+
export type AchievementUpdateInput = {
|
|
116
|
+
name?: string;
|
|
117
|
+
description?: string;
|
|
118
|
+
points?: number;
|
|
119
|
+
hidden?: boolean;
|
|
120
|
+
active?: boolean;
|
|
121
|
+
};
|
|
122
|
+
/** Validate a PATCH body locally and refuse an empty one (a no-op round trip that reads as success). */
|
|
123
|
+
export declare function buildAchievementUpdate(input: AchievementUpdateInput): AchievementUpdateInput;
|