generated from Labyricorn/labyricorn-project-template
One commit for the work accumulated in the working tree since Step 6.3, which had never been split into per-step commits: - src/local-surfaces.js + src/surface-url.js (new); src/ui.js, src/validation.js, src/connection.js and public/index.html updated for local-surface hosting and generic surface rendering - tests: local-surfaces (20), scifi-surfaces (24) and postmessage-interop (7) new; connection/museum-gallery/surface-validation suites updated - reference exhibits: shared/contract-core.js defaults to Contract 5.3 (major 5, minor 3, xzbt 5.3); museum-gallery advertises its surface catalog; aquarium/haunted-house/planetarium adapters updated - SciFi-XZBT (Step 6.7A/6.7B): surface-mode.js + surface-bus.js, Observation-surface boot branch, local-change hooks, view.pillars / view.warp-flight targets; fixture byte-identical to G:/.vibe/SciFi-XZBT - SciFi-XZBT contract adapter handshake fix: the inbound bridge filter no longer gates on an exact advisory xzbt value (Contract 5.3 §6.5), only on its presence/type, matching the host's own envelope validation; the adapter now advertises contract minor 3 / version 5.3.0, which it already implemented via the 5.3 surfaces field. Root cause of the five failing postmessage-interop tests (host hello was silently dropped). - docs: architecture 6.4 and 6.7A, reference 6.6 and 6.7; evidence logs; test-fixtures/PROVENANCE.md resync record Test results: NGN 154/154 (was 149/154); postmessage-interop 7/7 (was 2/7); SciFi contract harness 21/21, real-adapter suite 32/32. git diff --check clean for changed files; two pre-existing trailing-whitespace lines remain in test-fixtures/reference-exhibits/scifi/index.html, copied verbatim from the authoritative SciFi source. Step 6.7 live verification (browser Observation, packaged standalone) is still pending and is not claimed here.
107 lines
4.5 KiB
JavaScript
107 lines
4.5 KiB
JavaScript
/*
|
|
* Museum Gallery — Control Room boot.
|
|
*
|
|
* This is the ONLY document in this exhibit that constructs an Exhibit
|
|
* State Core. Every other surface (artifact.html, info-wall.html) attaches
|
|
* to the Core this document creates, over the exhibit-internal bus in
|
|
* surface-bus.js -- see README.md.
|
|
*
|
|
* This document remains fully standalone: nothing below requires any other
|
|
* surface to be open, and nothing below requires XZBT-NGN. The optional
|
|
* HostTransport at the bottom lets an NGN attach later, exactly like every
|
|
* other reference exhibit -- it changes nothing about ordinary operation
|
|
* when no host ever connects.
|
|
*/
|
|
(function () {
|
|
'use strict';
|
|
|
|
var Shell = window.XZBTShell;
|
|
var el = Shell.el;
|
|
|
|
var gallery = new window.MuseumGalleryExhibit.Gallery();
|
|
var core = window.MuseumGalleryContract.create(gallery);
|
|
|
|
var announcer = new Shell.Announcer({ node: el('announcement'), idleText: 'Control Room standing by.' });
|
|
|
|
var artifactSelect = el('artifact-select');
|
|
var artifactDescriptor = core.catalog.get('artifact.selected');
|
|
artifactDescriptor.options.forEach(function (opt) {
|
|
var option = document.createElement('option');
|
|
option.value = opt.value;
|
|
option.textContent = opt.label;
|
|
artifactSelect.appendChild(option);
|
|
});
|
|
|
|
var lightingRange = el('lighting-range');
|
|
var rotationRange = el('rotation-range');
|
|
var labelsButton = el('labels-button');
|
|
var subscriberCountEl = el('subscriber-count');
|
|
|
|
function sync() {
|
|
var values = core.stateSnapshot().values;
|
|
Shell.setText(el('artifact-name'), window.MuseumGalleryExhibit.ARTIFACT_LABELS[values['artifact.selected']]);
|
|
artifactSelect.value = values['artifact.selected'];
|
|
|
|
Shell.setText(el('lighting-readout'), Shell.formatPercent(values['lighting.level']));
|
|
Shell.setText(el('lighting-panel-readout'), Shell.formatPercent(values['lighting.level']));
|
|
lightingRange.value = values['lighting.level'];
|
|
|
|
Shell.setText(el('rotation-readout'), values['rotation.speed'].toFixed(1) + 'x');
|
|
Shell.setText(el('rotation-panel-readout'), values['rotation.speed'].toFixed(1) + 'x');
|
|
rotationRange.value = values['rotation.speed'];
|
|
|
|
Shell.setText(el('labels-readout'), values['labels.enabled'] ? 'ON' : 'OFF');
|
|
labelsButton.setAttribute('aria-pressed', values['labels.enabled'] ? 'true' : 'false');
|
|
}
|
|
sync();
|
|
|
|
/* Every native control here calls the SAME core.applyMutation/invokeAction
|
|
* chokepoint a contract set/invoke (from NGN) or a bus-relayed mutation
|
|
* (from a non-primary surface) would call. There is exactly one path. */
|
|
artifactSelect.addEventListener('change', function () {
|
|
core.applyMutation('artifact.selected', artifactSelect.value, 'ui');
|
|
});
|
|
lightingRange.addEventListener('input', function () {
|
|
core.applyMutation('lighting.level', parseFloat(lightingRange.value), 'ui');
|
|
});
|
|
rotationRange.addEventListener('input', function () {
|
|
core.applyMutation('rotation.speed', parseFloat(rotationRange.value), 'ui');
|
|
});
|
|
labelsButton.addEventListener('click', function () {
|
|
var current = core.stateSnapshot().values['labels.enabled'];
|
|
core.applyMutation('labels.enabled', !current, 'ui');
|
|
});
|
|
el('flash-button').addEventListener('click', function () {
|
|
core.invokeAction('action.spotlight-flash', {}, 'ui');
|
|
announcer.flash('Spotlight flashed.');
|
|
});
|
|
|
|
/* The bus owner forwards every core event (however it originated -- this
|
|
* document's own controls, or a mutate request relayed from another
|
|
* surface) to attached surfaces, and answers their attach requests with a
|
|
* fresh snapshot read straight from this Core -- never a second
|
|
* computation. */
|
|
function updateSubscriberCount(count) {
|
|
Shell.setText(subscriberCountEl, String(count));
|
|
}
|
|
var bus = window.MuseumGallerySurfaceBus.createOwner(core, {
|
|
onConnectionChange: updateSubscriberCount
|
|
});
|
|
updateSubscriberCount(bus.attachedCount());
|
|
var priorOnEvent = core.onEvent;
|
|
core.onEvent = function (event) {
|
|
if (typeof priorOnEvent === 'function') priorOnEvent(event);
|
|
sync();
|
|
};
|
|
|
|
/* Optional NGN attachment -- same optional transport every reference
|
|
* exhibit includes. Museum Gallery Phase 6.2 does not exercise this path;
|
|
* see the verification document's known-limitations section. */
|
|
var transport = new window.XZBTHostTransport({
|
|
core: core,
|
|
onMessage: function () { el('contract-status').textContent = 'host attached'; }
|
|
});
|
|
|
|
window.__museumGalleryDebug = { core: core, gallery: gallery, bus: bus, transport: transport, sync: sync };
|
|
})();
|