Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,26 @@

Date-based versions use `YYYYMMDD`.

## 20260808

### Changed

- Replaced the unreleased A/B Player bundle with the canonical firmware 0.12.11
Project Berry Player for one static `player.show` and deterministic per-ID
SEB chains.
- Added a public synthetic three-Track Show Index/SEB corpus and a host Berry
lifecycle regression for filtering, pause/resume, retry, seek and 24-hour
wrap behavior.

### Impact

- Creator Kit and Studio can point to one small copy-ready plugin. Projects keep
Player policy in optional Berry while native SEB remains a reusable atomic
Event-value primitive and EventStore stays authoritative.
- The supported operator flow is explicit: pause, upload, wait for ordinary
NetworkStorage propagation, rewind and play. There is no generation or hot
update protocol in v1.

## 20260702

### Added
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ data/v2/examples/
├── gledopto-gl-rc-001wl-espnow-remote/ # Berry espnow.rx examples for a GLEDOPTO GL-RC-001WL remote
├── network-nested-element-groups/ # App elementsJson + controlPages group → groups → devices pattern
├── seb-causal-scene-recall/ # recall a mixed-ID SEB scene at the causal event time
└── seb-segmented-id-track-player/ # play an ordered one-ID Track from bounded SEB segments
├── seb-segmented-id-track-player/ # play an ordered one-ID Track from bounded SEB segments
└── player-show-complete-cue-tracks/ # static Show Index Player with complete per-ID Cues
```

## Example Rules
Expand Down
4 changes: 2 additions & 2 deletions app/v2/src/examplesData.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import YAML from 'yaml';

export type ExampleLanguage = 'berry' | 'tngl' | 'json' | 'markdown';
export type ExampleLanguage = 'berry' | 'tngl' | 'json' | 'markdown' | 'typescript';
export type ExampleCategory = 'controller' | 'espnow-remote' | 'network-pattern';

export type ExampleFileMeta = {
Expand Down Expand Up @@ -55,7 +55,7 @@ const metaModules = import.meta.glob('../../../data/v2/examples/*/example.yaml',
eager: true,
}) as Record<string, string>;

const fileModules = import.meta.glob('../../../data/v2/examples/*/*.{md,be,tngl,json}', {
const fileModules = import.meta.glob('../../../data/v2/examples/*/*.{md,be,tngl,json,mts}', {
query: '?raw',
import: 'default',
eager: true,
Expand Down
10 changes: 5 additions & 5 deletions data/v2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ data/v2/
└── <example-slug>/
├── example.yaml # metadata sidecar (drives the browsing app)
├── README.md # human explanation: use case, wiring, behavior
└── *.be / *.tngl / *.json # copyable source files (kept as-is)
└── *.be / *.tngl / *.json / *.mts # copyable source files (kept as-is)
```

The directory name (`<example-slug>`) describes the use case, not the client.
Expand All @@ -35,8 +35,8 @@ Source files are kept copyable and are **not** embedded into YAML.
| `files` | every file in the folder with `path`, `role` and `language` |
| `related` | optional slugs of related examples |

`language` is one of `berry` (`.be`), `tngl` (`.tngl`), `json` (`.json`) or
`markdown` (`.md`).
`language` is one of `berry` (`.be`), `tngl` (`.tngl`), `json` (`.json`),
`typescript` (`.mts`) or `markdown` (`.md`).

## How to add a new example

Expand All @@ -59,5 +59,5 @@ Source files are kept copyable and are **not** embedded into YAML.
must not duplicate them.
- This is a lightweight content model. It is intentionally **not** registered as
a strict `module-data.v2.json` yaml-only collection, because that validator
would reject the copyable `.be`/`.tngl`/`.json` source files that are the whole
point of an example.
would reject the copyable `.be`/`.tngl`/`.json`/`.mts` source files that are
the whole point of an example.
72 changes: 72 additions & 0 deletions data/v2/examples/player-show-complete-cue-tracks/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Complete-Cue Track Player from `player.show`

This is the canonical copy-ready Project Berry Player for firmware **0.12.11**.
Studio compiles one static `<base>.show` index and deterministic per-ID SEB
chains. The plugin follows the shared timeline; it owns no start, seek or loop
clock of its own.

```berry
Player({"base": "player", "ids": [1], "debug": false})
```

Configure `ids` with only the local Spectoda IDs 0–254 owned by this Controller.
ID255 is selected automatically when the Show Index contains it. NetworkStorage
still synchronizes every file to every Controller; the plugin opens only ID255
and its configured local IDs.

## Authoring and upload

One Track owns one Spectoda ID. Its Event definitions are stable across the
Track, and every Cue supplies one complete type-correct value for every enabled
Event. SEB files contain those encoded Event values/records; landing them
produces normal EventStore updates.

Use Studio's Event Player to Capture and edit Cues, then follow this workflow:

1. pause the shared timeline;
2. upload the changed SEB files and `<base>.show`;
3. wait for ordinary NetworkStorage propagation — App Controller readback does
not prove the whole mesh is ready;
4. rewind the shared timeline;
5. play.

Hot update and simultaneous writers for the same base are unsupported in v1.
Old deterministic files no longer referenced by `<base>.show` are ignored.

## Runtime behavior and limits

The plugin reads only the bounded Show Index into Berry. Each SEB payload is
read and atomically landed by the native `SEB.land(filename,
{"source":"networkStorage", ...})` path, without a Berry payload buffer.

- one complete Cue contains 1–340 Event values;
- one SEB file is at most 4,092 bytes and spans at most 65,535 ms;
- `<base>.show` is exact-EOF validated and at most 4,096 bytes;
- the base is 1–11 safe ASCII characters and generated names are at most 23
bytes;
- one plugin turn performs at most one SEB contribution;
- pause performs no landing; resume derives a fresh timeline projection;
- seek, rewind, loop and the 24-hour timeline wrap reconcile the last complete
Cue at or before the target.

The canonical compact source compiles to a 3,999-byte TNGL BERRY payload
(3,995 source bytes plus framing). Including the copy-ready `return Player(...)`
invocation produces 4,056 bytes, 40 bytes below the 4 KiB hard limit. The 1 KiB
target remains a stretch measurement, not a correctness promise.

The short local names and positional runtime arrays in `player.be` are
intentional consequences of that hard limit. `R` holds loaded state, selected
Tracks, reconciliation state, the next Track, seek target, last timeline
position, and epoch. Each selected Track stores ID, records per complete Cue,
ordered segments, next segment, and next Cue. The parser verifies those tuple
shapes before playback, rejects chronological segment overlap, and stops a
Track after an already-committed native result disagrees with the Show Index;
it never retries that committed contribution.

`player-show-artifacts.json` is a public synthetic three-Track corpus used by
the Berry smoke. It is illustrative compiled output; Project data remains the
authoring source of truth.

For causal scene recall, use the separate `seb-causal-scene-recall` example. A
scene is an ordinary SEB file landed at its trigger Event time and is independent
of the timeline Player.
13 changes: 13 additions & 0 deletions data/v2/examples/player-show-complete-cue-tracks/creator-kit.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"schemaVersion": "creator-kit-example.v1",
"include": true,
"audience": "partner-maker",
"license": "MIT",
"topic": "studio-event-player",
"stability": "firmware-0.12.11",
"compatibility": {
"firmware": "0.12.11",
"wasm": "DEBUG_UNIVERSAL_0.12.11_20260808"
},
"files": ["README.md", "example.yaml", "player.be"]
}
35 changes: 35 additions & 0 deletions data/v2/examples/player-show-complete-cue-tracks/example.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
schemaVersion: example.v2
slug: player-show-complete-cue-tracks
title: Complete-Cue Event Player from player.show
category: controller
summary: >-
Canonical firmware 0.12.11 Project Berry Player for one static player.show
index and deterministic per-ID SEB chains. It lands global ID255 plus explicit
local-ID Tracks from the shared timeline with complete Cue atomicity.
tags:
- berry
- event-player
- network-storage
- player-show
- seb
- timeline
hardware: >-
Requires firmware 0.12.11 with SEB.land NetworkStorage source support.
Configure only local IDs 0-254; ID255 is automatic. Pause before upload, wait
for ordinary propagation, rewind, and then play.
files:
- path: README.md
role: Setup, workflow, runtime behavior, and limits
language: markdown
- path: creator-kit.json
role: Fail-closed Spectoda Creator Kit selection
language: json
- path: player.be
role: Canonical copy-ready Project Berry Player
language: berry
- path: player-show-artifacts.json
role: Synthetic player.show and SEB golden corpus
language: json
related:
- seb-causal-scene-recall
- seb-segmented-id-track-player
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"schemaVersion": "spectoda.player-show-fixture.v1",
"base": "demo",
"description": "Synthetic complete-Cue Tracks for ID1, ID2 and global ID255.",
"files": [
{
"name": "demo.001.000.seb",
"hex": "534542010c00040088130c003f0000ffd2c33c03000001000b84d71700d02404000001013fff0000d2c33c03881301000b8c864700d0240488130101"
},
{
"name": "demo.002.000.seb",
"hex": "534542010c00040088130c003f0000ffd2c33c03000002000b84d71700d02404000002013fff0000d2c33c03881302000b8c864700d0240488130201"
},
{
"name": "demo.255.000.seb",
"hex": "534542010c00020088130c000b00000000d024040000ff000b105e5f00d024048813ff00"
},
{
"name": "demo.show",
"hex": "5053480110000300102700000000000001000200010000000000000002000000000088130200020001000000000000000200000000008813ff00010001000000000000000200000000008813"
}
]
}
Loading