@hyprune/schema 0.6.0 → 0.7.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/CHANGELOG.md +113 -0
- package/README.md +53 -1
- package/bin/validate.mjs +14 -4
- package/examples/library-releases.json +11 -0
- package/examples/library.json +18 -0
- package/examples/object-character.json +69 -0
- package/examples/object-machine.json +338 -0
- package/examples/object-seat.json +59 -0
- package/examples/object.json +148 -0
- package/lib/validate.d.mts +23 -2
- package/lib/validate.mjs +446 -12
- package/package.json +1 -1
- package/v0.10/library.schema.json +93 -0
- package/v0.10/object.schema.json +1713 -0
- package/v0.21/focus-history.schema.json +82 -0
- package/v0.21/guidance.schema.json +118 -0
- package/v0.21/ipc.schema.json +15726 -0
- package/v0.21/quests-personal.schema.json +448 -0
- package/v0.22/ipc.schema.json +17466 -0
- package/v0.9/library-releases.schema.json +53 -0
- package/v0.9/library.schema.json +93 -0
- package/v0.9/object.schema.json +739 -0
package/CHANGELOG.md
CHANGED
|
@@ -185,3 +185,116 @@ definition exists in 0.16 and the graphics properties differ only by the new key
|
|
|
185
185
|
## @hyprune/schema 0.6.0 (2026-10-11)
|
|
186
186
|
|
|
187
187
|
Publishes IPC 0.20 and world format 0.8 to npm.
|
|
188
|
+
|
|
189
|
+
## Object manifests 0.9, libraries and the library release record (RFC-0011)
|
|
190
|
+
|
|
191
|
+
New contract files; no IPC or world format change (world formats stay 0.1–0.8).
|
|
192
|
+
Object manifests use the world format numbering: a world may use objects whose
|
|
193
|
+
`formatVersion` is at most its own.
|
|
194
|
+
|
|
195
|
+
- `v0.9/object.schema.json` (`object.json`): `id` (slug, equals the directory
|
|
196
|
+
name), SemVer `version`, `name`, `category`, `tags`, a directory-relative
|
|
197
|
+
`scene`, `license` + `attribution`, rest-pose `bounds`, optional `thumbnail`
|
|
198
|
+
and `lighting`, `traits` and optional `slots`. Traits: `decorative` (0.8 node
|
|
199
|
+
animations), `collidable` (0.8 proxy), `movable` (`surfaces`, `upright`,
|
|
200
|
+
`scale`), `character` (measured `clips` with `walk` and `idle`, `height`,
|
|
201
|
+
`radius`, `accent`, asset-level `say`/`panel` interactions) and `seat`
|
|
202
|
+
(anchors, `capacity`). `mover`, `machine`, `mount` and `interactive` are
|
|
203
|
+
reserved and rejected with a reason. Slots `states`, `labels`, `spawns` and
|
|
204
|
+
`effects` (at most 8 each) are validated and inert.
|
|
205
|
+
- `v0.9/library.schema.json` (`library.json`): reverse-domain `id`, `version`,
|
|
206
|
+
`name`, `license` + `attribution` and 1–256 listed `objects`.
|
|
207
|
+
- `v0.9/library-releases.schema.json`: the meta repository's
|
|
208
|
+
`libraries/releases.json`, one record per `id@version` (`id`, `version`,
|
|
209
|
+
`formatVersion`, `url`, `sha256`, `nixHash`, `published`).
|
|
210
|
+
- **Draft** `v0.10/object.schema.json` and `v0.10/library.schema.json`: 0.9 plus
|
|
211
|
+
the `mover` trait, RFC-0013's `machine` trait (typed `inputs` with `repeat`,
|
|
212
|
+
`drives` in the mapping language, `primary`, `positions`, `recipes`) and the
|
|
213
|
+
slot additions (`labels` font/align/colour/plate, `spawns` track/items/maxRate,
|
|
214
|
+
`effects` kind/colour/durationMs, new `tracks`, `stacks`, `toggles`, `ports`).
|
|
215
|
+
It may change until world format 0.10 is defined.
|
|
216
|
+
- `validate('object', manifest, undefined, format?, options)`: trait
|
|
217
|
+
combinations, origin conventions (floor, wall and ceiling within 1 cm; a
|
|
218
|
+
character's rest-pose feet within 5 cm), slot
|
|
219
|
+
ids, poses inside the bounds grown by 0.5 m, palettes, seat anchors, track
|
|
220
|
+
points and arcs, stack layouts, machine input references, drive targets and
|
|
221
|
+
output domains. With `options.gltf`: the format's glTF extension rules, node
|
|
222
|
+
names (unique, in the scene; the proxy may sit outside it), the 0.8 animation
|
|
223
|
+
and proxy rules, states-slot materials and nodes (one slot each),
|
|
224
|
+
`KHR_materials_variants` mappings (variant names of a states slot are palette
|
|
225
|
+
ids), character skins, clips and `extras.speed` (2%), triangle budgets
|
|
226
|
+
(50,000; characters 16,000; items 2,000; proxy 2,000) and bounds (exact for
|
|
227
|
+
axis-aligned meshes, else a containing box). `options.files`, `thumbnail`,
|
|
228
|
+
`measured` and `directory` add the directory limits, attribution coverage, the
|
|
229
|
+
256 x 256 thumbnail, the 1 cm bounds check and texture and GPU budgets.
|
|
230
|
+
Results carry `warnings`.
|
|
231
|
+
- `validate('library', manifest, undefined, format?, {objects, files})` and
|
|
232
|
+
`validate('library-releases', record)`. `objectFormats` and `objectLimits` are
|
|
233
|
+
exported. The CLI accepts `object` (with an optional glTF/GLB), `library` and
|
|
234
|
+
`library-releases`.
|
|
235
|
+
|
|
236
|
+
## IPC 0.21: markers, personal quests and focus sessions
|
|
237
|
+
|
|
238
|
+
- New grant `quest.control` (hello capabilities): every quest and focus mutation
|
|
239
|
+
and `guidance.set`.
|
|
240
|
+
- Required state keys: `markers {reveal, persistent, calm, coreDraw, list}`
|
|
241
|
+
(reveal `holdMs` 0 = toggle or 1000..15000, `fadeMs` 0..600; at most 64
|
|
242
|
+
markers with tier 1..4, labels up to 48 characters, one target of position,
|
|
243
|
+
zone, area, place or workspace), `quests {enabled, tracked, active[<=16],
|
|
244
|
+
counts, world: null}` and `focus {state, pausedState, sessionId,
|
|
245
|
+
phaseStartedAtMs, phaseEndsAtMs, phaseMs, remainingMs, creditedMs, crediting,
|
|
246
|
+
cycle, cycles, breakKind, countMode, target, calm}`. Times are monotonic ms.
|
|
247
|
+
- Methods: `markers.reveal {durationMs?}` (shell.control); `guidance.get`,
|
|
248
|
+
`guidance.set {patch}` returning `{config, defaults, overrides, ranges,
|
|
249
|
+
options, path, error}` over 21 flat dotted keys; `quests.list {states?,
|
|
250
|
+
sources?}`, `quests.get {questRef}`, `quests.track {questRef|null}`,
|
|
251
|
+
`quests.accept/abandon/resume/delete {questRef}`, `quests.create {quest}`
|
|
252
|
+
(`{revision, questRef}`), `quests.update {questRef, quest}`, `quests.mark
|
|
253
|
+
{questRef, stepId, objectiveId}`; `focus.start {target?, questRef?,
|
|
254
|
+
objectiveId?, overrides?}` (`{revision, sessionId}`),
|
|
255
|
+
`focus.pause/resume/skip/stop {}`, `focus.history {days?}` (at most 512
|
|
256
|
+
intervals). Personal quests: 1..16 steps, 1..8 `manual`, `reach` or `focus`
|
|
257
|
+
objectives per step.
|
|
258
|
+
- Events: `quest.progress` and `focus.phase` (`focusSessionId`; every event
|
|
259
|
+
carries the IPC `sessionId` and `revision`).
|
|
260
|
+
- `inputConfig` world mode gains `markers.reveal`; `overlayStyle` gains
|
|
261
|
+
required `questColor` (optional in the patch); `spatial.projection` markers
|
|
262
|
+
gain optional `markerId`.
|
|
263
|
+
- File schemas: `v0.21/quests-personal.schema.json`,
|
|
264
|
+
`v0.21/guidance.schema.json`, `v0.21/focus-history.schema.json`.
|
|
265
|
+
- Everything else is inherited from 0.20 unchanged; `session.hello` reports
|
|
266
|
+
`0.21`. Inheritance test included.
|
|
267
|
+
|
|
268
|
+
## IPC 0.22: object catalog, user placements and libraries (RFC-0011 P1)
|
|
269
|
+
|
|
270
|
+
- New grant `objects.control` (hello capabilities): every overlay change and
|
|
271
|
+
library install/remove.
|
|
272
|
+
- Required state key `objects {catalogRevision, instances[<=512], pocket[<=16],
|
|
273
|
+
usage, limits}`. An instance is `{id, source (authored|user), ref, name,
|
|
274
|
+
areaId, pose, scale, state (active|hidden|missing|blocked|loading|suspended),
|
|
275
|
+
movable, locked, rule, path, activity, seat}`; `path`, `activity` and `seat`
|
|
276
|
+
are always null until P2. `usage`/`limits` count this world's user
|
|
277
|
+
placements (placements, assets, triangles, gpuBytes, collisionTriangles).
|
|
278
|
+
- Methods: `objects.catalog {}` (`{revision, entries[<=1024]}`; an entry carries
|
|
279
|
+
ref, source, id, version, formatVersion, name, description, category, tags,
|
|
280
|
+
traits, surfaces, scale range, bounds, triangles, gpuBytes,
|
|
281
|
+
collisionTriangles, an absolute thumbnail path, license, library, other
|
|
282
|
+
versions, state, placeable, reason and up to 8 errors);
|
|
283
|
+
`objects.pocket {ref}` (`{revision, itemId}`); `objects.place {ref, pose?,
|
|
284
|
+
scale?}` (`{revision, id}`); `objects.transform {id, pose, scale?}`;
|
|
285
|
+
`objects.remove {id}|{all:true}`; `objects.hide {id, hidden}`;
|
|
286
|
+
`objects.reset {id}|{all:true}`; `objects.configure {id, patch:{locked}}`;
|
|
287
|
+
`libraries.list {}`; `libraries.install {archive, sha256}` (`{revision, id,
|
|
288
|
+
version}`); `libraries.remove {id, version}`. Refs are
|
|
289
|
+
`package/<asset>`, `library/<id>@<semver>/<object>` or `user/<object>`.
|
|
290
|
+
- `editor.selectedKind` gains `node`; `editor.submode` gains `universal`;
|
|
291
|
+
`editor.unplaced` gains `objects` (pocket items, `count` up to 32); new
|
|
292
|
+
required `editor.gizmo {space, pivot, snap}`.
|
|
293
|
+
- Error `data` may carry `rule` (the placement rule or limit that refused a
|
|
294
|
+
method).
|
|
295
|
+
- Everything else is inherited from 0.21 unchanged; `session.hello` reports
|
|
296
|
+
`0.22`. Inheritance test included.
|
|
297
|
+
|
|
298
|
+
## @hyprune/schema 0.7.0 (2026-10-12)
|
|
299
|
+
|
|
300
|
+
Publishes IPC 0.21 (markers, personal quests, focus sessions) and IPC 0.22 (object catalog, user placements, libraries), plus the object manifest (`object.json` 0.9 and the 0.10 draft), library and library release-record schemas.
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> **Hyprune** is an explorable, world-driven desktop environment for Hyprland: your workspaces become places you can walk through, with live windows on the walls. This repository holds the versioned **schemas** for world packages, IPC and manifests, and their validator. Install Hyprune through the [hyprune](https://github.com/hyprune/hyprune) repository (starter kits, Nix, Arch); learn more at [hyprune.com](https://hyprune.com). Licence: MIT.
|
|
4
4
|
|
|
5
|
-
Versioned contracts for Hyprune, a world-driven Hyprland desktop: world packages (formats 0.1–0.8), the IPC protocol (0.1–0.
|
|
5
|
+
Versioned contracts for Hyprune, a world-driven Hyprland desktop: world packages (formats 0.1–0.8), the IPC protocol (0.1–0.22), object and library manifests (0.9, draft 0.10), extension and screen-type manifests and the input keymap. JSON Schema dialect: **2020-12**. Every version is frozen once published; core, the shell and the SDK pin these exact files. Readable reference: [hyprune.com/reference/schema](https://hyprune.com/reference/schema/).
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -156,3 +156,55 @@ stays `editor.unplaced.windows`. `spatial.map` gains optional `levels` (1-6
|
|
|
156
156
|
per-level blueprint SVGs). `extensions/blueprint.schema.json` defines the world
|
|
157
157
|
extension `com.hyprune.blueprint` 0.1 that supplies them. Every other 0.19
|
|
158
158
|
definition is unchanged. See the RFC-0004 and RFC-0005 amendments for IPC 0.20.
|
|
159
|
+
|
|
160
|
+
IPC **0.21** adds markers, personal quests and focus sessions (RFC-0012 P1). Three
|
|
161
|
+
new required state keys: `markers` (the marker reveal, the persistent-marker mode
|
|
162
|
+
and up to 64 resolved markers), `quests` (tracked and up to 16 active quests,
|
|
163
|
+
counts) and `focus` (the focus session phase, monotonic phase times, credited
|
|
164
|
+
time, cycles and target). New methods `markers.reveal` (shell.control),
|
|
165
|
+
`guidance.get`/`guidance.set` (marker, quest and focus settings, the `player.get`
|
|
166
|
+
pattern), `quests.list/get/track/accept/abandon/resume/create/update/delete/mark`
|
|
167
|
+
and `focus.start/pause/resume/skip/stop/history`; mutations need the new
|
|
168
|
+
`quest.control` grant. Events `quest.progress` and `focus.phase`. The world keymap
|
|
169
|
+
gains `markers.reveal`, the overlay style a required `questColor`, and
|
|
170
|
+
`spatial.projection` markers an optional `markerId`. File schemas in `v0.21/`:
|
|
171
|
+
`quests-personal.schema.json` (`quests/personal.json`), `guidance.schema.json`
|
|
172
|
+
(`guidance.json`) and `focus-history.schema.json` (one `focus/history.jsonl`
|
|
173
|
+
line). Every other 0.20 definition is unchanged. See RFC-0012.
|
|
174
|
+
|
|
175
|
+
IPC **0.22** adds the object catalog and user placements (RFC-0011 P1): the
|
|
176
|
+
`objects.control` grant, a required `objects` state key (this world's authored
|
|
177
|
+
and user instances, object pocket items, user-object usage and limits),
|
|
178
|
+
`objects.catalog/pocket/place/transform/remove/hide/reset/configure` and
|
|
179
|
+
`libraries.list/install/remove`. `editor.selectedKind` gains `node`,
|
|
180
|
+
`editor.submode` gains `universal`, `editor.unplaced` gains `objects` and the
|
|
181
|
+
new `editor.gizmo` carries the tool 4 axis space, pivot and snapping. Error
|
|
182
|
+
`data` may name the refusing placement `rule`. Every other 0.21 definition is
|
|
183
|
+
unchanged. See the RFC-0011 amendment "P1 in IPC 0.22".
|
|
184
|
+
|
|
185
|
+
## Objects and libraries (RFC-0011)
|
|
186
|
+
|
|
187
|
+
Object manifests (`object.json`) and library manifests (`library.json`) use the
|
|
188
|
+
world format numbering and start at **0.9** (`v0.9/object.schema.json`,
|
|
189
|
+
`v0.9/library.schema.json`); `v0.9/library-releases.schema.json` describes the
|
|
190
|
+
meta repository's `libraries/releases.json`. `v0.10/` holds a **draft** that adds
|
|
191
|
+
the `mover` trait, RFC-0013's `machine` trait and the extra slot kinds; it may
|
|
192
|
+
change until world format 0.10 is defined.
|
|
193
|
+
|
|
194
|
+
```js
|
|
195
|
+
import { validate, objectFormats } from '@hyprune/schema';
|
|
196
|
+
const result = validate('object', manifest, undefined, undefined, { gltf, directory: 'street-lantern' });
|
|
197
|
+
// result.errors, result.warnings, result.triangles
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
```sh
|
|
201
|
+
npm run validate -- object examples/object.json
|
|
202
|
+
npm run validate -- object objects/bench/object.json - 0.9 objects/bench/object.glb
|
|
203
|
+
npm run validate -- library examples/library.json
|
|
204
|
+
npm run validate -- library-releases examples/library-releases.json
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
The validator is pure: it never reads files. Pass `gltf` (the parsed glTF or a
|
|
208
|
+
GLB's JSON chunk) for the scene cross-checks, and `files`, `thumbnail` and
|
|
209
|
+
`measured` (exact rest bounds, largest texture, GPU bytes) when you have them;
|
|
210
|
+
`@hyprune/sdk`'s `hyprune object check <dir>` gathers all of them for a directory.
|
package/bin/validate.mjs
CHANGED
|
@@ -2,17 +2,27 @@
|
|
|
2
2
|
import { readFileSync } from 'node:fs';
|
|
3
3
|
import { validate } from '../lib/validate.mjs';
|
|
4
4
|
const [kind, file, method, version, worldFile, asset, ...extra] = process.argv.slice(2);
|
|
5
|
-
|
|
5
|
+
// For kind `object` the fifth argument is the object's glTF (.gltf or .glb) for the cross-checks.
|
|
6
|
+
const gltfJson = path => {
|
|
7
|
+
const bytes = readFileSync(path);
|
|
8
|
+
if (!/\.glb$/i.test(path)) return JSON.parse(bytes.toString('utf8'));
|
|
9
|
+
if (bytes.length < 20 || bytes.readUInt32LE(0) !== 0x46546c67 || bytes.readUInt32LE(16) !== 0x4e4f534a) throw new Error('Invalid GLB header/JSON chunk');
|
|
10
|
+
return JSON.parse(bytes.subarray(20, 20 + bytes.readUInt32LE(12)).toString('utf8'));
|
|
11
|
+
};
|
|
12
|
+
if (!kind || !file || extra.length || ((worldFile || asset) && kind !== 'scene' && kind !== 'object') || (asset && kind === 'object')) {
|
|
6
13
|
console.error('Usage: hyprune-validate <world|extension|screen-type|ipc> <file.json|-> [response-method|-] [contract-version]\n' +
|
|
7
|
-
' hyprune-validate scene <scene.gltf> - <world-format> <world.json> [object-asset-id]\n
|
|
14
|
+
' hyprune-validate scene <scene.gltf> - <world-format> <world.json> [object-asset-id]\n' +
|
|
15
|
+
' hyprune-validate <object|library|library-releases> <file.json|-> [-] [format] [object scene.gltf|.glb]\n(in this repository: npm run validate -- ...)');
|
|
8
16
|
process.exitCode = 2;
|
|
9
17
|
} else {
|
|
10
18
|
try {
|
|
11
19
|
const bytes = readFileSync(file === '-' ? 0 : file);
|
|
12
20
|
if (bytes.length > 1_048_576) throw new Error('Document exceeds 1 MiB');
|
|
13
21
|
const value = JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes));
|
|
14
|
-
const
|
|
15
|
-
|
|
22
|
+
const options = kind === 'object' ? { gltf: worldFile ? gltfJson(worldFile) : undefined }
|
|
23
|
+
: { world: worldFile ? JSON.parse(readFileSync(worldFile, 'utf8')) : undefined, asset };
|
|
24
|
+
const result = validate(kind, value, method === '-' ? undefined : method, version || undefined, options);
|
|
25
|
+
for (const warning of result.warnings || []) console.error(`warning: ${warning}`);
|
|
16
26
|
if (result.valid) console.log(`VALID ${kind}: ${file}`);
|
|
17
27
|
else { console.error(result.errors.join('\n')); process.exitCode = 1; }
|
|
18
28
|
} catch (error) { console.error(error.message); process.exitCode = 2; }
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"com.example.street@1.2.0": {
|
|
3
|
+
"id": "com.example.street",
|
|
4
|
+
"version": "1.2.0",
|
|
5
|
+
"formatVersion": "0.9",
|
|
6
|
+
"url": "https://example.com/releases/street-v1.2.0/com.example.street-1.2.0.tar.zst",
|
|
7
|
+
"sha256": "f06838d7b0725080016c84ae4f47aa01367ee665e3844637b14ed7f23706c894",
|
|
8
|
+
"nixHash": "sha256-8Gg417ByUIABbISuT0eqATZ+5mXjhEY3sU7X8jcGyJQ=",
|
|
9
|
+
"published": false
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"formatVersion": "0.9",
|
|
3
|
+
"id": "com.example.street",
|
|
4
|
+
"version": "1.2.0",
|
|
5
|
+
"name": "Street kit",
|
|
6
|
+
"license": "CC-BY-4.0",
|
|
7
|
+
"attribution": [
|
|
8
|
+
{
|
|
9
|
+
"path": ".",
|
|
10
|
+
"author": "Example Author",
|
|
11
|
+
"license": "CC-BY-4.0"
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"objects": [
|
|
15
|
+
"street-lantern",
|
|
16
|
+
"bench"
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"formatVersion": "0.9",
|
|
3
|
+
"id": "resident",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"name": "Resident",
|
|
6
|
+
"category": "characters",
|
|
7
|
+
"scene": "object.glb",
|
|
8
|
+
"license": "CC-BY-4.0",
|
|
9
|
+
"attribution": [
|
|
10
|
+
{
|
|
11
|
+
"path": ".",
|
|
12
|
+
"author": "Example Author",
|
|
13
|
+
"license": "CC-BY-4.0"
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"bounds": {
|
|
17
|
+
"min": [
|
|
18
|
+
-0.45,
|
|
19
|
+
0,
|
|
20
|
+
-0.2
|
|
21
|
+
],
|
|
22
|
+
"max": [
|
|
23
|
+
0.45,
|
|
24
|
+
1.69,
|
|
25
|
+
0.22
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
"thumbnail": "thumbnail.png",
|
|
29
|
+
"traits": {
|
|
30
|
+
"character": {
|
|
31
|
+
"clips": {
|
|
32
|
+
"walk": {
|
|
33
|
+
"speed": 1.12
|
|
34
|
+
},
|
|
35
|
+
"run": {
|
|
36
|
+
"speed": 2.9
|
|
37
|
+
},
|
|
38
|
+
"idle": {},
|
|
39
|
+
"sit": {
|
|
40
|
+
"seatHeight": 0.46
|
|
41
|
+
},
|
|
42
|
+
"sit_idle": {}
|
|
43
|
+
},
|
|
44
|
+
"height": 1.69,
|
|
45
|
+
"radius": 0.3,
|
|
46
|
+
"accent": false,
|
|
47
|
+
"interactions": [
|
|
48
|
+
{
|
|
49
|
+
"id": "talk",
|
|
50
|
+
"label": "Talk",
|
|
51
|
+
"action": {
|
|
52
|
+
"type": "say",
|
|
53
|
+
"lines": [
|
|
54
|
+
"The lifts run every few minutes."
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"id": "where",
|
|
60
|
+
"label": "Where am I?",
|
|
61
|
+
"action": {
|
|
62
|
+
"type": "panel",
|
|
63
|
+
"panel": "map"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
{
|
|
2
|
+
"formatVersion": "0.10",
|
|
3
|
+
"id": "conveyor",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"name": "Conveyor",
|
|
6
|
+
"category": "machines",
|
|
7
|
+
"tags": [
|
|
8
|
+
"ci",
|
|
9
|
+
"pipeline"
|
|
10
|
+
],
|
|
11
|
+
"scene": "object.glb",
|
|
12
|
+
"license": "CC-BY-4.0",
|
|
13
|
+
"attribution": [
|
|
14
|
+
{
|
|
15
|
+
"path": ".",
|
|
16
|
+
"author": "Example Author",
|
|
17
|
+
"license": "CC-BY-4.0"
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"bounds": {
|
|
21
|
+
"min": [
|
|
22
|
+
-2.2,
|
|
23
|
+
0,
|
|
24
|
+
-0.8
|
|
25
|
+
],
|
|
26
|
+
"max": [
|
|
27
|
+
2.2,
|
|
28
|
+
1.9,
|
|
29
|
+
0.8
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
"traits": {
|
|
33
|
+
"decorative": {
|
|
34
|
+
"animations": [
|
|
35
|
+
{
|
|
36
|
+
"node": "belt-rollers",
|
|
37
|
+
"type": "spin",
|
|
38
|
+
"axis": [
|
|
39
|
+
1,
|
|
40
|
+
0,
|
|
41
|
+
0
|
|
42
|
+
],
|
|
43
|
+
"pivot": [
|
|
44
|
+
0,
|
|
45
|
+
0.6,
|
|
46
|
+
0
|
|
47
|
+
],
|
|
48
|
+
"period": 1.2
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
},
|
|
52
|
+
"collidable": {
|
|
53
|
+
"node": "proxy"
|
|
54
|
+
},
|
|
55
|
+
"movable": {
|
|
56
|
+
"surfaces": [
|
|
57
|
+
"floor"
|
|
58
|
+
]
|
|
59
|
+
},
|
|
60
|
+
"machine": {
|
|
61
|
+
"primary": "status",
|
|
62
|
+
"inputs": [
|
|
63
|
+
{
|
|
64
|
+
"id": "status",
|
|
65
|
+
"type": "enum",
|
|
66
|
+
"values": [
|
|
67
|
+
"idle",
|
|
68
|
+
"running",
|
|
69
|
+
"ok",
|
|
70
|
+
"fail"
|
|
71
|
+
],
|
|
72
|
+
"default": "idle",
|
|
73
|
+
"label": "Pipeline status",
|
|
74
|
+
"explain": "Lamp colour and belt motion: the belt runs while the pipeline runs."
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"id": "jobStarted",
|
|
78
|
+
"type": "event",
|
|
79
|
+
"label": "Job started",
|
|
80
|
+
"explain": "Each started job drops a crate onto the belt."
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"id": "queued",
|
|
84
|
+
"type": "int",
|
|
85
|
+
"min": 0,
|
|
86
|
+
"max": 64,
|
|
87
|
+
"default": 0,
|
|
88
|
+
"label": "Queued jobs",
|
|
89
|
+
"explain": "Crates waiting beside the entry, one per queued job."
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"id": "lastJob",
|
|
93
|
+
"type": "text",
|
|
94
|
+
"maxLength": 24,
|
|
95
|
+
"label": "Last job",
|
|
96
|
+
"explain": "The most recent job's name."
|
|
97
|
+
}
|
|
98
|
+
],
|
|
99
|
+
"drives": [
|
|
100
|
+
{
|
|
101
|
+
"input": "status",
|
|
102
|
+
"target": "state:lamp"
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"input": "status",
|
|
106
|
+
"target": "animation:belt-rollers",
|
|
107
|
+
"map": {
|
|
108
|
+
"cases": [
|
|
109
|
+
{
|
|
110
|
+
"equals": "running",
|
|
111
|
+
"to": 1
|
|
112
|
+
}
|
|
113
|
+
],
|
|
114
|
+
"else": 0
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"input": "queued",
|
|
119
|
+
"target": "count:waiting"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"input": "lastJob",
|
|
123
|
+
"target": "label:sign"
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"input": "jobStarted",
|
|
127
|
+
"target": "spawn:belt-in"
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"input": "status",
|
|
131
|
+
"target": "effect:confetti",
|
|
132
|
+
"map": {
|
|
133
|
+
"becomes": "ok",
|
|
134
|
+
"from": "running"
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
],
|
|
138
|
+
"recipes": [
|
|
139
|
+
{
|
|
140
|
+
"name": "Pipeline summary JSON",
|
|
141
|
+
"fields": {
|
|
142
|
+
"status": "/pipelines/0/status",
|
|
143
|
+
"jobStarted": "/pipelines/0/jobs_started",
|
|
144
|
+
"queued": {
|
|
145
|
+
"countWhere": {
|
|
146
|
+
"array": "/jobs",
|
|
147
|
+
"pointer": "/status",
|
|
148
|
+
"equals": "queued"
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
"lastJob": "/pipelines/0/last_job/name"
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
]
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
"slots": {
|
|
158
|
+
"states": [
|
|
159
|
+
{
|
|
160
|
+
"id": "lamp",
|
|
161
|
+
"materials": [
|
|
162
|
+
"lamp-glass"
|
|
163
|
+
],
|
|
164
|
+
"palette": [
|
|
165
|
+
{
|
|
166
|
+
"id": "idle",
|
|
167
|
+
"colour": [
|
|
168
|
+
0.35,
|
|
169
|
+
0.45,
|
|
170
|
+
0.6
|
|
171
|
+
],
|
|
172
|
+
"emission": 0.5
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
"id": "running",
|
|
176
|
+
"colour": [
|
|
177
|
+
1.0,
|
|
178
|
+
0.7,
|
|
179
|
+
0.2
|
|
180
|
+
],
|
|
181
|
+
"emission": 2
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"id": "ok",
|
|
185
|
+
"colour": [
|
|
186
|
+
0.3,
|
|
187
|
+
1.0,
|
|
188
|
+
0.45
|
|
189
|
+
],
|
|
190
|
+
"emission": 2
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
"id": "fail",
|
|
194
|
+
"colour": [
|
|
195
|
+
1.0,
|
|
196
|
+
0.2,
|
|
197
|
+
0.15
|
|
198
|
+
],
|
|
199
|
+
"emission": 3
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"id": "stale",
|
|
203
|
+
"colour": [
|
|
204
|
+
0.4,
|
|
205
|
+
0.4,
|
|
206
|
+
0.4
|
|
207
|
+
],
|
|
208
|
+
"emission": 0.2
|
|
209
|
+
}
|
|
210
|
+
]
|
|
211
|
+
}
|
|
212
|
+
],
|
|
213
|
+
"labels": [
|
|
214
|
+
{
|
|
215
|
+
"id": "sign",
|
|
216
|
+
"pose": {
|
|
217
|
+
"position": [
|
|
218
|
+
0,
|
|
219
|
+
1.75,
|
|
220
|
+
0.81
|
|
221
|
+
],
|
|
222
|
+
"rotation": [
|
|
223
|
+
0,
|
|
224
|
+
0,
|
|
225
|
+
0,
|
|
226
|
+
1
|
|
227
|
+
]
|
|
228
|
+
},
|
|
229
|
+
"size": [
|
|
230
|
+
1.2,
|
|
231
|
+
0.3
|
|
232
|
+
],
|
|
233
|
+
"maxChars": 24,
|
|
234
|
+
"font": "mono"
|
|
235
|
+
}
|
|
236
|
+
],
|
|
237
|
+
"tracks": [
|
|
238
|
+
{
|
|
239
|
+
"id": "belt",
|
|
240
|
+
"speed": 0.6,
|
|
241
|
+
"points": [
|
|
242
|
+
{
|
|
243
|
+
"position": [
|
|
244
|
+
-2,
|
|
245
|
+
0.8,
|
|
246
|
+
0
|
|
247
|
+
],
|
|
248
|
+
"type": "line"
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
"position": [
|
|
252
|
+
2,
|
|
253
|
+
0.8,
|
|
254
|
+
0
|
|
255
|
+
],
|
|
256
|
+
"type": "line"
|
|
257
|
+
}
|
|
258
|
+
],
|
|
259
|
+
"items": {
|
|
260
|
+
"assets": [
|
|
261
|
+
"job-crate"
|
|
262
|
+
],
|
|
263
|
+
"max": 24,
|
|
264
|
+
"spacing": 0.45
|
|
265
|
+
},
|
|
266
|
+
"sink": true
|
|
267
|
+
}
|
|
268
|
+
],
|
|
269
|
+
"spawns": [
|
|
270
|
+
{
|
|
271
|
+
"id": "belt-in",
|
|
272
|
+
"pose": {
|
|
273
|
+
"position": [
|
|
274
|
+
-2,
|
|
275
|
+
0.8,
|
|
276
|
+
0
|
|
277
|
+
],
|
|
278
|
+
"rotation": [
|
|
279
|
+
0,
|
|
280
|
+
0.707,
|
|
281
|
+
0,
|
|
282
|
+
0.707
|
|
283
|
+
]
|
|
284
|
+
},
|
|
285
|
+
"track": "belt",
|
|
286
|
+
"items": [
|
|
287
|
+
"job-crate"
|
|
288
|
+
],
|
|
289
|
+
"maxRate": 2
|
|
290
|
+
}
|
|
291
|
+
],
|
|
292
|
+
"stacks": [
|
|
293
|
+
{
|
|
294
|
+
"id": "waiting",
|
|
295
|
+
"node": "crate",
|
|
296
|
+
"cap": 64,
|
|
297
|
+
"layout": {
|
|
298
|
+
"grid": [
|
|
299
|
+
4,
|
|
300
|
+
4,
|
|
301
|
+
4
|
|
302
|
+
],
|
|
303
|
+
"spacing": [
|
|
304
|
+
0.35,
|
|
305
|
+
0.35,
|
|
306
|
+
0.35
|
|
307
|
+
],
|
|
308
|
+
"fill": "xzy"
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
],
|
|
312
|
+
"effects": [
|
|
313
|
+
{
|
|
314
|
+
"id": "confetti",
|
|
315
|
+
"pose": {
|
|
316
|
+
"position": [
|
|
317
|
+
0,
|
|
318
|
+
2.0,
|
|
319
|
+
0
|
|
320
|
+
],
|
|
321
|
+
"rotation": [
|
|
322
|
+
0,
|
|
323
|
+
0,
|
|
324
|
+
0,
|
|
325
|
+
1
|
|
326
|
+
]
|
|
327
|
+
},
|
|
328
|
+
"kind": "burst",
|
|
329
|
+
"colour": [
|
|
330
|
+
1.0,
|
|
331
|
+
0.8,
|
|
332
|
+
0.2
|
|
333
|
+
],
|
|
334
|
+
"durationMs": 1500
|
|
335
|
+
}
|
|
336
|
+
]
|
|
337
|
+
}
|
|
338
|
+
}
|