diff --git a/ts/index.html b/ts/index.html
index 00d4559..1004dd1 100644
--- a/ts/index.html
+++ b/ts/index.html
@@ -406,7 +406,7 @@
flex-shrink: 0
}
- /* red × — section & element */
+ /* red × - section & element */
.x-btn {
background: none;
border: none;
@@ -681,11 +681,11 @@
- —
+ -
- —
+ -
@@ -728,7 +728,7 @@
let currentFilename = 'untitled';
let isDirty = false;
- // ─── Element type definitions ────────────────────────────────────────────────
+ // --- Element type definitions ------------------------------------------------
const EL_TYPES = ['Image2D', 'Animation', 'ClippedText', 'HScrollText', 'CurrentTime'];
const EL_FIELDS = {
Image2D: [
@@ -746,7 +746,7 @@
{ k: 'width', l: 'Width', t: 'number', d: W }, { k: 'height', l: 'Height', t: 'number', d: 16 },
],
HScrollText: [
- { k: 'text', l: 'Text', t: 'text', d: 'Scrolling text — ', full: true },
+ { k: 'text', l: 'Text', t: 'text', d: 'Scrolling text - ', full: true },
{ k: 'xOffset', l: 'X offset', t: 'number', d: 0 }, { k: 'yOffset', l: 'Y offset', t: 'number', d: 32 },
{ k: 'width', l: 'Width', t: 'number', d: W }, { k: 'height', l: 'Height', t: 'number', d: 16 },
{ k: 'scrollSpeed', l: 'Scroll speed', t: 'number', d: 50 },
@@ -763,7 +763,7 @@
CurrentTime: [{ k: 'clock12h', l: '12h mode' }, { k: 'showHours', l: 'Show hours' }, { k: 'showSeconds', l: 'Show seconds' }],
};
- // ─── Confirm dialog ───────────────────────────────────────────────────────────
+ // --- Confirm dialog -----------------------------------------------------------
function confirm(msg, buttons) {
// buttons: [{label,primary,action}]
return new Promise(resolve => {
@@ -782,7 +782,7 @@
});
}
- // ─── Dirty tracking ───────────────────────────────────────────────────────────
+ // --- Dirty tracking -----------------------------------------------------------
function markDirty() {
isDirty = true;
document.getElementById('filename').classList.add('dirty');
@@ -800,7 +800,7 @@
return action;
}
- // ─── Helpers ─────────────────────────────────────────────────────────────────
+ // --- Helpers -----------------------------------------------------------------
function newSec() {
secCounter++;
return {
@@ -819,7 +819,7 @@
function getSec(id) { return sections.find(s => s.id === id) }
function getEl(secId, elId) { const s = getSec(secId); return s && s.elements.find(e => e.id === elId) }
- // ─── Mutations ────────────────────────────────────────────────────────────────
+ // --- Mutations ----------------------------------------------------------------
function addSection() {
const s = newSec(); sections.push(s);
activeSec = s.id; activeEl = null;
@@ -871,7 +871,7 @@
el.flags[key] = val; markDirty(); triggerPreview();
}
- // ─── Load demo into editor state ─────────────────────────────────────────────
+ // --- Load demo into editor state ---------------------------------------------
const DEMO_DEFS = [
{
label: 'Checkerboard', build() {
@@ -900,7 +900,7 @@
label: 'Scrolltext', build() {
const s = newSec(); s.name = 'Scrolltext'; s.flags = { drawFront: true, clearBuffer: true };
const el = newEl('HScrollText');
- el.fields.text = 'MONO DISPLAY — scrolling ticker — 🚀 ';
+ el.fields.text = 'MONO DISPLAY - scrolling ticker - 🚀 ';
el.fields.yOffset = 32; el.fields.scrollSpeed = 50;
el.flags.endless = true; el.flags.invertDirection = false;
s.elements.push(el); return [s];
@@ -925,7 +925,7 @@
},
];
- // ─── Preview via MonoDisplayFile (same as original demos) ────────────────────
+ // --- Preview via MonoDisplayFile (same as original demos) --------------------
const DEMO_PREVIEWS = {
Checkerboard() {
const { MonoDisplayFile, ElementType } = window.MonoDisplay;
@@ -963,7 +963,7 @@
elements_always: {
flags: { drawFront: true, clearBuffer: true },
elements: [{
- type: ElementType.HScrollText, text: 'MONO DISPLAY — scrolling ticker — 🚀 ',
+ type: ElementType.HScrollText, text: 'MONO DISPLAY - scrolling ticker - 🚀 ',
xOffset: 0, yOffset: 32, width: W, height: 16, scrollSpeed: 50, flags: { endless: true, invertDirection: false }
}]
}
@@ -1011,7 +1011,7 @@
});
}
- // ─── Render ───────────────────────────────────────────────────────────────────
+ // --- Render -------------------------------------------------------------------
function render() {
updateMeta();
const wrap = document.getElementById('sections-wrap');
@@ -1085,20 +1085,20 @@
}
function elSummary(el) {
- if (el.fields.text) return esc(el.fields.text.slice(0, 24) + (el.fields.text.length > 24 ? '…' : ''));
+ if (el.fields.text) return esc(el.fields.text.slice(0, 24) + (el.fields.text.length > 24 ? '...' : ''));
return `${el.fields.xOffset ?? 0}, ${el.fields.yOffset ?? 0}`;
}
function esc(s) { return String(s).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"') }
function updateMeta() {
const s = activeSec ? getSec(activeSec) : null;
- document.getElementById('meta-name').textContent = s ? s.name : '—';
- document.getElementById('meta-count').textContent = s ? s.elements.length + ' element(s)' : '—';
+ document.getElementById('meta-name').textContent = s ? s.name : '-';
+ document.getElementById('meta-count').textContent = s ? s.elements.length + ' element(s)' : '-';
document.getElementById('flag-drawFront').checked = s ? !!s.flags.drawFront : false;
document.getElementById('flag-clearBuffer').checked = s ? !!s.flags.clearBuffer : false;
}
- // ─── Preview ──────────────────────────────────────────────────────────────────
+ // --- Preview ------------------------------------------------------------------
let previewTimer = null;
function triggerPreview() {
clearTimeout(previewTimer);
@@ -1120,17 +1120,69 @@
));
}
- // ─── Load / Export ────────────────────────────────────────────────────────────
+ // --- Load / Export ------------------------------------------------------------
+ function parsedToSections(parsedSecs) {
+ const TYPE_MAP = { 1: 'Image2D', 2: 'Animation', 16: 'ClippedText', 17: 'HScrollText', 32: 'CurrentTime' };
+ return parsedSecs
+ .filter(s => s.sectionType === 1 || s.sectionType === 2)
+ .map(s => {
+ secCounter++;
+ const elements = (s.elements || []).map(el => {
+ const typeName = TYPE_MAP[el.type];
+ if (!typeName) return null;
+ elCounter++;
+ let fields = {}, flags = {};
+ switch (typeName) {
+ case 'Image2D':
+ fields = { xOffset: el.xOffset, yOffset: el.yOffset, width: el.image?.width ?? W, height: el.image?.height ?? H };
+ break;
+ case 'Animation':
+ fields = { xOffset: el.xOffset, yOffset: el.yOffset, width: el.width, height: el.height, updateInterval: el.updateInterval };
+ break;
+ case 'ClippedText':
+ fields = { text: el.text, xOffset: el.xOffset, yOffset: el.yOffset, width: el.width, height: el.height };
+ break;
+ case 'HScrollText':
+ fields = { text: el.text, xOffset: el.xOffset, yOffset: el.yOffset, width: el.width, height: el.height, scrollSpeed: el.scrollSpeed };
+ flags = { endless: !!el.flags?.endless, invertDirection: !!el.flags?.invertDirection };
+ break;
+ case 'CurrentTime':
+ fields = { xOffset: el.xOffset, yOffset: el.yOffset, width: el.width, height: el.height, utcOffsetMinutes: el.utcOffsetMinutes };
+ flags = { clock12h: !!el.flags?.clock12h, showHours: !!el.flags?.showHours, showSeconds: !!el.flags?.showSeconds };
+ break;
+ }
+ return { id: 'e' + elCounter, type: typeName, fields, flags };
+ }).filter(Boolean);
+ return {
+ id: 's' + secCounter,
+ name: 'Section ' + secCounter,
+ open: true,
+ flags: { drawFront: !!s.flags?.drawFront, clearBuffer: !!s.flags?.clearBuffer },
+ elements
+ };
+ });
+ }
+
function loadBin(input) {
const file = input.files[0]; if (!file) return;
currentFilename = file.name;
document.getElementById('filename').textContent = file.name;
const reader = new FileReader();
reader.onload = e => {
- const buf = new Uint8Array(e.target.result);
+ const arrayBuf = e.target.result;
+ const buf = new Uint8Array(arrayBuf);
if (!window._mdDriver && window.MonoDisplay)
window._mdDriver = new window.MonoDisplay.MonoDisplayDriver('canvas_root', { onColor: '#EC0', offColor: '#000', fps: 25 });
if (window._mdDriver) window._mdDriver.load(() => Promise.resolve(buf));
+ try {
+ const parsed = new window.MonoDisplay.MonoDisplayParser().parse(arrayBuf);
+ sections = parsedToSections(parsed.sections);
+ activeSec = sections.length ? sections[0].id : null;
+ activeEl = null;
+ render();
+ } catch (err) {
+ console.warn('Could not parse sections from bin:', err);
+ }
};
reader.readAsArrayBuffer(file);
input.value = ''; markClean();
@@ -1149,7 +1201,7 @@
a.click(); markClean();
}
- // ─── Theme ────────────────────────────────────────────────────────────────────
+ // --- Theme --------------------------------------------------------------------
var _THEMES = ['dark', 'light', 'auto'];
function _getTheme() { return document.documentElement.getAttribute('data-theme') || 'auto'; }
function _applyTheme(t) {
@@ -1172,11 +1224,11 @@
var t = _getTheme(), dr = _detectDR();
var lbl = { dark: '☾ dark', light: '☀ light', auto: '⊙ auto' };
btn.textContent = (dr ? 'DR · ' : '') + (lbl[t] || lbl.auto);
- btn.title = dr ? 'DarkReader active — controlling theme' : ('Theme: ' + t + ' (click to cycle)');
+ btn.title = dr ? 'DarkReader active - controlling theme' : ('Theme: ' + t + ' (click to cycle)');
}
window.addEventListener('DOMContentLoaded', _updateThemeBtn);
- // ─── Init ─────────────────────────────────────────────────────────────────────
+ // --- Init ---------------------------------------------------------------------
render();
if (window.MonoDisplay) { initDemos(); }
else { const iv = setInterval(() => { if (window.MonoDisplay) { clearInterval(iv); initDemos(); } }, 100); }