Compare commits

..

59 Commits

Author SHA1 Message Date
flop debce36336 feat(ts-editor): display change support 4 days ago
flop 395e5efa54 feat(ts-editor): resize display support 4 days ago
Christian Seiler faeb89fb42 PHP/schedule.php: additional improvements 4 days ago
Christian Seiler 2417aee259 PHP: fix bug in serialization code 4 days ago
flop 8efc44d1c2 feat: mobile support for drag/touch 4 days ago
flop 2b60c30f7f feat(ts-editor): add mobile support 4 days ago
flop e7e60d4de6 docs: rename Specification.rst from v1 folder 6 days ago
flop 59d683dbd2 Merge branch 'feat/typescript_changes' 1 week ago
flop 2dafdacd53 chore(ts): remove old index 1 week ago
flop 23662243be chore(ts-editor): clean up 1 week ago
flop 1d1a7577dc chore: remove font 1 week ago
flop 2f763d9355 chore: move to examples folders 1 week ago
flop d901725c17 chore: move GPN files to its own folder 1 week ago
flop 3c44b97400 chore: remove Kulturanzeiger folder (avj20260523 1 week ago
flop ed4456b7a5 fix: bugfixes so its clean 2 weeks ago
flop 6370191553 fix: imports for browser 2 weeks ago
flop 2a63573c1b fix: remove old files 2 weeks ago
flop c37b172991 feat: fix exports 2 weeks ago
flop 23d99d6a41 feat: go for dist instead of public folder 2 weeks ago
flop a1e9110c14 feat: changes for library exports 2 weeks ago
flop 0d759e8315 refactor(editor): split out web editor 2 weeks ago
flop 2817d4a845 gatest wifi 2 weeks ago
flop 82d5ade615 chore: gpn24 wifi update 2 weeks ago
flop 4fc827e8d8 chore: gpn24 animated wifi default image 2 weeks ago
flop 79edde4319 feat: drag and drop support 2 weeks ago
flop 176e787a09 chore: GPN24 default screen 2 weeks ago
flop d8371d77cf chore: template updates for gpn24 2 weeks ago
flop 847b2c832b chore: updates for 0.text 2 weeks ago
flop 66c453fb58 feat: update line support 2 weeks ago
flop f5ba0ff0f6 chore: updated template for gpn 2 weeks ago
flop f7c02d7426 chore: updated template for gpn24 2 weeks ago
flop 47b210b2ec chore: more example bin files 2 weeks ago
flop a902c172dd feat: updated .bin file 2 weeks ago
flop 5d200a1dde updates 3 weeks ago
flop fc5abc0c23 fix(kulturanzeiger_avj): updated formats 3 weeks ago
flop 147945c751 feat(browser): add two more flags to text scroll 3 weeks ago
flop b45f51126e fix: top align fonts 3 weeks ago
flop 2f708a0ddc original files 3 weeks ago
flop 0abba3d954 feat(php): updates to live 3 weeks ago
flop 7d7ebf88c6 feat(php): update live 3 weeks ago
flop 3e34bd8404 feat(cpp): add nix build stuff 3 weeks ago
flop 82458df080 feat(php): live script 3 weeks ago
flop 3d73eca6f7 feat: fix dark/light style 3 weeks ago
flop c4775d7c23 feat: vibe color 3 weeks ago
flop 8a743736fe fix: selection bug 3 weeks ago
flop 495f76aaad fix: font rendering 3 weeks ago
flop 02c03d3f1f fix: default values 3 weeks ago
flop eefda87709 fix: redraw on reloads 3 weeks ago
flop 941ffd0f2c feat: clear all 3 weeks ago
flop db865a7666 feat: session persistence 3 weeks ago
flop dd4d7d25c7 fix: animation support 3 weeks ago
flop f300393122 feat: prevent easy reloading 3 weeks ago
flop 8dc2a5c3d8 feat: create nice image defaults 3 weeks ago
flop d50e17b1cc feat: image draw editor support 3 weeks ago
flop a61927ef1d feat: image editor support 3 weeks ago
flop 82ac1d56e0 fix: sections change instead of deleteing 3 weeks ago
flop 000f479b2f fix: timestamps for timespan sections 3 weeks ago
flop 555541e84f refactor: move to mithril 3 weeks ago
flop d74eed81b3 fix: multiple adjustments to rendering and updating fields 3 weeks ago
  1. 0
      GPN24/120px-GPN24.png
  2. 0
      GPN24/120px-GPN24_.png
  3. 0
      GPN24/120px-GPN24_wifi0.png
  4. 0
      GPN24/120px-GPN24_wifi1.png
  5. 0
      GPN24/120px-GPN24_wifi2.png
  6. 0
      GPN24/120px-GPN24_wifi3.png
  7. 0
      GPN24/300px-GPN24.png
  8. 0
      GPN24/300px-GPN24_g.png
  9. 0
      GPN24/300px-GPN24_g.svg
  10. 0
      GPN24/300px-GPN24_gray.png
  11. 0
      GPN24/300px-GPN24_gray2.png
  12. 0
      GPN24/300px-GPN24_gray3.png
  13. 0
      GPN24/300px-GPN24_gray3.svg
  14. 0
      GPN24/300px-GPN24_gray4.svg
  15. BIN
      cpp/Kulturanzeiger/Artikel1.bin
  16. BIN
      cpp/Kulturanzeiger/Artikel1.png
  17. BIN
      cpp/Kulturanzeiger/Artikel21.bin
  18. BIN
      cpp/Kulturanzeiger/Artikel21.png
  19. BIN
      cpp/Kulturanzeiger/Frosch161.bin
  20. BIN
      cpp/Kulturanzeiger/Frosch161.png
  21. BIN
      cpp/Kulturanzeiger/LaufSpruch1.bin
  22. BIN
      cpp/Kulturanzeiger/LaufSpruch1.png
  23. BIN
      cpp/Kulturanzeiger/LaufSpruch2.bin
  24. BIN
      cpp/Kulturanzeiger/LaufSpruch2.png
  25. BIN
      cpp/Kulturanzeiger/LaufSpruch3.bin
  26. BIN
      cpp/Kulturanzeiger/LaufSpruch3.png
  27. BIN
      cpp/Kulturanzeiger/MvAVJ.bin
  28. BIN
      cpp/Kulturanzeiger/MvAVJ.png
  29. BIN
      cpp/Kulturanzeiger/NotWidersetzen.bin
  30. BIN
      cpp/Kulturanzeiger/NotWidersetzen.png
  31. BIN
      cpp/Kulturanzeiger/Schildkroete.bin
  32. BIN
      cpp/Kulturanzeiger/Schildkroete.png
  33. BIN
      cpp/Kulturanzeiger/Widersetzen.bin
  34. BIN
      cpp/Kulturanzeiger/Widersetzen.png
  35. BIN
      cpp/Kulturanzeiger/Widersetzen1.bin
  36. BIN
      cpp/Kulturanzeiger/Widersetzen1.png
  37. BIN
      cpp/Kulturanzeiger/Zitat1.bin
  38. BIN
      cpp/Kulturanzeiger/Zitat1.png
  39. BIN
      cpp/Kulturanzeiger/Zitat2.bin
  40. BIN
      cpp/Kulturanzeiger/Zitat2.png
  41. BIN
      cpp/Kulturanzeiger/Zitat3.bin
  42. BIN
      cpp/Kulturanzeiger/Zitat3.png
  43. 0
      examples/v1/franzwerk.bin
  44. 0
      examples/v1/gpn24.bin
  45. 0
      examples/v1/template.bin
  46. 0
      examples/v1/time.bin
  47. 0
      examples/v1/time_nice.bin
  48. 2
      php/monoformat_structured.php
  49. 29
      php/schedule.php
  50. 1042
      ts-editor/dist_old/index.html
  51. 23
      ts-editor/index.html
  52. 68
      ts-editor/mobile.css
  53. 102
      ts-editor/src/browser.ts
  54. 41
      ts-editor/style.css
  55. 1042
      ts/dist_old/index.html
  56. 5
      ts/src/driver.ts
  57. BIN
      u8g2_font_5x7_tf.u8g2font

Before

Width:  |  Height:  |  Size: 403 B

After

Width:  |  Height:  |  Size: 403 B

Before

Width:  |  Height:  |  Size: 408 B

After

Width:  |  Height:  |  Size: 408 B

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

@ -26,7 +26,7 @@ function serializePixels(array $pixels): string {
function unserializePixels(int $n, string $serialized): array {
$nBytes = intdiv($n + 7, 8);
if (strlen($serialized) != $nBytes) {
$actual = strlen($serializd);
$actual = strlen($serialized);
throw new \ValueError("Could not unserialize a pixel bitmap: the size $actual does not equal the expected $nBytes");
}
$result = array_fill(0, $n, false);

@ -1,5 +1,11 @@
<?php
$roomMapping = [
];
$passThroughMapping = [
];
include_once("monoformat_schema.php");
include_once("monoformat_structured.php");
@ -23,8 +29,27 @@ function replaceTalkInfo($str, $talks) {
}, $str);
}
$roomMapping = [
];
if (isset($_GET["mac"]) and array_key_exists($_GET["mac"], $passThroughMapping)) {
$fn = $passThroughMapping[$_GET["mac"]];
if (is_dir($fn)) {
$d = opendir($fn);
$files = [];
while (($e = readdir($d)) !== false) {
if (str_ends_with($e, ".bin")) {
array_push($files, $fn . "/" . $e);
}
}
sort($files);
if (!count($files)) {
die("No files found");
}
$n = (time() / 60) % count($files);
$fn = $files[$n];
}
Header("Content-Type: application/octet-stream");
readfile($fn);
exit(0);
}
if (!isset($_GET["mac"]) or !array_key_exists($_GET["mac"], $roomMapping)) {
/* We didn't find this device in the mapping, so let's just

File diff suppressed because it is too large Load Diff

@ -5,12 +5,12 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<title>MonoDisplay Editor</title>
<script>!function(){var t=localStorage.getItem('theme');t&&document.documentElement.setAttribute('data-theme',t)}();</script>
<link href="style.css" rel="stylesheet"/>
<script>!function () { var t = localStorage.getItem('theme'); t && document.documentElement.setAttribute('data-theme', t) }();</script>
<link href="style.css" rel="stylesheet" />
<link href="mobile.css" rel="stylesheet" />
</head>
<body>
<div id="topbar">
<span class="app-name">MonoDisplay</span>
<div class="tb-sep"></div>
@ -52,10 +52,13 @@
<div class="tb-sep"></div>
<button class="tb-btn" id="theme-toggle" onclick="cycleTheme()">⊙ auto</button>
</div>
<div id="main">
<div id="left">
<span class="pv-label">preview · 120 × 60</span>
<span class="pv-label">preview · <select onchange="changeDisplayLayout()">
<option>120 × 60</option>
<option>120 × 40</option>
</select></span>
</span>
<div id="display-box">
<canvas id="canvas_root" width="120" height="60"></canvas>
</div>
@ -87,25 +90,27 @@
</div>
</div>
</div>
<div id="right">
<div id="right-hdr">
<span class="rh-title">sections</span>
<button class="tb-btn" id="mob-add-section" onclick="addSection()">
<svg viewBox="0 0 24 24">
<line x1="12" y1="5" x2="12" y2="19" />
<line x1="5" y1="12" x2="19" y2="12" />
</svg>
</button>
</div>
<div id="sections-wrap">
<div class="empty-state">No sections yet.<br />Use <b>Add section</b> to get started.</div>
</div>
</div>
</div>
<!-- confirm dialog -->
<div id="confirm-overlay">
<div id="confirm-box">
<div id="confirm-msg"></div>
<div id="confirm-btns"></div>
</div>
</div>
<script src="./public/mono-display.js"></script>
</body>

@ -0,0 +1,68 @@
@media (max-width: 640px) {
#topbar {
overflow-x: auto;
overflow-y: hidden;
scrollbar-width: none;
-webkit-overflow-scrolling: touch;
gap: 6px;
padding: 0 8px;
}
#topbar::-webkit-scrollbar {
display: none;
}
#topbar>* {
flex-shrink: 0;
}
#topbar .tb-btn {
font-size: 0;
gap: 0;
padding: 3px 8px;
}
#topbar .tb-btn svg {
width: 15px;
height: 15px;
}
#topbar #theme-toggle {
font-size: 11px;
}
#topbar button[onclick="addSection()"] {
display: none;
}
#mob-add-section {
display: flex;
}
#topbar [style*="flex:1"] {
display: none;
}
#main {
flex-direction: column;
overflow-y: auto;
}
#left,
#right {
width: 100%;
border-right: none;
flex-shrink: 0;
}
#left {
border-bottom: 1px solid var(--bd-inner);
padding: 10px;
gap: 8px;
}
#display-box {
aspect-ratio: 2/1;
width: 100%;
}
}

@ -26,7 +26,7 @@ import {
} from "libmonoformat";
const W = 120, H = 60;
let W = 120, H = 60;
// --- State -------------------------------------------------------------------
let file: MonoDisplayFile = new MonoDisplayFile([]);
@ -185,6 +185,15 @@ async function guardDirty(): Promise<boolean> {
);
}
function changeDisplayLayout() {
const sel = document.querySelector('.pv-label select') as HTMLSelectElement;
const [w, h] = sel.value.split('×').map(s => parseInt(s.trim()));
W = w as number;
H = h as number;
((window as any)._mdDriver as MonoDisplayDriver).setSize(W, H);
((window as any)._mdDriver as MonoDisplayDriver).load(() => Promise.resolve(file.toBuffer()));
}
// --- Helpers -----------------------------------------------------------------
function newSec(): MonoFormatElementsAlways {
return {
@ -425,7 +434,7 @@ function triggerPreview() {
function buildPreview() {
if (!(window as any)._mdDriver)
(window as any)._mdDriver = new MonoDisplayDriver("canvas_root", { onColor: "#EC0", offColor: "#000", fps: 25 });
(window as any)._mdDriver.load(() => Promise.resolve(file.toBuffer()));
changeDisplayLayout();
}
// --- Load / Export -----------------------------------------------------------
@ -518,82 +527,99 @@ const PixelCanvas: m.Component<{ img: MonoFormatPixelImage; onpaint: () => void
vnode.state.drawing = false;
vnode.state.drawValue = 1;
},
view({ attrs: { img, onpaint }, state }) {
function pixelFromEvent(e: MouseEvent): { x: number; y: number } | null {
const canvas = e.currentTarget as HTMLCanvasElement;
view({ attrs: { img, onpaint }, state: s }) {
function pixelFromCoords(canvas: HTMLCanvasElement, clientX: number, clientY: number) {
const rect = canvas.getBoundingClientRect();
const scaleX = canvas.width / rect.width;
const scaleY = canvas.height / rect.height;
const x = Math.floor((e.clientX - rect.left) * scaleX / PIXEL_SCALE);
const y = Math.floor((e.clientY - rect.top) * scaleY / PIXEL_SCALE);
const x = Math.floor((clientX - rect.left) * scaleX / PIXEL_SCALE);
const y = Math.floor((clientY - rect.top) * scaleY / PIXEL_SCALE);
if (x < 0 || x >= img.width || y < 0 || y >= img.height) return null;
return { x, y };
}
function paint(e: MouseEvent) {
const p = pixelFromEvent(e);
function paintAt(canvas: HTMLCanvasElement, clientX: number, clientY: number) {
const p = pixelFromCoords(canvas, clientX, clientY);
if (!p) return;
img.pixels[getPixelIndex(img, p.x, p.y)] = state.drawValue;
img.pixels[getPixelIndex(img, p.x, p.y)] = s.drawValue;
onpaint();
drawPixelCanvas(e.currentTarget as HTMLCanvasElement, img);
drawPixelCanvas(canvas, img);
}
function paint(e: MouseEvent) {
paintAt(e.currentTarget as HTMLCanvasElement, e.clientX, e.clientY);
}
function attachTouch(canvas: HTMLCanvasElement) {
canvas.addEventListener("touchstart", (e: TouchEvent) => {
e.preventDefault();
s.drawing = true;
const touch = e.changedTouches[0];
const p = pixelFromCoords(canvas, touch.clientX, touch.clientY);
if (p) s.drawValue = img.pixels[getPixelIndex(img, p.x, p.y)] ? 0 : 1;
paintAt(canvas, touch.clientX, touch.clientY);
}, { passive: false });
canvas.addEventListener("touchmove", (e: TouchEvent) => {
e.preventDefault();
if (!s.drawing) return;
const touch = e.changedTouches[0];
paintAt(canvas, touch.clientX, touch.clientY);
}, { passive: false });
canvas.addEventListener("touchend", (e) => { e.preventDefault(); s.drawing = false; }, { passive: false });
canvas.addEventListener("touchcancel", (e) => { e.preventDefault(); s.drawing = false; }, { passive: false });
}
return m("canvas.pixel-editor", {
width: img.width * PIXEL_SCALE,
height: img.height * PIXEL_SCALE,
oncreate: ({ dom }: m.VnodeDOM) => drawPixelCanvas(dom as HTMLCanvasElement, img),
oncreate: ({ dom }: m.VnodeDOM) => {
const canvas = dom as HTMLCanvasElement;
drawPixelCanvas(canvas, img);
attachTouch(canvas);
},
onupdate: ({ dom }: m.VnodeDOM) => drawPixelCanvas(dom as HTMLCanvasElement, img),
onmousedown: (e: MouseEvent) => {
state.drawing = true;
const p = pixelFromEvent(e);
if (p) state.drawValue = img.pixels[getPixelIndex(img, p.x, p.y)] ? 0 : 1;
s.drawing = true;
const p = pixelFromCoords(e.currentTarget as HTMLCanvasElement, e.clientX, e.clientY);
if (p) s.drawValue = img.pixels[getPixelIndex(img, p.x, p.y)] ? 0 : 1;
paint(e);
},
onmousemove: (e: MouseEvent) => { if (state.drawing) paint(e); },
onmouseup: () => { state.drawing = false; },
onmouseleave: () => { state.drawing = false; },
onmousemove: (e: MouseEvent) => { if (s.drawing) paint(e); },
onmouseup: () => { s.drawing = false; },
onmouseleave: () => { s.drawing = false; },
ondragover: (e: DragEvent) => {
e.preventDefault();
e.dataTransfer!.dropEffect = "copy";
},
ondrop: (e: DragEvent) => {
e.preventDefault();
const file = e.dataTransfer?.files[0];
if (!file || !file.type.startsWith("image/")) return;
const url = URL.createObjectURL(file);
const htmlImg = new Image();
htmlImg.onload = () => {
// Draw the dropped image into an offscreen canvas to read pixel data
const offscreen = document.createElement("canvas");
offscreen.width = htmlImg.width;
offscreen.height = htmlImg.height;
const ctx = offscreen.getContext("2d")!;
ctx.drawImage(htmlImg, 0, 0);
const imageData = ctx.getImageData(0, 0, htmlImg.width, htmlImg.height);
// Convert to your pixel format — adjust this to match your img structure
const scale = Math.min(1, 120 / htmlImg.width, 60 / htmlImg.height);
const w = Math.round(htmlImg.width * scale);
const h = Math.round(htmlImg.height * scale);
offscreen.width = w;
offscreen.height = h;
ctx.drawImage(htmlImg, 0, 0, w, h); // scales the image down while drawing
ctx.drawImage(htmlImg, 0, 0, w, h);
const imageData = ctx.getImageData(0, 0, w, h);
img.width = w;
img.height = h;
// then read imageData from the scaled offscreen canvas as before
img.pixels = new Uint8Array(w * h).map((_, i) => {
const r = imageData.data[i * 4] || 0;
const g = imageData.data[i * 4 + 1] || 0;
const b = imageData.data[i * 4 + 2] || 0;
const a = imageData.data[i * 4 + 3] || 0;
// transparent = 0, dark pixels = 1, light pixels = 0
const r = imageData.data[i * 4];
const g = imageData.data[i * 4 + 1];
const b = imageData.data[i * 4 + 2];
const a = imageData.data[i * 4 + 3];
return a > 128 && (r * 299 + g * 587 + b * 114) < 128_000 ? 0 : 1;
});
URL.revokeObjectURL(url);
m.redraw();
};
@ -916,7 +942,7 @@ async function clearAll() {
}
// Expose globals referenced by topbar inline handlers
Object.assign(window, { loadBin, exportBin, addSection, clearAll, cycleTheme });
Object.assign(window, { loadBin, exportBin, addSection, clearAll, cycleTheme, changeDisplayLayout });
// window.addEventListener("beforeunload", (e) => {
// if (isDirty) e.preventDefault();

@ -11,7 +11,7 @@
--bg-input: #0a0a0a;
--bg-canvas: #000;
--bg-xhover: #1e1010;
--bg-overlay: rgba(0,0,0,.6);
--bg-overlay: rgba(0, 0, 0, .6);
--bd: #2a2a2a;
--bd-inner: #1e1e1e;
--bd-deep: #1c1c1c;
@ -49,7 +49,7 @@
--bg-input: #fff;
--bg-canvas: #fff;
--bg-xhover: #ffe8e8;
--bg-overlay: rgba(0,0,0,.4);
--bg-overlay: rgba(0, 0, 0, .4);
--bd: #d0d0d0;
--bd-inner: #ddd;
--bd-deep: #e0e0e0;
@ -87,7 +87,7 @@
--bg-input: #fff;
--bg-canvas: #fff;
--bg-xhover: #ffe8e8;
--bg-overlay: rgba(0,0,0,.4);
--bg-overlay: rgba(0, 0, 0, .4);
--bd: #d0d0d0;
--bd-inner: #ddd;
--bd-deep: #e0e0e0;
@ -252,7 +252,8 @@ body {
gap: 5px;
margin-top: 6px
}
#demo-btns > div {
#demo-btns>div {
display: contents;
}
@ -263,17 +264,20 @@ canvas.pixel-editor {
max-width: 100%;
border: 1px solid var(--bd-inner);
}
.anim-editor {
display: flex;
flex-direction: column;
gap: 4px;
}
.anim-frame-tabs {
display: flex;
flex-wrap: wrap;
gap: 3px;
align-items: center;
}
.anim-frame-tab {
display: flex;
align-items: center;
@ -285,10 +289,12 @@ canvas.pixel-editor {
font-size: 11px;
user-select: none;
}
.anim-frame-tab.active {
border-color: var(--accent, #EC0);
color: var(--accent, #EC0);
}
.x-btn-sm {
background: none;
border: none;
@ -299,7 +305,10 @@ canvas.pixel-editor {
line-height: 1;
opacity: 0.6;
}
.x-btn-sm:hover { opacity: 1; }
.x-btn-sm:hover {
opacity: 1;
}
#sec-meta {
background: var(--bg-sunken);
@ -680,3 +689,25 @@ select.meta-val {
.cb.primary:hover {
background: var(--bg-active)
}
#mob-add-section {
display: none;
}
canvas.pixel-editor {
touch-action: none;
/* belt-and-suspenders alongside preventDefault */
-webkit-user-select: none;
user-select: none;
}
.pv-label select {
background: var(--bg-input);
color: var(--ac);
border: 1px solid var(--bd-inner);
border-radius: 3px;
padding: 1px 14px;
font-family: monospace;
font-size: 10px;
letter-spacing: .1em;
}

File diff suppressed because it is too large Load Diff

@ -88,6 +88,11 @@ export class MonoDisplayDriver {
}
}
setSize(w: number, h: number) {
this.opts.displayHeight = h;
this.opts.displayWidth = w;
}
stop(): void { this.renderer?.stop(); }
}

Binary file not shown.
Loading…
Cancel
Save