@fabi-play/protocol 0.0.0-stage → 0.2.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/LICENSE ADDED
@@ -0,0 +1,76 @@
1
+ Fabi Play Kit License
2
+ Version 1.0 (DRAFT, not yet reviewed by a lawyer)
3
+
4
+ Copyright (c) 2026 Fabi Play. All rights reserved.
5
+
6
+ This license applies to the Fabi Play Kit: the packages @fabi-play/protocol, @fabi-play/motion,
7
+ @fabi-play/avatars, @fabi-play/sdk and @fabi-play/engine, in source and built form, as published on npm, served
8
+ from https://cdn.fabiplay.app or found in this repository, including their code, type declarations, documentation,
9
+ avatar artwork and other assets (together, the "Kit").
10
+
11
+ 1. Free of charge, for Fabi Play only
12
+
13
+ Fabi Play grants you a worldwide, non-exclusive, non-transferable, non-sublicensable, royalty-free license to
14
+ use, copy, and modify the Kit, and to distribute it as part of a Permitted Work, solely to make, test, run and
15
+ distribute Permitted Works.
16
+
17
+ A "Permitted Work" is a game, tool, or other software made to run on, be published on, or support the
18
+ development of games for the Fabi Play platform (https://fabiplay.app), including games submitted to Fabi Play
19
+ and tools used to build, test or preview them.
20
+
21
+ 2. What is not allowed
22
+
23
+ You may not, without Fabi Play's prior written permission:
24
+
25
+ a. use the Kit, or any part or modified version of it, in software that is not a Permitted Work, including in
26
+ any other game platform, product or service;
27
+ b. distribute the Kit, or a modified version of it, on its own or as a library, SDK, engine or framework for
28
+ others to build with, other than as part of a Permitted Work (installing it from npm or loading it from
29
+ https://cdn.fabiplay.app is not a distribution by you);
30
+ c. sell, rent or sublicense the Kit itself;
31
+ d. remove or alter this license, copyright notices, or the license banners in the built files;
32
+ e. use the avatars, the mascot "Fabi", or the name, logos or other trademarks of Fabi Play, except as the Kit
33
+ does when it runs inside a Permitted Work. This license grants no trademark rights;
34
+ f. use the Kit to circumvent, interfere with or misrepresent the Fabi Play platform, its safety, privacy or
35
+ parental controls, or its rules for games.
36
+
37
+ 3. Visible, not open source
38
+
39
+ The Kit's code is published so that developers can read it, debug with it and build Permitted Works. Being
40
+ visible does not make it open source; no rights are granted beyond those stated here.
41
+
42
+ 4. Your works
43
+
44
+ You keep all rights in your own code and content. This license does not give Fabi Play any rights in your
45
+ Permitted Works; publishing a game on Fabi Play is governed by Fabi Play's separate developer terms.
46
+
47
+ 5. Feedback
48
+
49
+ If you send Fabi Play suggestions or changes for the Kit, Fabi Play may use them without obligation to you.
50
+
51
+ 6. Termination
52
+
53
+ This license ends automatically if you break its terms. If you fix the breach within 30 days of becoming aware
54
+ of it, the license is reinstated, unless Fabi Play has already told you in writing that it is terminated. On
55
+ termination you must stop using and distributing the Kit. Permitted Works already distributed to end users in
56
+ compliance with this license may continue to be used by those end users.
57
+
58
+ 7. No warranty
59
+
60
+ THE KIT IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
61
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
62
+
63
+ 8. Limitation of liability
64
+
65
+ TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL FABI PLAY OR ITS CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
66
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
67
+ CONNECTION WITH THE KIT OR THE USE OR OTHER DEALINGS IN THE KIT.
68
+
69
+ 9. Changes to this license
70
+
71
+ Fabi Play may publish new versions of this license. Each version of the Kit is governed by the license version
72
+ it is distributed with, unless you choose to accept a later version.
73
+
74
+ 10. Contact
75
+
76
+ For permissions beyond this license: https://fabiplay.app
package/README.md CHANGED
@@ -1,3 +1,76 @@
1
- # Temporary Holding Version
1
+ # @fabi-play/protocol
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The messages between the phone, the screen and the games of [Fabi Play](https://fabiplay.app), with their checks:
4
+ the body landmarks (`P`, `Body`), players, age bands, the game manifest (`fabi-play.json`, `parseManifest`, and its
5
+ JSON Schema), and the parsers every side runs on what it receives.
6
+
7
+ ```sh
8
+ npm install @fabi-play/protocol
9
+ ```
10
+
11
+ ```ts
12
+ import { parseManifest, AGE_RANGES, type GameManifest } from '@fabi-play/protocol'
13
+
14
+ const result = parseManifest(JSON.parse(text))
15
+ if ('errors' in result) console.error(result.errors)
16
+ ```
17
+
18
+ The manifest's JSON Schema: `@fabi-play/protocol/fabi-play.schema.json` (also served next to the SDK on
19
+ https://cdn.fabiplay.app). ESM only, types included, no dependencies. Docs: https://docs.fabiplay.app.
20
+
21
+ ## The game intro
22
+
23
+ A manifest's optional `intro` (`GameIntro`: 1 to 4 steps, each a sentence over an image or a move) is what Fabi
24
+ says on the TV before calibration; see "Fabi explains your game" in the
25
+ [`@fabi-play/sdk` README](https://www.npmjs.com/package/@fabi-play/sdk). `parseManifest` reports what is wrong with
26
+ it; `parseIntro` gives the intro or null (the TV skips a bad one, unknown fields included), `introText` the
27
+ sentence for a locale and age.
28
+
29
+ - **Sentences**: up to 90 characters per language, counted as Unicode code points of the NFC form (an emoji is
30
+ one); no white space at either end; no control characters, lone surrogates or bidirectional controls
31
+ (U+202A–U+202E, U+2066–U+2069). The JSON Schema says the same, except lone surrogates and the NFC count, which
32
+ portable JSON Schema regexes can't express: `parseManifest` is the reference.
33
+ - **Paths** (`entry`, a step's `image`): relative to the game's address, no scheme, no leading `/`, no empty, `.` or
34
+ `..` segments, up to 200 characters; segments of ASCII letters, digits, `_` and `-` (dots inside, not first);
35
+ extensions in lowercase: `.html` for `entry`, `.jpg` or `.png` for images (`intro/track.jpg`, not
36
+ `intro/Track.PNG`). No WebP: old TV browsers (WebKit-based Tizen 2.x, webOS 1–2) may not decode it. JPG (quality
37
+ about 80) for screenshots, PNG only for flat art.
38
+ - **Voice clips**: a sentence's clip is at `voiceUrl(base, voiceKeySync(text, locale))` (`voiceKey` is the same as
39
+ a promise). The key is the first 32 lowercase hex characters of SHA-256 of the UTF-8 bytes of
40
+ `` `${FABI_VOICE}\n${locale}\n${t}` `` (`FABI_VOICE` is `fabi-v1`), where `t` is the text in Unicode NFC with
41
+ JavaScript's `trim()` applied; a valid sentence has no white space around it, so for a generator in any language
42
+ `t` is just the NFC text. So `voiceKeySync('Salta!', 'it')` is `cbd16ba39816bdc5afd34a3e84082331` and its clip
43
+ `https://cdn.fabiplay.app/voice/fabi-v1/cbd16ba39816bdc5afd34a3e84082331.mp3`. The SHA-256 is plain JavaScript,
44
+ synchronous: no `crypto.subtle`, so it works on TV pages served over http, old TV browsers and Node 18 (the
45
+ package's `engines`).
46
+ - **The phone's buttons**: during the intro the phone sends `{ type: 'intro', action }`, with action `next`,
47
+ `repeat`, `skip`, or `replay` (from the pause menu: the explanation again); the screen tells it what Fabi is
48
+ saying with `{ type: 'intro', step, steps, text, voice }`. Its `phase` message carries `intro: true` when the
49
+ game has an intro: only then does the phone offer `replay`.
50
+
51
+ ## Poses on the wire
52
+
53
+ The phone streams `{ type: 'pose', t, bodies }` about 30 times a second over an unordered, no-retransmit data
54
+ channel. A screen that lists `POSE_CODEC_VERSION` in its welcome (`binaryPose: [1]`, see `acceptsBinaryPose`) gets
55
+ them in binary, `encodePose` on the phone and `decodePose` on the screen; any other screen gets JSON, and a screen
56
+ reads both. Version 1, little-endian:
57
+
58
+ | Offset | Size | Field |
59
+ |---|---|---|
60
+ | 0 | 1 | magic `0xFB` |
61
+ | 1 | 1 | codec version, 1 |
62
+ | 2 | 1 | kind, 1 = pose |
63
+ | 3 | 1 | body count, 0–4 |
64
+ | 4 | 8 | `t`, float64 (ms on the phone's clock) |
65
+ | 12 | 132 per body | 33 landmarks × uint32: bits 0–9 x·1000, 10–19 y·1000, 20–29 visibility·1000, 30–31 zero |
66
+
67
+ So 12 + 132 × bodies bytes (540 for 4 bodies). Values are the thousandths `toPlayerSpace` rounds to, so a decoded
68
+ pose holds exactly the numbers the JSON one would. `decodePose` returns null on anything else (wrong length,
69
+ magic, version or kind, more than 4 bodies, a value over 1000, `t` not finite) and never throws.
70
+
71
+ Most games need only [`@fabi-play/sdk`](https://www.npmjs.com/package/@fabi-play/sdk), which includes what it uses
72
+ from this package.
73
+
74
+ ## License
75
+
76
+ Fabi Play Kit License: free to use, for making games and tools for Fabi Play only. See [LICENSE](./LICENSE).