From c3ab9cd1b8e7a219a5ce3a31c35ea14c023638c8 Mon Sep 17 00:00:00 2001 From: flop Date: Sat, 30 May 2026 15:10:39 +0200 Subject: [PATCH] feat: go for dist instead of public folder --- ts-editor/src/browser.ts | 138 +++++++++++++++++++-------------------- ts/package.json | 12 ++-- 2 files changed, 74 insertions(+), 76 deletions(-) diff --git a/ts-editor/src/browser.ts b/ts-editor/src/browser.ts index 0b164f2..d56eda7 100644 --- a/ts-editor/src/browser.ts +++ b/ts-editor/src/browser.ts @@ -2,10 +2,8 @@ // Built by: bun build src/browser.ts --target browser --outfile public/mono-display.js import m from "mithril"; -import * as MonoDisplay from "libmonoformat"; import { MonoDisplayFile, cycleTheme } from "libmonoformat"; -(globalThis as typeof globalThis & { MonoDisplay: typeof MonoDisplay }).MonoDisplay = MonoDisplay; const W = 120, H = 60; @@ -20,7 +18,7 @@ let isDirty = false; type ElFieldMeta = { key: string; label: string; type: string; default: any; full?: boolean }; type ElFlagMeta = { key: string; label: string; default?: boolean }; -const EL_FIELDS: Partial> = { +const EL_FIELDS: Partial> = { Image2D: [ { key: "xOffset", label: "X offset", type: "number", default: 0 }, { key: "yOffset", label: "Y offset", type: "number", default: 0 }, @@ -78,7 +76,7 @@ const EL_FIELDS: Partial> = { ], }; -const EL_FLAGS: Partial> = { +const EL_FLAGS: Partial> = { HScrollText: [ { key: "endless", label: "Endless" }, { key: "invertDirection", label: "Invert direction" }, @@ -92,11 +90,11 @@ const EL_FLAGS: Partial> = { ], }; -const EL_TYPES: MonoDisplay.ElementType[] = Object.keys(EL_FIELDS).map( - (x) => MonoDisplay.StringToElementType[x as MonoDisplay.ElementTypeName] +const EL_TYPES: ElementType[] = Object.keys(EL_FIELDS).map( + (x) => StringToElementType[x as ElementTypeName] ); -const DEFAULT_FONTS = Object.keys(MonoDisplay.MonoDisplayRenderer.builtinFonts); +const DEFAULT_FONTS = Object.keys(MonoDisplayRenderer.builtinFonts); // --- Confirm dialog ---------------------------------------------------------- function showConfirm( @@ -137,7 +135,7 @@ function loadFromStorage() { if (!raw) return; const { filename, data } = JSON.parse(raw); const bytes = Uint8Array.from(atob(data), c => c.charCodeAt(0)); - const parsed = new MonoDisplay.MonoDisplayParser().parse(bytes.buffer); + const parsed = new MonoDisplayParser().parse(bytes.buffer); file = new MonoDisplayFile(parsed.sections); currentFilename = filename; const filenameEl = document.getElementById("filename"); @@ -167,9 +165,9 @@ async function guardDirty(): Promise { } // --- Helpers ----------------------------------------------------------------- -function newSec(): MonoDisplay.MonoFormatElementsAlways { +function newSec(): MonoFormatElementsAlways { return { - sectionType: MonoDisplay.SectionType.ElementsAlways, elements: [], flags: { + sectionType: SectionType.ElementsAlways, elements: [], flags: { clearBuffer: true, drawBack: true, drawFront: true, @@ -177,47 +175,47 @@ function newSec(): MonoDisplay.MonoFormatElementsAlways { }; } -function createNewElement(type: MonoDisplay.ElementType): MonoDisplay.MonoFormatElement { +function createNewElement(type: ElementType): MonoFormatElement { const fields: Record = {}; - (EL_FIELDS[MonoDisplay.ElementTypeToString[type]] as ElFieldMeta[] || []) + (EL_FIELDS[ElementTypeToString[type]] as ElFieldMeta[] || []) .forEach(f => (fields[f.key] = f.default)); const flags: Record = {}; - (EL_FLAGS[MonoDisplay.ElementTypeToString[type]] as ElFlagMeta[] || []) + (EL_FLAGS[ElementTypeToString[type]] as ElFlagMeta[] || []) .forEach(f => (flags[f.key] = f.default ?? false)); const el: any = { type, ...fields, flags }; - if (type === MonoDisplay.ElementType.Image2D) { + if (type === ElementType.Image2D) { el.image = { pixels: new Uint8Array(el.width * el.height), width: el.width, height: el.height }; } - if (type === MonoDisplay.ElementType.Animation) { + if (type === ElementType.Animation) { el.frames = [{ pixels: new Uint8Array(el.width * el.height), width: el.width, height: el.height }]; } - return el as MonoDisplay.MonoFormatElement; + return el as MonoFormatElement; } -function getSectionByIndex(i: number | null): MonoDisplay.MonoFormatSection | undefined { +function getSectionByIndex(i: number | null): MonoFormatSection | undefined { return i !== null ? file.sections[i] : undefined; } -function getElementByIndex(si: number, ei: number): MonoDisplay.MonoFormatElement | undefined { +function getElementByIndex(si: number, ei: number): MonoFormatElement | undefined { const s = getSectionByIndex(si); return s && "elements" in s ? s.elements[ei] : undefined; } function getCustomFonts(): { fontname: string; index: number }[] { return file.sections - .filter(s => s.sectionType === MonoDisplay.SectionType.CustomFont) + .filter(s => s.sectionType === SectionType.CustomFont) .map((_, i) => ({ fontname: `CustomFont ${i}`, index: 0x8000 + i })); } -function elSummary(el: MonoDisplay.MonoFormatElement): string { +function elSummary(el: MonoFormatElement): string { switch (el.type) { - case MonoDisplay.ElementType.ClippedText: - case MonoDisplay.ElementType.HScrollText: + case ElementType.ClippedText: + case ElementType.HScrollText: return el.text.slice(0, 24) + (el.text.length > 24 ? "..." : ""); - case MonoDisplay.ElementType.CurrentTime: - case MonoDisplay.ElementType.Image2D: - case MonoDisplay.ElementType.HorizontalScroll: - case MonoDisplay.ElementType.VerticalScroll: + case ElementType.CurrentTime: + case ElementType.Image2D: + case ElementType.HorizontalScroll: + case ElementType.VerticalScroll: return `${(el as any).xOffset ?? 0}, ${(el as any).yOffset ?? 0}`; default: return el.type.toString(); @@ -263,9 +261,9 @@ function setSectionField(si: number, key: string, val: any) { function setSectionType(si: number, sectionType: string) { const sec = getSectionByIndex(si); if (!sec) return; - const wasElementsSection = sec.sectionType !== MonoDisplay.SectionType.CustomFont; - (sec as any).sectionType = MonoDisplay.StringToSectionType[sectionType as MonoDisplay.SectionTypeName]; - if ((sec as any).sectionType === MonoDisplay.SectionType.CustomFont) { + const wasElementsSection = sec.sectionType !== SectionType.CustomFont; + (sec as any).sectionType = StringToSectionType[sectionType as SectionTypeName]; + if ((sec as any).sectionType === SectionType.CustomFont) { (sec as any).fontData = new Uint8Array(); delete (sec as any).elements; delete (sec as any).flags; @@ -275,7 +273,7 @@ function setSectionType(si: number, sectionType: string) { (sec as any).flags = {}; } delete (sec as any).fontData; - if ((sec as any).sectionType === MonoDisplay.SectionType.ElementsTimespan) { + if ((sec as any).sectionType === SectionType.ElementsTimespan) { const now = BigInt(Math.floor(Date.now() / 1000)); (sec as any).startTimestamp = now; (sec as any).endTimestamp = now + 3600n; @@ -290,7 +288,7 @@ function setSectionType(si: number, sectionType: string) { function addElement(si: number) { const s = getSectionByIndex(si); if (!s || !("elements" in s)) return; - s.elements.push(createNewElement(MonoDisplay.ElementType.HScrollText)); + s.elements.push(createNewElement(ElementType.HScrollText)); activeElIndex = s.elements.length - 1; activeSecIndex = si; markDirty(); triggerPreview(); @@ -313,10 +311,10 @@ function selectElement(si: number, ei: number) { } } -function changeElType(si: number, ei: number, typeString: MonoDisplay.ElementTypeName) { +function changeElType(si: number, ei: number, typeString: ElementTypeName) { const el = getElementByIndex(si, ei); if (!el) return; - const fresh = createNewElement(MonoDisplay.StringToElementType[typeString]); + const fresh = createNewElement(StringToElementType[typeString]); Object.assign(el, fresh); markDirty(); triggerPreview(); } @@ -341,16 +339,16 @@ const DEMO: Record MonoDisplayFile> = { const pixels = new Uint8Array(W * H); for (let y = 0; y < H; y++) for (let x = 0; x < W; x++) pixels[y * W + x] = (x + y) % 2; return new MonoDisplayFile([{ - sectionType: MonoDisplay.SectionType.ElementsAlways, - elements: [{ type: MonoDisplay.ElementType.Image2D, image: { pixels, height: H, width: W }, xOffset: 0, yOffset: 0 }], + sectionType: SectionType.ElementsAlways, + elements: [{ type: ElementType.Image2D, image: { pixels, height: H, width: W }, xOffset: 0, yOffset: 0 }], flags: { clearBuffer: true, drawFront: true, drawBack: true }, }]); }, Blink() { return new MonoDisplayFile([{ - sectionType: MonoDisplay.SectionType.ElementsAlways, + sectionType: SectionType.ElementsAlways, elements: [{ - type: MonoDisplay.ElementType.Animation, width: W, height: H, updateInterval: 12, xOffset: 0, yOffset: 0, + type: ElementType.Animation, width: W, height: H, updateInterval: 12, xOffset: 0, yOffset: 0, frames: [ { pixels: new Uint8Array(W * H).fill(1), width: 0, height: 0 }, { pixels: new Uint8Array(W * H).fill(0), width: 0, height: 0 }, @@ -361,16 +359,16 @@ const DEMO: Record MonoDisplayFile> = { }, Text() { return new MonoDisplayFile([{ - sectionType: MonoDisplay.SectionType.ElementsAlways, - elements: [{ type: MonoDisplay.ElementType.ClippedText, fontIndex: 0, text: "Hello, World!", xOffset: 0, yOffset: 16, width: 60, height: 10 }], + sectionType: SectionType.ElementsAlways, + elements: [{ type: ElementType.ClippedText, fontIndex: 0, text: "Hello, World!", xOffset: 0, yOffset: 16, width: 60, height: 10 }], flags: { clearBuffer: true, drawFront: true, drawBack: true }, }]); }, Scrolltext() { return new MonoDisplayFile([{ - sectionType: MonoDisplay.SectionType.ElementsAlways, + sectionType: SectionType.ElementsAlways, elements: [{ - type: MonoDisplay.ElementType.HScrollText, fontIndex: 0, + type: ElementType.HScrollText, fontIndex: 0, text: "MONO DISPLAY - scrolling ticker - 🚀 ", xOffset: 0, yOffset: 32, width: W, height: 16, scrollSpeed: 50, flags: { endless: true, invertDirection: false, padStart: false, padEnd: false }, @@ -380,13 +378,13 @@ const DEMO: Record MonoDisplayFile> = { }, Time() { return new MonoDisplayFile([{ - sectionType: MonoDisplay.SectionType.ElementsAlways, + sectionType: SectionType.ElementsAlways, elements: [ - { type: MonoDisplay.ElementType.CurrentTime, fontIndex: 0, flags: {}, xOffset: 0, yOffset: 8, width: W, height: 16, utcOffsetMinutes: 120 }, - { type: MonoDisplay.ElementType.CurrentTime, fontIndex: 0, flags: { clock12h: true }, xOffset: 40, yOffset: 16, width: W, height: 16, utcOffsetMinutes: 120 }, - { type: MonoDisplay.ElementType.CurrentTime, fontIndex: 0, flags: { clock12h: true, showHours: true }, xOffset: 0, yOffset: 24, width: W, height: 16, utcOffsetMinutes: 120 }, - { type: MonoDisplay.ElementType.CurrentTime, fontIndex: 0, flags: { clock12h: true, showHours: false }, xOffset: 40, yOffset: 32, width: W, height: 16, utcOffsetMinutes: 120 }, - { type: MonoDisplay.ElementType.CurrentTime, fontIndex: 0, flags: { clock12h: true, showSeconds: true }, xOffset: 80, yOffset: 32, width: W, height: 16, utcOffsetMinutes: 120 }, + { type: ElementType.CurrentTime, fontIndex: 0, flags: {}, xOffset: 0, yOffset: 8, width: W, height: 16, utcOffsetMinutes: 120 }, + { type: ElementType.CurrentTime, fontIndex: 0, flags: { clock12h: true }, xOffset: 40, yOffset: 16, width: W, height: 16, utcOffsetMinutes: 120 }, + { type: ElementType.CurrentTime, fontIndex: 0, flags: { clock12h: true, showHours: true }, xOffset: 0, yOffset: 24, width: W, height: 16, utcOffsetMinutes: 120 }, + { type: ElementType.CurrentTime, fontIndex: 0, flags: { clock12h: true, showHours: false }, xOffset: 40, yOffset: 32, width: W, height: 16, utcOffsetMinutes: 120 }, + { type: ElementType.CurrentTime, fontIndex: 0, flags: { clock12h: true, showSeconds: true }, xOffset: 80, yOffset: 32, width: W, height: 16, utcOffsetMinutes: 120 }, ], flags: { clearBuffer: true, drawFront: true, drawBack: true }, }]); @@ -406,7 +404,7 @@ function triggerPreview() { function buildPreview() { if (!window.MonoDisplay) return; if (!window._mdDriver) - window._mdDriver = new MonoDisplay.MonoDisplayDriver("canvas_root", { onColor: "#EC0", offColor: "#000", fps: 25 }); + window._mdDriver = new MonoDisplayDriver("canvas_root", { onColor: "#EC0", offColor: "#000", fps: 25 }); window._mdDriver.load(() => Promise.resolve(file.toBuffer())); } @@ -420,7 +418,7 @@ function loadBin(input: HTMLInputElement) { const reader = new FileReader(); reader.onload = e => { try { - const parsed = new window.MonoDisplay.MonoDisplayParser().parse(e.target!.result as ArrayBuffer); + const parsed = new window.MonoDisplayParser().parse(e.target!.result as ArrayBuffer); file = new MonoDisplayFile(parsed.sections); activeSecIndex = null; activeElIndex = null; @@ -447,7 +445,7 @@ function exportBin() { // --- Mithril Components ------------------------------------------------------- -function FieldInput(si: number, ei: number, field: ElFieldMeta, el: MonoDisplay.MonoFormatElement): m.Vnode { +function FieldInput(si: number, ei: number, field: ElFieldMeta, el: MonoFormatElement): m.Vnode { const val = (el as any)[field.key] ?? field.default; switch (field.type) { case "text": @@ -475,11 +473,11 @@ function FieldInput(si: number, ei: number, field: ElFieldMeta, el: MonoDisplay. const PIXEL_SCALE = 4; -function getPixelIndex(img: MonoDisplay.MonoFormatPixelImage, x: number, y: number): number { +function getPixelIndex(img: MonoFormatPixelImage, x: number, y: number): number { return y * img.width + x; } -function drawPixelCanvas(canvas: HTMLCanvasElement, img: MonoDisplay.MonoFormatPixelImage) { +function drawPixelCanvas(canvas: HTMLCanvasElement, img: MonoFormatPixelImage) { const ctx = canvas.getContext("2d")!; ctx.fillStyle = "#000"; ctx.fillRect(0, 0, canvas.width, canvas.height); @@ -495,7 +493,7 @@ function drawPixelCanvas(canvas: HTMLCanvasElement, img: MonoDisplay.MonoFormatP interface PixelCanvasState { drawing: boolean; drawValue: number; } -const PixelCanvas: m.Component<{ img: MonoDisplay.MonoFormatPixelImage; onpaint: () => void }, PixelCanvasState> = { +const PixelCanvas: m.Component<{ img: MonoFormatPixelImage; onpaint: () => void }, PixelCanvasState> = { drawing: false, drawValue: 1, @@ -586,7 +584,7 @@ const PixelCanvas: m.Component<{ img: MonoDisplay.MonoFormatPixelImage; onpaint: // --- Image2D editor ----------------------------------------------------------- -const Image2DEditor: m.Component<{ si: number; ei: number; el: MonoDisplay.MonoFormatImage2D }> = { +const Image2DEditor: m.Component<{ si: number; ei: number; el: MonoFormatImage2D }> = { view({ attrs: { si, ei, el } }) { if (!el.image) { const w = (el as any).width || W; @@ -604,7 +602,7 @@ const Image2DEditor: m.Component<{ si: number; ei: number; el: MonoDisplay.MonoF interface AnimationEditorState { activeFrame: number; } -const AnimationEditor: m.Component<{ si: number; ei: number; el: MonoDisplay.MonoFormatAnimation }, AnimationEditorState> = { +const AnimationEditor: m.Component<{ si: number; ei: number; el: MonoFormatAnimation }, AnimationEditorState> = { activeFrame: 0, view({ attrs: { si, ei, el }, state }) { @@ -658,10 +656,10 @@ const AnimationEditor: m.Component<{ si: number; ei: number; el: MonoDisplay.Mon }, }; -const ElementItem: m.Component<{ si: number; ei: number; el: MonoDisplay.MonoFormatElement }> = { +const ElementItem: m.Component<{ si: number; ei: number; el: MonoFormatElement }> = { view({ attrs: { si, ei, el } }) { const isActive = activeSecIndex === si && activeElIndex === ei; - const typeStr = MonoDisplay.ElementTypeToString[el.type]; + const typeStr = ElementTypeToString[el.type]; const fields = EL_FIELDS[typeStr] || []; const flags = EL_FLAGS[typeStr] || []; @@ -678,10 +676,10 @@ const ElementItem: m.Component<{ si: number; ei: number; el: MonoDisplay.MonoFor m(".field.full", m("label", "Type"), m("select", { - onchange: (e: Event) => changeElType(si, ei, (e.target as HTMLSelectElement).value as MonoDisplay.ElementTypeName), + onchange: (e: Event) => changeElType(si, ei, (e.target as HTMLSelectElement).value as ElementTypeName), }, EL_TYPES.map(t => - m("option", { value: MonoDisplay.ElementTypeToString[t], selected: t === el.type }, MonoDisplay.ElementTypeToString[t]) + m("option", { value: ElementTypeToString[t], selected: t === el.type }, ElementTypeToString[t]) ) ), ), @@ -707,15 +705,15 @@ const ElementItem: m.Component<{ si: number; ei: number; el: MonoDisplay.MonoFor ) ), ) : null, - el.type === MonoDisplay.ElementType.Image2D + el.type === ElementType.Image2D ? m(".field.full", m("label", "Pixels"), - m(Image2DEditor, { si, ei, el: el as MonoDisplay.MonoFormatImage2D }), + m(Image2DEditor, { si, ei, el: el as MonoFormatImage2D }), ) - : el.type === MonoDisplay.ElementType.Animation + : el.type === ElementType.Animation ? m(".field.full", m("label", "Frames"), - m(AnimationEditor, { si, ei, el: el as MonoDisplay.MonoFormatAnimation }), + m(AnimationEditor, { si, ei, el: el as MonoFormatAnimation }), ) : null, ), @@ -728,7 +726,7 @@ const SectionCard: m.Component<{ si: number }> = { const section = file.sections[si]; if (!section) return null; const isActive = activeSecIndex === si; - const typeStr = MonoDisplay.SectionTypeToString[section.sectionType]; + const typeStr = SectionTypeToString[section.sectionType]; const hdr = m(`.sec-hdr${isActive ? ".active" : ""}`, { onclick: () => toggleSection(si) }, m("span.sec-arrow", "▶"), @@ -739,7 +737,7 @@ const SectionCard: m.Component<{ si: number }> = { }, "X"), ); - if (section.sectionType === MonoDisplay.SectionType.CustomFont) { + if (section.sectionType === SectionType.CustomFont) { return m(`.sec-card.open${isActive ? ".active" : ""}`, m(`.sec-hdr${isActive ? ".active" : ""}`, { onclick: () => toggleSection(si) }, m("span.sec-arrow", "▶"), @@ -754,7 +752,7 @@ const SectionCard: m.Component<{ si: number }> = { ); } - const elSection = section as MonoDisplay.MonoFormatElementsAlways | MonoDisplay.MonoFormatElementsTimespan; + const elSection = section as MonoFormatElementsAlways | MonoFormatElementsTimespan; return m(`.sec-card.open${isActive ? ".active" : ""}`, m(`.sec-hdr${isActive ? ".active" : ""}`, { onclick: () => toggleSection(si) }, @@ -766,7 +764,7 @@ const SectionCard: m.Component<{ si: number }> = { onclick: (e: Event) => { e.stopPropagation(); removeSection(si); }, }, "X"), ), - section.sectionType === MonoDisplay.SectionType.ElementsTimespan + section.sectionType === SectionType.ElementsTimespan ? m(".el-list", ([["Start Time", "startTimestamp"], ["Stop Time", "endTimestamp"]] as [string, string][]) .map(([label, key]) => { @@ -814,12 +812,12 @@ const MetaPanel: m.Component = { m("label", "Selected section"), section ? m("select.meta-val.green", { - value: MonoDisplay.SectionTypeToString[section.sectionType], + value: SectionTypeToString[section.sectionType], onchange: (e: Event) => activeSecIndex !== null && setSectionType(activeSecIndex, (e.target as HTMLSelectElement).value), }, - Object.values(MonoDisplay.SectionTypeToString).map(name => - m("option", { value: name, selected: name === MonoDisplay.SectionTypeToString[section.sectionType] }, name) + Object.values(SectionTypeToString).map(name => + m("option", { value: name, selected: name === SectionTypeToString[section.sectionType] }, name) ) ) : m("span.meta-val.green", "-"), diff --git a/ts/package.json b/ts/package.json index 3f121b8..813f3d4 100644 --- a/ts/package.json +++ b/ts/package.json @@ -4,16 +4,16 @@ "type": "module", "exports": { ".": { - "require": "./public/index.cjs", - "import": "./public/index.mjs", - "types": "./public/index.d.ts" + "require": "./dist/index.cjs", + "import": "./dist/index.mjs", + "types": "./dist/index.d.ts" } }, "scripts": { "build": "bun run buildcjs && bun run buildmjs && bun run builddts", - "buildcjs": "bun build src/index.ts --target browser --format cjs --outfile public/index.cjs", - "buildmjs": "bun build src/index.ts --target browser --format esm --outfile public/index.mjs", - "builddts": "bun build src/index.ts --dts --outfile public/index.d.ts", + "buildcjs": "bun build src/index.ts --target browser --format cjs --outfile dist/index.cjs", + "buildmjs": "bun build src/index.ts --target browser --format esm --outfile dist/index.mjs", + "builddts": "bun build src/index.ts --dts --outfile dist/index.d.ts", "test": "bun test" }, "devDependencies": {