diff --git a/index.html b/index.html
index 0fd6071..fcb9ea2 100644
--- a/index.html
+++ b/index.html
@@ -4,7 +4,7 @@
-
+
diff --git a/package.json b/package.json
index 43e16ab..dd2036d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "amerc-site",
- "version": "0.60.0-canvasperf",
+ "version": "0.61.0-syntax",
"private": true,
"type": "module",
"scripts": {
diff --git a/src/DocsApp.jsx b/src/DocsApp.jsx
index 545154e..0d4e6ef 100644
--- a/src/DocsApp.jsx
+++ b/src/DocsApp.jsx
@@ -6,6 +6,22 @@ import { copyToast } from './toast.js';
marked.setOptions({ breaks: true });
+// Minimal, safe syntax highlighter: strings, numbers, keywords only.
+// No comment rule on purpose — '//' inside URLs (https://) must never be eaten.
+const esc = (s) => s.replace(/[&<>]/g, (c) => ({ '&': '&', '<': '<', '>': '>' }[c]));
+const HL_RE = /("(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|`(?:\\.|[^`\\])*`)|(\b\d+(?:\.\d+)?\b)|\b(const|let|var|function|return|while|do|done|if|then|else|fi|for|true|false|null|async|await|new|export|import|setInterval|setTimeout|fetch|sleep|curl|JSON|Math|console)\b/g;
+function highlightCode(code) {
+ let out = '', last = 0, m;
+ HL_RE.lastIndex = 0;
+ while ((m = HL_RE.exec(code))) {
+ out += esc(code.slice(last, m.index));
+ const cls = m[1] ? 'hl-str' : m[2] ? 'hl-num' : 'hl-kw';
+ out += `${esc(m[0])}`;
+ last = m.index + m[0].length;
+ }
+ return out + esc(code.slice(last));
+}
+
function DocsWorkspace({ canEdit }) {
const [docs, setDocs] = useState([]);
const [sel, setSel] = useState(null);
@@ -30,6 +46,8 @@ function DocsWorkspace({ canEdit }) {
if (!el || editing) return;
el.querySelectorAll('pre').forEach((pre) => {
if (pre.parentElement?.classList.contains('docs-code')) return;
+ const codeEl = pre.querySelector('code') || pre;
+ codeEl.innerHTML = highlightCode(codeEl.textContent);
const wrap = document.createElement('div'); wrap.className = 'docs-code';
const btn = document.createElement('button'); btn.type = 'button'; btn.className = 'docs-copy'; btn.textContent = 'copy';
btn.addEventListener('click', () => copyToast(pre.innerText, 'Copied'));
diff --git a/src/Scene2D.jsx b/src/Scene2D.jsx
index dfbf13d..b077bd7 100644
--- a/src/Scene2D.jsx
+++ b/src/Scene2D.jsx
@@ -7,7 +7,7 @@ import Account from './Account.jsx';
import TavernGame from './TavernGame.jsx';
import { api } from './api.js';
-const RELEASE = '0.60.0-canvasperf';
+const RELEASE = '0.61.0-syntax';
const NAV = [
{ id: 'home', label: 'Tavern' },
diff --git a/src/styles.css b/src/styles.css
index 4fae3d1..be1e562 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -1426,3 +1426,8 @@ button {
/* keyboard focus indicators — visible for keyboard users only (a11y, 0.59) */
:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }
.gm-cta-primary:focus-visible, .px-action:focus-visible { outline-color: #f3d27a; }
+
+/* docs syntax highlight tokens (0.61) */
+.docs-render pre code .hl-str { color: #9ce5a4; }
+.docs-render pre code .hl-num { color: #f0b86a; }
+.docs-render pre code .hl-kw { color: #c79aef; }