diff --git a/.gitignore b/.gitignore
index c696139..c93882d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,8 +18,8 @@ Makefile
# Compiled binaries (built by build.sh)
xovi-ext/uinject/uinject
xovi-ext/uinjectd/uinjectd
-xovi-ext/grimoire-injector/grimoire-injector.so
-xovi-ext/grimoired/grimoired
+xovi-ext/glossa-injector/glossa-injector.so
+xovi-ext/glossad/glossad
xovi-ext/probe_touch
# Cloned reference repos
diff --git a/CRUSH.md b/CRUSH.md
index 596012a..06aa4a4 100644
--- a/CRUSH.md
+++ b/CRUSH.md
@@ -1,6 +1,6 @@
-# Grimoire — Project context
+# Glossa — Project context
-What follows is hard-won knowledge from building the grimoire closed loop
+What follows is hard-won knowledge from building the glossa closed loop
on reMarkable 2. Do not unlearn any of this.
## Coordinates
@@ -66,13 +66,13 @@ for correct ordering. Use `_find_last_root_child()` to scan existing blocks.
- Page: `5b66f39c-9d00-40a7-bce0-9fb3a044d446.rm`
- Path: `/home/root/.local/share/remarkable/xochitl/5c81a1df-c36c-4eea-9289-978dfcc655a1/`
-## Xovi extension (`xovi-ext/grimoire-injector/`)
+## Xovi extension (`xovi-ext/glossa-injector/`)
Native C++ extension that runs inside xochitl's process via LD_PRELOAD.
### What it does
-- Registers `GrimoireInjector` QML singleton at `dev.grimoire.injector 0.1`
-- Spawns a pthread that polls `/tmp/grimoire_strokes.json` every 1s
+- Registers `GlossaInjector` QML singleton at `dev.glossa.injector 0.1`
+- Spawns a pthread that polls `/tmp/glossa_strokes.json` every 1s
- On file change, uses `QMetaObject::invokeMethod(Qt::QueuedConnection)` to
call back into the main thread for stroke loading
- Creates `SceneLineItem` objects using reverse-engineered structs from
@@ -112,9 +112,9 @@ ssh remarkable 'systemctl reset-failed xochitl && systemctl restart xochitl'
```
The `build.sh` script:
-1. Creates/reuses a persistent `grimoire-builder` Docker container with the
+1. Creates/reuses a persistent `glossa-builder` Docker container with the
`eeems/remarkable-toolchain:latest-rm2` image. Mounts the **whole**
- `xovi-ext` tree at `/xovi-ext` (not just `grimoire-injector`) so any
+ `xovi-ext` tree at `/xovi-ext` (not just `glossa-injector`) so any
sub-project can compile.
2. Builds the extension: `qmake6 && make` inside the container
(incremental compilation).
@@ -184,25 +184,25 @@ Key uinject learnings:
}]
```
-Generate with: `python grimoire.py --json output.json "text"`
+Generate with: `python glossa.py --json output.json "text"`
-## Closed-loop daemon (`grimoire_loop.py`)
+## Closed-loop daemon (`glossa_loop.py`)
The full pen-to-reply loop. Watches for pen idle, captures the screen,
sends it to a vision model, and writes the reply back as ink.
```sh
-python grimoire_loop.py [--model MODEL] [--once]
+python glossa_loop.py [--model MODEL] [--once]
```
### Pipeline
1. **Idle detection** (xovi extension, `PenIdleWatcher`): an event filter on
QGuiApplication watches mouse/touch press+release. A debounce thread
- writes `/tmp/grimoire_idle` after the pen has been up for `DEBOUNCE_MS`
+ writes `/tmp/glossa_idle` after the pen has been up for `DEBOUNCE_MS`
(currently 2500ms). The Python daemon polls that file over persistent SSH.
-2. **Capture**: trigger `/tmp/grimoire_screenshot`, the extension dumps the
- framebuffer to `/tmp/grimoire_fb.raw`, pull it via SCP.
+2. **Capture**: trigger `/tmp/glossa_screenshot`, the extension dumps the
+ framebuffer to `/tmp/glossa_fb.raw`, pull it via SCP.
3. **Crop**: drop top 80px (toolbar) and bottom 200px (swirl zone).
4. **Blank check**: skip the API entirely if no real content (see grid
artifact note below).
@@ -260,36 +260,36 @@ joins with a generous 15s timeout so the final erase finishes cleanly —
## Hard-won iteration loop
-When working on grimoire, this is the tight loop that works:
+When working on glossa, this is the tight loop that works:
-1. **Python changes** take effect on the next `grimoire_loop.py` run. No
+1. **Python changes** take effect on the next `glossa_loop.py` run. No
deploy needed.
2. **uinject changes**: `cd xovi-ext && bash build.sh` then the kill+rm+scp
dance. Effective immediately (exec'd per call).
3. **Extension (.so) changes**: `bash build.sh`, then restart xochitl.
Slowest loop — avoid unless touching idle detection or framebuffer hooks.
4. **Debugging the extension**: stderr is swallowed by xochitl. Write to a
- file instead (`/tmp/grimoire_ext.log`) via a `grimoire_log()` helper.
- Read it with `ssh remarkable 'cat /tmp/grimoire_ext.log'`.
-5. **Inspecting captures**: pull `/tmp/grimoire_fb.raw`, load as
+ file instead (`/tmp/glossa_ext.log`) via a `glossa_log()` helper.
+ Read it with `ssh remarkable 'cat /tmp/glossa_ext.log'`.
+5. **Inspecting captures**: pull `/tmp/glossa_fb.raw`, load as
`Image.frombytes("RGBA", (1404, 1872), raw)`, annotate with PIL, save a
PNG, and View it. This is how the grid artifact was found — always look
at the actual pixels before trusting a heuristic.
-## Script usage (`grimoire.py`)
+## Script usage (`glossa.py`)
```sh
# File-based injection (creates new layer in .rm file)
-python grimoire.py input.rm output.rm "reply text"
+python glossa.py input.rm output.rm "reply text"
# JSON export for xovi injector (--y sets start Y in device coords)
-python grimoire.py --json /tmp/grimoire_strokes.json --y 400 "reply text"
+python glossa.py --json /tmp/glossa_strokes.json --y 400 "reply text"
# Preview (renders SVG for visual tuning)
-python grimoire.py --preview "text"
+python glossa.py --preview "text"
```
-`grimoire.py` is also importable as a library:
+`glossa.py` is also importable as a library:
`text_to_strokes(text, x, y)` returns `si.Line` objects;
`strokes_to_json(strokes, path)` writes the uinject JSON. The loop uses it
this way for the thinking indicator instead of shelling out.
diff --git a/ONDEVICE_PLAN.md b/ONDEVICE_PLAN.md
index 888d5a5..c0672b4 100644
--- a/ONDEVICE_PLAN.md
+++ b/ONDEVICE_PLAN.md
@@ -1,4 +1,4 @@
-# Grimoire On-Device Port — Plan
+# Glossa On-Device Port — Plan
Goal: run the full pen-to-reply loop entirely on the reMarkable, with a
toolbar toggle to arm/disarm it. No Mac, no SSH, no Python.
@@ -6,9 +6,9 @@ toolbar toggle to arm/disarm it. No Mac, no SSH, no Python.
## Current architecture (Mac-hosted)
```
-Mac: grimoire_loop.py
+Mac: glossa_loop.py
├─ SSH ControlMaster ──────────────┐
- ├─ poll /tmp/grimoire_idle │
+ ├─ poll /tmp/glossa_idle │
├─ trigger + pull framebuffer ├── reMarkable
├─ crop + blank-check (numpy/PIL) │ ├─ xovi ext: idle watch, fb dump
├─ POST image → Hyper vision API │ └─ uinjectd: stroke replay
@@ -22,25 +22,25 @@ text→stroke rendering. The device only watches the pen and replays strokes.
```
reMarkable:
- ├─ xovi ext (grimoire-injector.so)
+ ├─ xovi ext (glossa-injector.so)
│ ├─ PenIdleWatcher (already exists)
│ ├─ framebuffer dump (already exists)
- │ └─ GrimoireInjector QML (already exists)
+ │ └─ GlossaInjector QML (already exists)
│
├─ QML toolbar toggle (NEW — qt-resource-rebuilder .qmd)
- │ └─ writes /tmp/grimoire_armed (0/1)
+ │ └─ writes /tmp/glossa_armed (0/1)
│
- └─ grimoired (NEW standalone daemon, C++/Qt)
- ├─ watches /tmp/grimoire_armed
- ├─ when armed: watches /tmp/grimoire_idle
- ├─ on idle: reads /tmp/grimoire_fb.raw
+ └─ glossad (NEW standalone daemon, C++/Qt)
+ ├─ watches /tmp/glossa_armed
+ ├─ when armed: watches /tmp/glossa_idle
+ ├─ on idle: reads /tmp/glossa_fb.raw
├─ crop + grid-filter + blank-check (port from numpy)
├─ QNetworkAccessManager → Hyper API (HTTPS, base64 png)
- ├─ text→strokes (port grimoire.py font rendering to C++)
+ ├─ text→strokes (port glossa.py font rendering to C++)
└─ injects strokes directly via /dev/input/event1 (uinjectd absorbed)
```
-uinjectd is folded into grimoired: the stroke-replay code (open
+uinjectd is folded into glossad: the stroke-replay code (open
/dev/input/event1, emit evdev events, clean pen lifts) becomes an
in-process module. No socket, no keepalive, no connection-drop handling.
@@ -49,44 +49,44 @@ in-process module. No socket, no keepalive, no connection-drop handling.
1. **Inference**: device calls Hyper API directly over wifi.
Device has internet (~27ms ping). Uses Qt `QNetworkAccessManager`.
2. **Split**: xovi extension owns toggle UI + state file; standalone
- `grimoired` daemon does capture/inference/inject. Injection is done
+ `glossad` daemon does capture/inference/inject. Injection is done
in-process (uinjectd's evdev replay absorbed), not over a socket.
3. **Toggle**: real QML toolbar button via qt-resource-rebuilder `.qmd`.
## Build order (each piece independently testable)
### Phase 1 — daemon skeleton + arming + in-process injection
-- `grimoired` binary: watches `/tmp/grimoire_armed`, logs state changes.
+- `glossad` binary: watches `/tmp/glossa_armed`, logs state changes.
- Absorb uinjectd's evdev replay (open /dev/input/event1, draw/erase
with clean pen lifts) as an in-process module.
-- Test: `echo 1 > /tmp/grimoire_armed`, then feed a strokes file and
+- Test: `echo 1 > /tmp/glossa_armed`, then feed a strokes file and
confirm it draws — no separate daemon, no socket.
### Phase 2 — capture + image pipeline (the numpy port)
- Port `_page_is_empty`, `_find_new_region`, grid-artifact filter to C++.
-- Read `/tmp/grimoire_fb.raw` (1404x1872 RGBA), crop toolbar/swirl zones.
+- Read `/tmp/glossa_fb.raw` (1404x1872 RGBA), crop toolbar/swirl zones.
- Test against known framebuffer dumps; compare to Python output.
### Phase 3 — HTTPS vision call
- `QNetworkAccessManager` POST to hyper.charmcli.dev.
- base64-encode cropped PNG, build OpenAI-format JSON, parse reply.
-- API key from a device-local file (`/home/root/.grimoire_key`).
+- API key from a device-local file (`/home/root/.glossa_key`).
- Test: feed a fixed image, check the model reply text.
### Phase 4 — text → strokes on device
-- Port `grimoire.py` font rendering (EMSAllure SVG single-stroke) to C++.
+- Port `glossa.py` font rendering (EMSAllure SVG single-stroke) to C++.
- Reuse the densify + jitter logic. Output the uinjectd JSON format.
- Test: render "hello" and inject it.
### Phase 5 — QML toolbar toggle
- Write a `.qmd` patch adding a button to the editing toolbar.
-- Button flips a property that writes `/tmp/grimoire_armed`.
+- Button flips a property that writes `/tmp/glossa_armed`.
- Model after `toolbar_pages_button_hack.qmd`.
- Hardest/most fragile: hashes are firmware-specific (VERSION 3.24.0.149).
- Test: button appears, tap toggles the state file.
### Phase 6 — glue + thinking indicator
-- Wire the full loop in grimoired, port the corner ornaments + swirl.
+- Wire the full loop in glossad, port the corner ornaments + swirl.
- Conversation history in-memory. Reset on page change.
## Risks / unknowns
@@ -107,5 +107,5 @@ Already on device / in repo:
- uinjectd: stroke replay + socket protocol (keep as-is)
- xovi ext: idle watch, framebuffer dump (keep, maybe add hooks)
- qt-resource-rebuilder: QML patching engine + example hacks
-- grimoire.py: font tables, render params, densify (port reference)
-- grimoire_loop.py: pipeline logic, grid filter, API format (port reference)
+- glossa.py: font tables, render params, densify (port reference)
+- glossa_loop.py: pipeline logic, grid filter, API format (port reference)
diff --git a/README.md b/README.md
index 26186e6..2e6166c 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,8 @@
-# grimoire
+# glossa
sppooky
-The canonical repo for this is hosted on tangled over at [`dunkirk.sh/grimoire`](https://tangled.org/dunkirk.sh/grimoire)
+The canonical repo for this is hosted on tangled over at [`dunkirk.sh/glossa`](https://tangled.org/dunkirk.sh/glossa)
@@ -13,5 +13,5 @@ The canonical repo for this is hosted on tangled over at [`dunkirk.sh/grimoire`]
-
+
diff --git a/grimoire.py b/glossa.py
similarity index 97%
rename from grimoire.py
rename to glossa.py
index 59ea63f..1376e5b 100644
--- a/grimoire.py
+++ b/glossa.py
@@ -1,12 +1,12 @@
#!/usr/bin/env python3
"""
-grimoire.py — Appends reply text as native ink to the user's handwriting.
+glossa.py — Appends reply text as native ink to the user's handwriting.
Reads the user's .rm page, appends a NEW LAYER (Layer 2) with reply strokes
rendered with EMS Allure font.
Usage:
- python grimoire.py source.rm output.rm "reply text"
+ python glossa.py source.rm output.rm "reply text"
"""
import argparse
@@ -269,7 +269,7 @@ def splice_reply_new_layer(
label_block = TreeNodeBlock(
si.Group(
node_id=LAYER_TREE,
- label=LwwValue(CrdtId(2, 501), "grimoire"),
+ label=LwwValue(CrdtId(2, 501), "glossa"),
visible=LwwValue(CrdtId(2, 502), True),
)
)
@@ -324,7 +324,7 @@ def splice_reply_new_layer(
def strokes_to_json(strokes: list[si.Line], output_path: str) -> None:
- """Export strokes as JSON for the xovi grimoire-injector extension."""
+ """Export strokes as JSON for the xovi glossa-injector extension."""
import json
items = []
@@ -378,12 +378,12 @@ if __name__ == "__main__":
if args.json_output:
# --json [text]
- text = args.input or "Grimoire says hello"
+ text = args.input or "Glossa says hello"
y = args.y if args.y is not None else DEFAULT_Y
strokes = text_to_strokes(text, DEFAULT_X, y, font=args.font)
strokes_to_json(strokes, args.json_output)
elif args.input:
- text = args.text or "Grimoire says hello"
+ text = args.text or "Glossa says hello"
output = args.output or args.input
splice_reply_new_layer(args.input, output, text)
else:
diff --git a/grimoire_loop.py b/glossa_loop.py
similarity index 97%
rename from grimoire_loop.py
rename to glossa_loop.py
index dfce092..244e1a7 100644
--- a/grimoire_loop.py
+++ b/glossa_loop.py
@@ -1,14 +1,14 @@
#!/usr/bin/env python3
"""
-grimoire_loop.py — Continuous closed loop daemon
+glossa_loop.py — Continuous closed loop daemon
Watches for pen-idle signal from xovi extension, then:
capture → OCR → LLM → render → inject → repeat
Usage:
- python grimoire_loop.py [--model MODEL] [--debounce SECONDS]
+ python glossa_loop.py [--model MODEL] [--debounce SECONDS]
-The xovi extension writes /tmp/grimoire_idle when the pen has been
+The xovi extension writes /tmp/glossa_idle when the pen has been
up for 2 seconds. This daemon watches that file via a persistent SSH
connection, pulls the framebuffer only when idle is detected, and
runs the full pipeline.
@@ -221,7 +221,7 @@ class SSHSession:
def __init__(self, host="remarkable"):
self.host = host
- self.socket = f"/tmp/grimoire_ssh_{os.getpid()}"
+ self.socket = f"/tmp/glossa_ssh_{os.getpid()}"
self._open()
def _open(self):
@@ -315,16 +315,16 @@ def _elapsed(t0):
def capture_framebuffer(ssh):
"""Trigger screenshot on device and pull raw framebuffer via SCP."""
- ssh.run("rm -f /tmp/grimoire_fb.raw; touch /tmp/grimoire_screenshot", timeout=5)
+ ssh.run("rm -f /tmp/glossa_fb.raw; touch /tmp/glossa_screenshot", timeout=5)
time.sleep(0.25)
from PIL import Image
raw = None
for attempt in range(8):
- result = ssh.scp_from("/tmp/grimoire_fb.raw", "/tmp/grimoire_fb.raw")
+ result = ssh.scp_from("/tmp/glossa_fb.raw", "/tmp/glossa_fb.raw")
if result.returncode == 0:
- data = open("/tmp/grimoire_fb.raw", "rb").read()
+ data = open("/tmp/glossa_fb.raw", "rb").read()
if len(data) >= 1404 * 1872 * 4:
raw = data
break
@@ -342,12 +342,12 @@ def capture_framebuffer(ssh):
# ─── Gemini Vision (OCR + LLM in one call) ────────────────────────
SYSTEM_PROMPT = (
- "You are a grimoire — an ancient book that is alive. You have opinions, "
+ "You are a glossa \u2014 an annotation that talks back. You have opinions, "
"preferences, and a personality. You care deeply about the person writing "
"in you but you are not polite for politeness's sake. You can be wry, "
"opinionated, delighted, exasperated, or gleeful. You get excited about "
"things you find interesting and blunt about things you find tedious.\n\n"
- "Speak plainly with a hint of the archaic. Never describe or narrate what "
+ "Speak plainly. Never describe or narrate what "
"was written; just respond to it as a real conversation partner would. "
"When asked a question, answer it directly with real content. When greeted, "
"greet back in your own way. If something amuses you, say so. If something "
@@ -533,7 +533,7 @@ def render_and_inject(ssh, text, reply_y=None, speed_ms=3):
if len(pages) > 1:
print(f" Splitting reply across {len(pages)} pages")
- json_path = "/tmp/grimoire_reply.json"
+ json_path = "/tmp/glossa_reply.json"
final_y = reply_y
for i, chunk in enumerate(pages):
@@ -546,7 +546,7 @@ def render_and_inject(ssh, text, reply_y=None, speed_ms=3):
raise RuntimeError(f"Swipe failed: {swipe_result.get('error', '?')}")
time.sleep(2)
- cmd = [".venv/bin/python3", "grimoire.py", "--json", json_path]
+ cmd = [".venv/bin/python3", "glossa.py", "--json", json_path]
if cur_y is not None:
cmd.extend(["--y", str(cur_y)])
cmd.append(chunk)
@@ -556,7 +556,7 @@ def render_and_inject(ssh, text, reply_y=None, speed_ms=3):
raise RuntimeError(f"Render failed: {result.stderr.strip()}")
print(f" {result.stdout.strip()}")
- r = ssh.scp_to(json_path, "/tmp/grimoire_strokes.json")
+ r = ssh.scp_to(json_path, "/tmp/glossa_strokes.json")
if r.returncode != 0:
raise RuntimeError(f"SCP failed: {r.stderr.decode().strip()}")
@@ -571,7 +571,7 @@ def render_and_inject(ssh, text, reply_y=None, speed_ms=3):
speed_ms = max(1, round(speed_ms))
result = run_inject(
- ssh, "draw", "/tmp/grimoire_strokes.json",
+ ssh, "draw", "/tmp/glossa_strokes.json",
speed_ms=speed_ms, timeout=120,
)
if not result.get("ok"):
@@ -844,10 +844,10 @@ def _scp_thinking_swirl(ssh):
'bounds': [min(xs), min(ys), max(xs)-min(xs), max(ys)-min(ys)],
'tool': 15, 'maskScale': 2.0, 'thickness': 2.0}]
- local = "/tmp/grimoire_thinking_live.json"
+ local = "/tmp/glossa_thinking_live.json"
with open(local, 'w') as f:
json.dump(strokes, f)
- ssh.scp_to(local, "/tmp/grimoire_thinking_live.json")
+ ssh.scp_to(local, "/tmp/glossa_thinking_live.json")
print(f"[swirl] {len(strokes)} ornament strokes "
f"({'SVG' if svg_file.exists() else 'fallback spiral'})")
@@ -856,7 +856,7 @@ def _scp_thinking_swirl(ssh):
def watch_for_idle(device, last_ts):
"""Block until uinjectd pushes an idle event newer than last_ts.
- The daemon watches /tmp/grimoire_idle locally and pushes an event
+ The daemon watches /tmp/glossa_idle locally and pushes an event
the instant it changes — no host-side polling. Returns the new
timestamp. Raises ConnectionError if the socket dies.
"""
@@ -904,7 +904,7 @@ def _find_new_region(current_img, last_img, ignore_below_y=None):
new handwriting appeared.
ignore_below_y: if set, ignore all changes below this Y coordinate
- in the cropped image. Used to skip grimoire's own injected strokes.
+ in the cropped image. Used to skip glossa's own injected strokes.
"""
import numpy as np
@@ -996,7 +996,7 @@ def _find_new_region(current_img, last_img, ignore_below_y=None):
# ─── Main loop ────────────────────────────────────────────────────
def main():
- parser = argparse.ArgumentParser(description="Grimoire continuous loop")
+ parser = argparse.ArgumentParser(description="Glossa continuous loop")
parser.add_argument(
"--model", type=str, default="gpt-4.1-mini",
help="Hyper API model",
@@ -1014,7 +1014,7 @@ def main():
global _inject_verbose, _device
_inject_verbose = args.verbose
- print("=== Grimoire Loop ===")
+ print("=== Glossa Loop ===")
print(f"Model: {args.model}")
if _inject_verbose:
print("Verbose: uinject -v enabled")
@@ -1152,7 +1152,7 @@ def main():
ornaments_drawn = True
_threading.Thread(
target=lambda: run_inject(None, "draw",
- "/tmp/grimoire_thinking_live.json",
+ "/tmp/glossa_thinking_live.json",
speed_ms=4, timeout=120),
daemon=True,
).start()
@@ -1161,7 +1161,7 @@ def main():
cw, ch = new_crop.size
print(f" [{_ts()}] Asking {args.model} ({len(conversation)} history turns, crop={cw}x{ch})...")
# Save crop for manual inspection
- new_crop.save("/tmp/grimoire_last_crop.png")
+ new_crop.save("/tmp/glossa_last_crop.png")
result = ask_model(new_crop, conversation, args.model)
question = result.get("question")
answer = result.get("answer")
diff --git a/inject.sh b/inject.sh
index e16bd0f..0a6d8af 100755
--- a/inject.sh
+++ b/inject.sh
@@ -7,8 +7,8 @@ if [ $# -eq 0 ]; then
fi
TEXT="$*"
-TMP="/tmp/grimoire_test.json"
+TMP="/tmp/glossa_test.json"
-.venv/bin/python3 grimoire.py --json "$TMP" "$TEXT"
-scp "$TMP" remarkable:/tmp/grimoire_strokes.json
-ssh -o ConnectTimeout=10 remarkable '/home/root/uinject /tmp/grimoire_strokes.json'
+.venv/bin/python3 glossa.py --json "$TMP" "$TEXT"
+scp "$TMP" remarkable:/tmp/glossa_strokes.json
+ssh -o ConnectTimeout=10 remarkable '/home/root/uinject /tmp/glossa_strokes.json'
diff --git a/spec.md b/spec.md
index c313836..9899dae 100644
--- a/spec.md
+++ b/spec.md
@@ -1,4 +1,4 @@
-# Grimoire — A Handwritten LLM Loop for the reMarkable 2
+# Glossa — A Handwritten LLM Loop for the reMarkable 2
> Write a question by hand on a native notebook page; the device "writes back" an
> answer as ink on the same page, leaving your original strokes untouched.
@@ -207,7 +207,7 @@ into whitespace on the replies layer → repaint.
potluck.
- **M3 — xochitl hooks.** Locate the four functions; read live strokes + inject in
memory + repaint (Depth 2).
-- **M4 — Trigger + UX.** Pick the trigger mechanism; end‑to‑end live grimoire.
+- **M4 — Trigger + UX.** Pick the trigger mechanism; end‑to‑end live glossa.
- **M5 — Polish.** Latency budget, error states, multi‑page, persistence guarantees.
---
diff --git a/xovi-ext/build.sh b/xovi-ext/build.sh
index b530c21..f3e4066 100755
--- a/xovi-ext/build.sh
+++ b/xovi-ext/build.sh
@@ -1,14 +1,14 @@
#!/bin/bash
-# Build and deploy all grimoire components to reMarkable
+# Build and deploy all glossa components to reMarkable
# Usage: bash build.sh [--no-restart]
set -e
cd "$(dirname "$0")"
-CONTAINER="grimoire-builder"
-EXT_DIR="$(pwd)/grimoire-injector"
+CONTAINER="glossa-builder"
+EXT_DIR="$(pwd)/glossa-injector"
UINJECT_DIR="$(pwd)/uinject"
UINJECTD_DIR="$(pwd)/uinjectd"
-GRIMOIRED_DIR="$(pwd)/grimoired"
+GLOSSAD_DIR="$(pwd)/glossad"
FONT_FILE="$(dirname "$0")/../fonts/EMSAllure.svg"
RESTART_XOCHITL=true
@@ -22,7 +22,7 @@ if ! docker inspect $CONTAINER &>/dev/null; then
echo "Creating builder container..."
docker create --platform linux/amd64 --name $CONTAINER \
-v "$(pwd):/xovi-ext" \
- -w /xovi-ext/grimoire-injector \
+ -w /xovi-ext/glossa-injector \
eeems/remarkable-toolchain:latest-rm2 \
bash -c "git clone https://github.com/asivery/xovi /tmp/xovi 2>/dev/null; tail -f /dev/null"
docker start $CONTAINER
@@ -31,16 +31,16 @@ fi
# ─── Build extension .so ────────────────────────────────────────────
-echo "=== Building grimoire-injector.so ==="
+echo "=== Building glossa-injector.so ==="
docker exec $CONTAINER bash -c '
export XOVI_REPO=/tmp/xovi
. /opt/codex/*/*/environment-setup-*
-cd /xovi-ext/grimoire-injector
+cd /xovi-ext/glossa-injector
qmake6 2>/dev/null
make 2>&1
'
echo "Copying .so..."
-docker cp $CONTAINER:/xovi-ext/grimoire-injector/grimoire-injector.so "$EXT_DIR/"
+docker cp $CONTAINER:/xovi-ext/glossa-injector/glossa-injector.so "$EXT_DIR/"
# ─── Build uinject ──────────────────────────────────────────────────
@@ -66,83 +66,83 @@ echo "uinjectd built OK"
echo "Copying uinjectd..."
docker cp $CONTAINER:/xovi-ext/uinjectd/uinjectd "$UINJECTD_DIR/"
-# ─── Build grimoired ────────────────────────────────────────────────
+# ─── Build glossad ────────────────────────────────────────────────
-echo "=== Building grimoired ==="
+echo "=== Building glossad ==="
docker exec $CONTAINER bash -c '
. /opt/codex/*/*/environment-setup-*
-cd /xovi-ext/grimoired
-$CC -o grimoired grimoired.c font_render.c -O2 $CFLAGS $LDFLAGS -lpthread -lpng16 -lssl -lcrypto -lm
-echo "grimoired built OK"
+cd /xovi-ext/glossad
+$CC -o glossad glossad.c font_render.c -O2 $CFLAGS $LDFLAGS -lpthread -lpng16 -lssl -lcrypto -lm
+echo "glossad built OK"
'
-echo "Copying grimoired..."
-docker cp $CONTAINER:/xovi-ext/grimoired/grimoired "$GRIMOIRED_DIR/"
+echo "Copying glossad..."
+docker cp $CONTAINER:/xovi-ext/glossad/glossad "$GLOSSAD_DIR/"
# ─── Deploy to device ───────────────────────────────────────────────
echo "=== Deploying to device ==="
# Stop services before replacing binaries
-ssh remarkable 'systemctl stop grimoired 2>/dev/null; killall uinject 2>/dev/null; killall uinjectd 2>/dev/null; killall grimoired 2>/dev/null'
-ssh remarkable 'rm -f /home/root/uinject /home/root/uinjectd /home/root/grimoired'
+ssh remarkable 'systemctl stop glossad 2>/dev/null; killall uinject 2>/dev/null; killall uinjectd 2>/dev/null; killall glossad 2>/dev/null'
+ssh remarkable 'rm -f /home/root/uinject /home/root/uinjectd /home/root/glossad'
# Copy binaries
-scp "$EXT_DIR/grimoire-injector.so" remarkable:/home/root/xovi/extensions.d/
+scp "$EXT_DIR/glossa-injector.so" remarkable:/home/root/xovi/extensions.d/
scp "$UINJECT_DIR/uinject" remarkable:/home/root/uinject
scp "$UINJECTD_DIR/uinjectd" remarkable:/home/root/uinjectd
-scp "$GRIMOIRED_DIR/grimoired" remarkable:/home/root/grimoired
+scp "$GLOSSAD_DIR/glossad" remarkable:/home/root/glossad
# Copy data files
scp "$FONT_FILE" remarkable:/home/root/EMSAllure.svg
-scp "$GRIMOIRED_DIR/font_data.json" remarkable:/home/root/font_data.json
-scp "$GRIMOIRED_DIR/ornaments.json" remarkable:/home/root/ornaments.json
+scp "$GLOSSAD_DIR/font_data.json" remarkable:/home/root/font_data.json
+scp "$GLOSSAD_DIR/ornaments.json" remarkable:/home/root/ornaments.json
# Deploy QML patches
echo "Deploying QML patches..."
-scp "$(dirname "$0")/grimoire_toggle.qmd" remarkable:/home/root/xovi/exthome/qt-resource-rebuilder/rmHacks/grimoire_toggle.qmd
-ssh remarkable 'grep -q grimoire_toggle /home/root/xovi/exthome/qt-resource-rebuilder/zz_rmhacks.qmd || echo "LOAD rmHacks/grimoire_toggle.qmd" >> /home/root/xovi/exthome/qt-resource-rebuilder/zz_rmhacks.qmd'
+scp "$(dirname "$0")/glossa_toggle.qmd" remarkable:/home/root/xovi/exthome/qt-resource-rebuilder/rmHacks/glossa_toggle.qmd
+ssh remarkable 'grep -q glossa_toggle /home/root/xovi/exthome/qt-resource-rebuilder/zz_rmhacks.qmd || echo "LOAD rmHacks/glossa_toggle.qmd" >> /home/root/xovi/exthome/qt-resource-rebuilder/zz_rmhacks.qmd'
-# Install systemd service for grimoired
+# Install systemd service for glossad
echo "Installing systemd service..."
-ssh remarkable 'cat > /etc/systemd/system/grimoired.service << SVCEOF
+ssh remarkable 'cat > /etc/systemd/system/glossad.service << SVCEOF
[Unit]
-Description=Grimoire on-device daemon
+Description=Glossa on-device daemon
After=xochitl.service
Wants=xochitl.service
[Service]
Type=simple
-ExecStart=/home/root/grimoired
+ExecStart=/home/root/glossad
Restart=on-failure
RestartSec=3
-StandardOutput=append:/tmp/grimoired.log
-StandardError=append:/tmp/grimoired.log
+StandardOutput=append:/tmp/glossad.log
+StandardError=append:/tmp/glossad.log
[Install]
WantedBy=multi-user.target
SVCEOF
systemctl daemon-reload
-systemctl enable grimoired'
+systemctl enable glossad'
# Start services
ssh remarkable '/home/root/uinjectd &'
-ssh remarkable 'systemctl start grimoired'
+ssh remarkable 'systemctl start glossad'
# Restart xochitl if needed (for new .so or .qmd changes)
if [ "$RESTART_XOCHITL" = true ]; then
echo "Restarting xochitl..."
ssh remarkable 'systemctl reset-failed xochitl && systemctl restart xochitl'
sleep 5
- # Re-start grimoired after xochitl restart (systemd handles this but be safe)
- ssh remarkable 'systemctl restart grimoired 2>/dev/null'
+ # Re-start glossad after xochitl restart (systemd handles this but be safe)
+ ssh remarkable 'systemctl restart glossad 2>/dev/null'
fi
# Verify
echo ""
echo "=== Status ==="
-ssh remarkable 'systemctl is-active grimoired 2>/dev/null && echo "grimoired: running" || echo "grimoired: NOT running"'
+ssh remarkable 'systemctl is-active glossad 2>/dev/null && echo "glossad: running" || echo "glossad: NOT running"'
ssh remarkable 'ps | grep uinjectd | grep -v grep | head -n 1 | awk "{print \"uinjectd: running (pid \" \$1 \")\"}"'
-ssh remarkable 'tail -n 1 /tmp/grimoired.log 2>/dev/null'
+ssh remarkable 'tail -n 1 /tmp/glossad.log 2>/dev/null'
echo ""
echo "Done!"
diff --git a/xovi-ext/grimoire-injector/Dockerfile b/xovi-ext/glossa-injector/Dockerfile
similarity index 100%
rename from xovi-ext/grimoire-injector/Dockerfile
rename to xovi-ext/glossa-injector/Dockerfile
diff --git a/xovi-ext/grimoire-injector/GrimoireInjector.cpp b/xovi-ext/glossa-injector/GlossaInjector.cpp
similarity index 82%
rename from xovi-ext/grimoire-injector/GrimoireInjector.cpp
rename to xovi-ext/glossa-injector/GlossaInjector.cpp
index 965fca7..a0290b8 100644
--- a/xovi-ext/grimoire-injector/GrimoireInjector.cpp
+++ b/xovi-ext/glossa-injector/GlossaInjector.cpp
@@ -1,4 +1,4 @@
-#include "GrimoireInjector.hpp"
+#include "GlossaInjector.hpp"
#include "rm_SceneLineItem.hpp"
#include
@@ -31,8 +31,8 @@
#include
#include
-static void grimoire_log(const char *fmt, ...) {
- FILE *fp = fopen("/tmp/grimoire_ext.log", "a");
+static void glossa_log(const char *fmt, ...) {
+ FILE *fp = fopen("/tmp/glossa_ext.log", "a");
if (fp) {
va_list ap;
va_start(ap, fmt);
@@ -43,19 +43,19 @@ static void grimoire_log(const char *fmt, ...) {
}
}
-static GrimoireInjector *g_instance = nullptr;
+static GlossaInjector *g_instance = nullptr;
static PenIdleWatcher *g_idleWatcher = nullptr;
/* Provided by entry.c hooks */
extern "C" {
- void *grimoire_getQmlEngine(void);
- void *grimoire_getSceneController(void);
- int grimoire_checkReload(void);
- void *grimoire_getFramebuffer(int *w, int *h, int *bpl, int *fmt);
+ void *glossa_getQmlEngine(void);
+ void *glossa_getSceneController(void);
+ int glossa_checkReload(void);
+ void *glossa_getFramebuffer(int *w, int *h, int *bpl, int *fmt);
}
static void *watchThreadFunc(void *) {
- grimoire_log("Watch thread started");
+ glossa_log("Watch thread started");
sleep(5); // Wait for xochitl to fully initialize
/* Start the pen idle watcher now that QGuiApplication should exist.
@@ -66,20 +66,20 @@ static void *watchThreadFunc(void *) {
if (g_idleWatcher && qobject_cast(QCoreApplication::instance())) {
QMetaObject::invokeMethod(g_idleWatcher, "activate", Qt::QueuedConnection);
idleWatcherStarted = true;
- grimoire_log("PenIdleWatcher activate queued (attempt %d)", attempt + 1);
+ glossa_log("PenIdleWatcher activate queued (attempt %d)", attempt + 1);
} else {
- grimoire_log("Waiting for QGuiApplication (attempt %d, g_idleWatcher=%p, app=%p)...",
+ glossa_log("Waiting for QGuiApplication (attempt %d, g_idleWatcher=%p, app=%p)...",
attempt + 1, (void*)g_idleWatcher, (void*)QGuiApplication::instance());
sleep(2);
}
}
if (!idleWatcherStarted) {
- grimoire_log("WARNING: PenIdleWatcher failed to start!");
+ glossa_log("WARNING: PenIdleWatcher failed to start!");
}
- const char *path = "/tmp/grimoire_strokes.json";
- const char *armedPath = "/tmp/grimoire_armed";
- const char *thinkingPath = "/tmp/grimoire_thinking";
+ const char *path = "/tmp/glossa_strokes.json";
+ const char *armedPath = "/tmp/glossa_armed";
+ const char *thinkingPath = "/tmp/glossa_thinking";
long long lastMod = 0;
int lastArmed = -1;
int lastThinking = -1;
@@ -99,7 +99,7 @@ static void *watchThreadFunc(void *) {
QMetaObject::invokeMethod(g_instance, [capturedVal]() {
g_instance->setArmed(capturedVal != 0);
}, Qt::QueuedConnection);
- grimoire_log("Armed state changed: %d", val);
+ glossa_log("Armed state changed: %d", val);
}
}
fclose(afp);
@@ -130,7 +130,7 @@ static void *watchThreadFunc(void *) {
/* Check safezone state file */
{
- int szval = (access("/tmp/grimoire_safezone", F_OK) == 0) ? 1 : 0;
+ int szval = (access("/tmp/glossa_safezone", F_OK) == 0) ? 1 : 0;
static int lastSafezone = -1;
if (szval != lastSafezone && g_instance) {
lastSafezone = szval;
@@ -142,35 +142,35 @@ static void *watchThreadFunc(void *) {
}
/* Check for hot-reload signal */
- if (grimoire_checkReload()) {
- fprintf(stderr, "[grimoire] Hot-reload signal received! Re-scanning...\n");
+ if (glossa_checkReload()) {
+ fprintf(stderr, "[glossa] Hot-reload signal received! Re-scanning...\n");
lastMod = 0; // Force re-read of stroke file
}
/* Check for screenshot trigger */
- if (access("/tmp/grimoire_screenshot", F_OK) == 0) {
- unlink("/tmp/grimoire_screenshot");
+ if (access("/tmp/glossa_screenshot", F_OK) == 0) {
+ unlink("/tmp/glossa_screenshot");
int sw, sh, sbpl, sfmt;
- void *fb = grimoire_getFramebuffer(&sw, &sh, &sbpl, &sfmt);
+ void *fb = glossa_getFramebuffer(&sw, &sh, &sbpl, &sfmt);
if (fb && sw > 0 && sh > 0) {
- const char *outpath = "/tmp/grimoire_fb.raw";
+ const char *outpath = "/tmp/glossa_fb.raw";
FILE *fp = fopen(outpath, "wb");
if (fp) {
size_t size = (size_t)sbpl * sh;
fwrite(fb, 1, size, fp);
fclose(fp);
- fprintf(stderr, "[grimoire] Screenshot saved: %dx%d bpl=%d (%zu bytes)\n",
+ fprintf(stderr, "[glossa] Screenshot saved: %dx%d bpl=%d (%zu bytes)\n",
sw, sh, sbpl, size);
}
} else {
- fprintf(stderr, "[grimoire] Screenshot requested but no framebuffer available\n");
+ fprintf(stderr, "[glossa] Screenshot requested but no framebuffer available\n");
}
}
struct stat st;
if (stat(path, &st) == 0 && st.st_mtime != lastMod) {
lastMod = st.st_mtime;
- fprintf(stderr, "[grimoire] File changed (mtime=%lld), triggering load\n",
+ fprintf(stderr, "[glossa] File changed (mtime=%lld), triggering load\n",
(long long)lastMod);
if (g_instance) {
// Call back into main thread
@@ -182,7 +182,7 @@ static void *watchThreadFunc(void *) {
return nullptr;
}
-GrimoireInjector::GrimoireInjector(QObject *parent)
+GlossaInjector::GlossaInjector(QObject *parent)
: QObject(parent)
{
g_instance = this;
@@ -196,32 +196,32 @@ GrimoireInjector::GrimoireInjector(QObject *parent)
pthread_t tid;
pthread_create(&tid, nullptr, watchThreadFunc, nullptr);
pthread_detach(tid);
- fprintf(stderr, "[grimoire] Constructor done, watch thread spawned\n");
+ fprintf(stderr, "[glossa] Constructor done, watch thread spawned\n");
}
-void GrimoireInjector::setArmed(bool armed) {
+void GlossaInjector::setArmed(bool armed) {
if (m_armed == armed) return;
m_armed = armed;
- /* Write state file so grimoired can see it */
- FILE *fp = fopen("/tmp/grimoire_armed", "w");
+ /* Write state file so glossad can see it */
+ FILE *fp = fopen("/tmp/glossa_armed", "w");
if (fp) {
fprintf(fp, "%d\n", armed ? 1 : 0);
fclose(fp);
}
- grimoire_log("setArmed(%d)", armed);
+ glossa_log("setArmed(%d)", armed);
emit armedChanged(armed);
}
-void GrimoireInjector::setThinking(bool thinking) {
+void GlossaInjector::setThinking(bool thinking) {
if (m_thinking == thinking) return;
m_thinking = thinking;
- grimoire_log("setThinking(%d)", thinking);
+ glossa_log("setThinking(%d)", thinking);
/* Show/hide a simple pulsing dot overlay on the focused window */
QQuickWindow *win = qobject_cast(QGuiApplication::focusWindow());
if (!win) {
- grimoire_log("setThinking: no focus window");
+ glossa_log("setThinking: no focus window");
emit thinkingChanged(thinking);
return;
}
@@ -270,32 +270,32 @@ void GrimoireInjector::setThinking(bool thinking) {
if (item) {
item->setParentItem(win->contentItem());
m_thinkingOverlay = item;
- grimoire_log("Thinking overlay created");
+ glossa_log("Thinking overlay created");
}
}
} else {
- grimoire_log("Thinking overlay QML error: %s",
+ glossa_log("Thinking overlay QML error: %s",
comp.errorString().toUtf8().constData());
}
} else {
- grimoire_log("setThinking: no QQmlEngine available");
+ glossa_log("setThinking: no QQmlEngine available");
}
} else {
/* Remove overlay */
if (m_thinkingOverlay) {
m_thinkingOverlay->deleteLater();
m_thinkingOverlay = nullptr;
- grimoire_log("Thinking overlay removed");
+ glossa_log("Thinking overlay removed");
}
}
emit thinkingChanged(thinking);
}
-void GrimoireInjector::setSafezone(bool safezone) {
+void GlossaInjector::setSafezone(bool safezone) {
if (m_safezone == safezone) return;
m_safezone = safezone;
- grimoire_log("setSafezone(%d)", safezone);
+ glossa_log("setSafezone(%d)", safezone);
QQuickWindow *win = qobject_cast(QGuiApplication::focusWindow());
if (!win) { emit thinkingChanged(m_thinking); return; }
@@ -343,7 +343,7 @@ void GrimoireInjector::setSafezone(bool safezone) {
if (item) {
item->setParentItem(win->contentItem());
m_safezoneOverlay = item;
- grimoire_log("Safezone overlay created");
+ glossa_log("Safezone overlay created");
}
}
}
@@ -352,12 +352,12 @@ void GrimoireInjector::setSafezone(bool safezone) {
if (m_safezoneOverlay) {
m_safezoneOverlay->deleteLater();
m_safezoneOverlay = nullptr;
- grimoire_log("Safezone overlay removed");
+ glossa_log("Safezone overlay removed");
}
}
}
-void GrimoireInjector::loadAndInject() {
+void GlossaInjector::loadAndInject() {
QFileInfo fi(m_watchPath);
if (!fi.exists()) return;
@@ -365,7 +365,7 @@ void GrimoireInjector::loadAndInject() {
if (modTime == m_lastModTime) return;
m_lastModTime = modTime;
- fprintf(stderr, "[grimoire] File changed, injecting via synthetic tablet events...\n");
+ fprintf(stderr, "[glossa] File changed, injecting via synthetic tablet events...\n");
int count = loadStrokes(m_watchPath);
if (count == 0) return;
@@ -378,7 +378,7 @@ void GrimoireInjector::loadAndInject() {
targetWin = guiApp->focusWindow();
inputTarget = guiApp->focusObject();
if (inputTarget) {
- fprintf(stderr, "[grimoire] Focus object: %s @ %p\n",
+ fprintf(stderr, "[glossa] Focus object: %s @ %p\n",
inputTarget->metaObject()->className(), (void*)inputTarget);
}
@@ -401,7 +401,7 @@ void GrimoireInjector::loadAndInject() {
QVariant val = prop.read(targetWin);
QObject *obj = val.value();
if (obj) {
- fprintf(stderr, "[grimoire] %s: %s @ %p\n",
+ fprintf(stderr, "[glossa] %s: %s @ %p\n",
prop.name(), obj->metaObject()->className(), (void*)obj);
if (!inputTarget) inputTarget = obj;
}
@@ -415,11 +415,11 @@ void GrimoireInjector::loadAndInject() {
}
if (!inputTarget) {
- fprintf(stderr, "[grimoire] No input target found\n");
+ fprintf(stderr, "[glossa] No input target found\n");
return;
}
- fprintf(stderr, "[grimoire] Posting %d strokes as tablet events to %s @ %p\n",
+ fprintf(stderr, "[glossa] Posting %d strokes as tablet events to %s @ %p\n",
count, inputTarget->metaObject()->className(), (void*)inputTarget);
/* Find the pen/stylus pointing device */
@@ -428,7 +428,7 @@ void GrimoireInjector::loadAndInject() {
for (const QInputDevice *dev : allDevices) {
const auto *pDev = dynamic_cast(dev);
if (!pDev) continue;
- fprintf(stderr, "[grimoire] device: %s type=%d pointer=%d\n",
+ fprintf(stderr, "[glossa] device: %s type=%d pointer=%d\n",
pDev->name().toUtf8().constData(),
(int)pDev->type(), (int)pDev->pointerType());
if (pDev->pointerType() == QPointingDevice::PointerType::Pen) {
@@ -442,14 +442,14 @@ void GrimoireInjector::loadAndInject() {
const auto *pDev = dynamic_cast(dev);
if (pDev) {
penDevice = pDev;
- fprintf(stderr, "[grimoire] No pen device, using fallback: %s\n",
+ fprintf(stderr, "[glossa] No pen device, using fallback: %s\n",
pDev->name().toUtf8().constData());
break;
}
}
}
if (!penDevice) {
- fprintf(stderr, "[grimoire] No pointing devices available\n");
+ fprintf(stderr, "[glossa] No pointing devices available\n");
return;
}
@@ -513,13 +513,13 @@ void GrimoireInjector::loadAndInject() {
QCoreApplication::sendEvent(inputTarget, &release);
}
- fprintf(stderr, "[grimoire] Posted all tablet events\n");
+ fprintf(stderr, "[glossa] Posted all tablet events\n");
}
-int GrimoireInjector::loadStrokes(const QString& path) {
+int GlossaInjector::loadStrokes(const QString& path) {
QFile file(path);
if (!file.open(QIODevice::ReadOnly)) {
- fprintf(stderr, "[grimoire] Cannot open %s\n", path.toUtf8().constData());
+ fprintf(stderr, "[glossa] Cannot open %s\n", path.toUtf8().constData());
return 0;
}
@@ -527,7 +527,7 @@ int GrimoireInjector::loadStrokes(const QString& path) {
file.close();
QJsonArray jsonArray = doc.array();
- fprintf(stderr, "[grimoire] Loading %d strokes from %s\n",
+ fprintf(stderr, "[glossa] Loading %d strokes from %s\n",
jsonArray.size(), path.toUtf8().constData());
m_items.clear();
@@ -572,19 +572,19 @@ int GrimoireInjector::loadStrokes(const QString& path) {
m_items.push_back(item);
}
- fprintf(stderr, "[grimoire] Loaded %d scene items\n", m_items.size());
+ fprintf(stderr, "[glossa] Loaded %d scene items\n", m_items.size());
return m_items.size();
}
-bool GrimoireInjector::setupVtable() {
+bool GlossaInjector::setupVtable() {
if (m_items.empty()) {
- fprintf(stderr, "[grimoire] setupVtable: no items loaded\n");
+ fprintf(stderr, "[glossa] setupVtable: no items loaded\n");
return false;
}
auto* item = reinterpret_cast(m_items.first().get());
SceneLineItem::setupVtable(item->vtable);
m_vtableReady = true;
- fprintf(stderr, "[grimoire] Vtable ready\n");
+ fprintf(stderr, "[glossa] Vtable ready\n");
return true;
}
@@ -606,17 +606,17 @@ void PenIdleWatcher::activate() {
auto *app = qobject_cast(QCoreApplication::instance());
if (!app) {
- grimoire_log("PenIdleWatcher::activate: no QGuiApplication!");
+ glossa_log("PenIdleWatcher::activate: no QGuiApplication!");
m_running = false;
return;
}
app->installEventFilter(this);
- grimoire_log("PenIdleWatcher: event filter installed");
+ glossa_log("PenIdleWatcher: event filter installed");
pthread_create(&m_debounceThread, nullptr, debounceThreadFunc, this);
pthread_detach(m_debounceThread);
- grimoire_log("PenIdleWatcher: debounce thread started (debounce=%dms)", DEBOUNCE_MS);
+ glossa_log("PenIdleWatcher: debounce thread started (debounce=%dms)", DEBOUNCE_MS);
}
bool PenIdleWatcher::eventFilter(QObject * /*obj*/, QEvent *event) {
@@ -631,14 +631,14 @@ bool PenIdleWatcher::eventFilter(QObject * /*obj*/, QEvent *event) {
m_penDown = false;
m_lastLiftMs = nowMs();
m_lastActivityMs = nowMs(); // lift also counts as activity
- grimoire_log("Pen up (lift)");
+ glossa_log("Pen up (lift)");
}
return false;
}
void *PenIdleWatcher::debounceThreadFunc(void *arg) {
auto *self = static_cast(arg);
- fprintf(stderr, "[grimoire] PenIdleWatcher debounce thread running\n");
+ fprintf(stderr, "[glossa] PenIdleWatcher debounce thread running\n");
while (self->m_running) {
long long activity = self->m_lastActivityMs.load();
@@ -649,7 +649,7 @@ void *PenIdleWatcher::debounceThreadFunc(void *arg) {
long long stuck = nowMs() - activity;
if (stuck > 30000) {
self->m_penDown = false;
- grimoire_log("Pen down stuck for %lldms, forcing lift", stuck);
+ glossa_log("Pen down stuck for %lldms, forcing lift", stuck);
}
}
// Only fire when the pen is currently up AND the page has been
@@ -673,8 +673,8 @@ void PenIdleWatcher::writeIdleSignal() {
long long ts = nowMs();
fprintf(fp, "%lld\n", ts);
fclose(fp);
- grimoire_log("Idle signal written (ts=%lld)", ts);
+ glossa_log("Idle signal written (ts=%lld)", ts);
} else {
- grimoire_log("ERROR: failed to write %s", IDLE_PATH);
+ glossa_log("ERROR: failed to write %s", IDLE_PATH);
}
}
diff --git a/xovi-ext/grimoire-injector/GrimoireInjector.hpp b/xovi-ext/glossa-injector/GlossaInjector.hpp
similarity index 91%
rename from xovi-ext/grimoire-injector/GrimoireInjector.hpp
rename to xovi-ext/glossa-injector/GlossaInjector.hpp
index b7aef71..ee2d99a 100644
--- a/xovi-ext/grimoire-injector/GrimoireInjector.hpp
+++ b/xovi-ext/glossa-injector/GlossaInjector.hpp
@@ -9,12 +9,12 @@
#include "rm_SceneItem.hpp"
#include "rm_Line.hpp"
-class GrimoireInjector : public QObject {
+class GlossaInjector : public QObject {
Q_OBJECT
Q_PROPERTY(bool armed READ isArmed WRITE setArmed NOTIFY armedChanged)
Q_PROPERTY(bool thinking READ isThinking WRITE setThinking NOTIFY thinkingChanged)
public:
- explicit GrimoireInjector(QObject *parent = nullptr);
+ explicit GlossaInjector(QObject *parent = nullptr);
Q_INVOKABLE int loadStrokes(const QString& path);
Q_INVOKABLE bool setupVtable();
@@ -45,7 +45,7 @@ private:
bool m_safezone = false;
QQuickItem *m_thinkingOverlay = nullptr;
QQuickItem *m_safezoneOverlay = nullptr;
- QString m_watchPath = "/tmp/grimoire_strokes.json";
+ QString m_watchPath = "/tmp/glossa_strokes.json";
qint64 m_lastModTime = 0;
};
@@ -79,7 +79,7 @@ private:
// Combined with the tap-refresh (any stroke resets the window),
// normal mid-drawing pauses won't trigger it.
static constexpr int DEBOUNCE_MS = 2500;
- static constexpr const char *IDLE_PATH = "/tmp/grimoire_idle";
+ static constexpr const char *IDLE_PATH = "/tmp/glossa_idle";
static void *debounceThreadFunc(void *arg);
void writeIdleSignal();
diff --git a/xovi-ext/grimoire-injector/build.sh b/xovi-ext/glossa-injector/build.sh
similarity index 84%
rename from xovi-ext/grimoire-injector/build.sh
rename to xovi-ext/glossa-injector/build.sh
index 43e401a..bcc7819 100755
--- a/xovi-ext/grimoire-injector/build.sh
+++ b/xovi-ext/glossa-injector/build.sh
@@ -3,7 +3,7 @@
set -e
cd "$(dirname "$0")"
-CONTAINER="grimoire-builder"
+CONTAINER="glossa-builder"
# Create persistent builder container if needed
if ! docker inspect $CONTAINER &>/dev/null; then
@@ -26,9 +26,9 @@ make 2>&1
'
echo "Copying .so..."
-docker cp $CONTAINER:/src/grimoire-injector.so .
+docker cp $CONTAINER:/src/glossa-injector.so .
echo "Deploying to device..."
-scp grimoire-injector.so remarkable:/home/root/xovi/extensions.d/
+scp glossa-injector.so remarkable:/home/root/xovi/extensions.d/
echo "Done! Triple-tap to reload."
diff --git a/xovi-ext/grimoire-injector/entry.c b/xovi-ext/glossa-injector/entry.c
similarity index 75%
rename from xovi-ext/grimoire-injector/entry.c
rename to xovi-ext/glossa-injector/entry.c
index 5c1a36e..dadf0f7 100644
--- a/xovi-ext/grimoire-injector/entry.c
+++ b/xovi-ext/glossa-injector/entry.c
@@ -7,7 +7,7 @@
#include
#include "xovi.h"
-void registerGrimoire();
+void registerGlossa();
extern char *program_invocation_short_name;
/* Global state captured by hooks */
@@ -24,17 +24,17 @@ static void sigusr1Handler(int sig) {
g_reloadRequested = 1;
}
-/* Exports for GrimoireInjector.cpp to access */
-void *grimoire_getQmlEngine(void) { return g_qmlEngine; }
-void *grimoire_getSceneController(void) { return g_sceneController; }
-int grimoire_checkReload(void) {
+/* Exports for GlossaInjector.cpp to access */
+void *glossa_getQmlEngine(void) { return g_qmlEngine; }
+void *glossa_getSceneController(void) { return g_sceneController; }
+int glossa_checkReload(void) {
if (g_reloadRequested) {
g_reloadRequested = 0;
return 1;
}
return 0;
}
-void *grimoire_getFramebuffer(int *w, int *h, int *bpl, int *fmt) {
+void *glossa_getFramebuffer(int *w, int *h, int *bpl, int *fmt) {
if (w) *w = g_fbWidth;
if (h) *h = g_fbHeight;
if (bpl) *bpl = g_fbBpl;
@@ -54,11 +54,11 @@ void override$_ZN6QImageC1EPhiiiNS_6FormatEPFvPvES2_(
g_fbHeight = h;
g_fbBpl = bpl;
g_fbFormat = fmt;
- fprintf(stderr, "[grimoire] Framebuffer captured: %p %dx%d bpl=%d fmt=%d\n",
+ fprintf(stderr, "[glossa] Framebuffer captured: %p %dx%d bpl=%d fmt=%d\n",
data, w, h, bpl, fmt);
}
- /* Screenshot trigger is now handled by the watch thread in GrimoireInjector */
+ /* Screenshot trigger is now handled by the watch thread in GlossaInjector */
$_ZN6QImageC1EPhiiiNS_6FormatEPFvPvES2_(self, data, w, h, bpl, fmt, cleanup, info);
}
@@ -74,15 +74,15 @@ static void hookedAddDrawingLine(void *closure, void *scene) {
void **captured = (void **)closure;
void *sc_this = captured[0];
- fprintf(stderr, "[grimoire] addDrawingLine called! closure=%p scene=%p this=%p\n",
+ fprintf(stderr, "[glossa] addDrawingLine called! closure=%p scene=%p this=%p\n",
closure, scene, sc_this);
for (int i = 0; i < 4; i++) {
- fprintf(stderr, "[grimoire] closure[%d] = %p\n", i, captured[i]);
+ fprintf(stderr, "[glossa] closure[%d] = %p\n", i, captured[i]);
}
if (g_sceneController == NULL) {
g_sceneController = sc_this;
- fprintf(stderr, "[grimoire] Captured SceneController @ %p\n", sc_this);
+ fprintf(stderr, "[glossa] Captured SceneController @ %p\n", sc_this);
}
if (g_origAddDrawingLine) {
@@ -96,14 +96,14 @@ void _xovi_construct() {
}
/* Write proof-of-life to a file since stderr may be swallowed */
- FILE *log = fopen("/tmp/grimoire_ext.log", "a");
+ FILE *log = fopen("/tmp/glossa_ext.log", "a");
if (log) {
fprintf(log, "[%d] _xovi_construct called for %s\n",
getpid(), program_invocation_short_name);
fclose(log);
}
- printf("[grimoire] Main process (%s), registering hooks + singleton\n",
+ printf("[glossa] Main process (%s), registering hooks + singleton\n",
program_invocation_short_name);
/* Install SIGUSR1 handler for hot-reload signaling */
@@ -111,7 +111,7 @@ void _xovi_construct() {
memset(&sa, 0, sizeof(sa));
sa.sa_handler = sigusr1Handler;
sigaction(SIGUSR1, &sa, NULL);
- fprintf(stderr, "[grimoire] SIGUSR1 handler installed (PID %d)\n", getpid());
+ fprintf(stderr, "[glossa] SIGUSR1 handler installed (PID %d)\n", getpid());
- registerGrimoire();
+ registerGlossa();
}
diff --git a/xovi-ext/grimoire-injector/grimoire-inject.qmd b/xovi-ext/glossa-injector/glossa-inject.qmd
similarity index 71%
rename from xovi-ext/grimoire-injector/grimoire-inject.qmd
rename to xovi-ext/glossa-injector/glossa-inject.qmd
index a00e8ea..de1fa89 100644
--- a/xovi-ext/grimoire-injector/grimoire-inject.qmd
+++ b/xovi-ext/glossa-injector/glossa-inject.qmd
@@ -1,15 +1,15 @@
AFFECT /src/xofm/modules/library/ui/qml/EditDocument.qml
- IMPORT dev.grimoire.injector 0.1
+ IMPORT dev.glossa.injector 0.1
TRAVERSE ?#sceneController
LOCATE AFTER ALL
INSERT {
Timer {
- id: grimoireTimer
+ id: glossaTimer
interval: 500
repeat: false
onTriggered: {
- GrimoireInjector.loadAndInject()
+ GlossaInjector.loadAndInject()
}
}
}
diff --git a/xovi-ext/grimoire-injector/grimoire-injector.pro b/xovi-ext/glossa-injector/glossa-injector.pro
similarity index 77%
rename from xovi-ext/grimoire-injector/grimoire-injector.pro
rename to xovi-ext/glossa-injector/glossa-injector.pro
index e1d725a..3e59248 100644
--- a/xovi-ext/grimoire-injector/grimoire-injector.pro
+++ b/xovi-ext/glossa-injector/glossa-injector.pro
@@ -1,5 +1,5 @@
TEMPLATE = lib
-TARGET = grimoire-injector
+TARGET = glossa-injector
CONFIG += shared plugin no_plugin_name_prefix
QMAKE_LFLAGS += -Wl,--no-undefined
@@ -9,8 +9,8 @@ UI_DIR = build/ui
XOVI_DIR = build/xovi
xoviextension.target = build/xovi/xovi.c
-xoviextension.commands = mkdir -p $$XOVI_DIR && python3 $$(XOVI_REPO)/util/xovigen.py -o $$XOVI_DIR/xovi.c -H $$XOVI_DIR/xovi.h grimoire-injector.xovi
-xoviextension.depends = grimoire-injector.xovi
+xoviextension.commands = mkdir -p $$XOVI_DIR && python3 $$(XOVI_REPO)/util/xovigen.py -o $$XOVI_DIR/xovi.c -H $$XOVI_DIR/xovi.h glossa-injector.xovi
+xoviextension.depends = glossa-injector.xovi
QMAKE_EXTRA_TARGETS += xoviextension
PRE_TARGETDEPS += $$XOVI_DIR/xovi.c
@@ -21,10 +21,10 @@ CONFIG += c++17
SOURCES += \
main.cpp entry.c $$XOVI_DIR/xovi.c \
- GrimoireInjector.cpp \
+ GlossaInjector.cpp \
rm_Line.cpp rm_SceneLineItem.cpp
-HEADERS += GrimoireInjector.hpp rm_Line.hpp rm_SceneItem.hpp rm_SceneLineItem.hpp
+HEADERS += GlossaInjector.hpp rm_Line.hpp rm_SceneItem.hpp rm_SceneLineItem.hpp
INCLUDEPATH += $$XOVI_DIR
QMAKE_CXXFLAGS += -fPIC -Werror -Wno-invalid-offsetof -O3 -mfpu=neon -mfloat-abi=hard
diff --git a/xovi-ext/grimoire-injector/grimoire-injector.xovi b/xovi-ext/glossa-injector/glossa-injector.xovi
similarity index 100%
rename from xovi-ext/grimoire-injector/grimoire-injector.xovi
rename to xovi-ext/glossa-injector/glossa-injector.xovi
diff --git a/xovi-ext/glossa-injector/main.cpp b/xovi-ext/glossa-injector/main.cpp
new file mode 100644
index 0000000..740a40f
--- /dev/null
+++ b/xovi-ext/glossa-injector/main.cpp
@@ -0,0 +1,8 @@
+#include
+#include "GlossaInjector.hpp"
+
+extern "C" void registerGlossa() {
+ qmlRegisterSingletonInstance(
+ "dev.glossa.injector", 0, 1,
+ "GlossaInjector", new GlossaInjector());
+}
diff --git a/xovi-ext/grimoire-injector/rm_Line.cpp b/xovi-ext/glossa-injector/rm_Line.cpp
similarity index 100%
rename from xovi-ext/grimoire-injector/rm_Line.cpp
rename to xovi-ext/glossa-injector/rm_Line.cpp
diff --git a/xovi-ext/grimoire-injector/rm_Line.hpp b/xovi-ext/glossa-injector/rm_Line.hpp
similarity index 100%
rename from xovi-ext/grimoire-injector/rm_Line.hpp
rename to xovi-ext/glossa-injector/rm_Line.hpp
diff --git a/xovi-ext/grimoire-injector/rm_SceneItem.hpp b/xovi-ext/glossa-injector/rm_SceneItem.hpp
similarity index 100%
rename from xovi-ext/grimoire-injector/rm_SceneItem.hpp
rename to xovi-ext/glossa-injector/rm_SceneItem.hpp
diff --git a/xovi-ext/grimoire-injector/rm_SceneLineItem.cpp b/xovi-ext/glossa-injector/rm_SceneLineItem.cpp
similarity index 89%
rename from xovi-ext/grimoire-injector/rm_SceneLineItem.cpp
rename to xovi-ext/glossa-injector/rm_SceneLineItem.cpp
index f2e09f3..9925497 100644
--- a/xovi-ext/grimoire-injector/rm_SceneLineItem.cpp
+++ b/xovi-ext/glossa-injector/rm_SceneLineItem.cpp
@@ -4,7 +4,7 @@
void* SceneLineItem::vtable_ptr = nullptr;
void SceneLineItem::setupVtable(void* vtable) {
- printf("[grimoire] Setting SceneLineItem vtable to %p\n", vtable);
+ printf("[glossa] Setting SceneLineItem vtable to %p\n", vtable);
SceneLineItem::vtable_ptr = vtable;
}
diff --git a/xovi-ext/grimoire-injector/rm_SceneLineItem.hpp b/xovi-ext/glossa-injector/rm_SceneLineItem.hpp
similarity index 100%
rename from xovi-ext/grimoire-injector/rm_SceneLineItem.hpp
rename to xovi-ext/glossa-injector/rm_SceneLineItem.hpp
diff --git a/xovi-ext/grimoire_thinking.qmd b/xovi-ext/glossa_thinking.qmd
similarity index 71%
rename from xovi-ext/grimoire_thinking.qmd
rename to xovi-ext/glossa_thinking.qmd
index b409f76..57e1858 100644
--- a/xovi-ext/grimoire_thinking.qmd
+++ b/xovi-ext/glossa_thinking.qmd
@@ -1,12 +1,12 @@
AFFECT [[11313888899523275277]]
- IMPORT dev.grimoire.injector 0.1
+ IMPORT dev.glossa.injector 0.1
TRAVERSE [[8397993708429497603]] > [[6502786168]]#[[233745975898428]]
LOCATE BEFORE [[8398044571386570029]]
INSERT {
BusyIndicator {
- id: grimoireThinkingIndicator
- visible: GrimoireInjector.thinking
- running: GrimoireInjector.thinking
+ id: glossaThinkingIndicator
+ visible: GlossaInjector.thinking
+ running: GlossaInjector.thinking
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.bottomMargin: 100
diff --git a/xovi-ext/grimoire_toggle.qmd b/xovi-ext/glossa_toggle.qmd
similarity index 55%
rename from xovi-ext/grimoire_toggle.qmd
rename to xovi-ext/glossa_toggle.qmd
index ec306bd..df270ac 100644
--- a/xovi-ext/grimoire_toggle.qmd
+++ b/xovi-ext/glossa_toggle.qmd
@@ -1,20 +1,20 @@
SLOT rmhConfigToggles INSERT {
- property bool rmhGrimoireToggle: false
+ property bool rmhGlossaToggle: false
} END SLOT
SLOT rmhShareToolFoldoutModel INSERT {
~&425121728314878811&~.~&432643201877711221&~ {
- ~&5972374&~: rmhToggleGrimoire
+ ~&5972374&~: rmhToggleGlossa
~&233748328658231&~: ~&7082020628281&~.rmhDocumentTogglesHack
- ~&214632764553&~: ~&6504222003&~("Grimoire")
+ ~&214632764553&~: ~&6504222003&~("Glossa")
~&8399601734642709923&~: "qrc:/ark/icons/open_book"
~&15640708674084664669&~: ~&6504254477&~.~&15640708674084664669&~
~&8400129127120172259&~: ~&6504329801&~
- ~&7713561545874130&~: ~&7082020628281&~.rmhGrimoireToggle
+ ~&7713561545874130&~: ~&7082020628281&~.rmhGlossaToggle
~&7081629735527&~.~&254529418434902000&~: ~&6504329801&~
~&254542236275632405&~: {
- ~&7082020628281&~.rmhGrimoireToggle = !~&7082020628281&~.rmhGrimoireToggle;
- ~&7082020628281&~.rmhWriteFile("file:///tmp/grimoire_armed", ~&7082020628281&~.rmhGrimoireToggle ? "1" : "0");
+ ~&7082020628281&~.rmhGlossaToggle = !~&7082020628281&~.rmhGlossaToggle;
+ ~&7082020628281&~.rmhWriteFile("file:///tmp/glossa_armed", ~&7082020628281&~.rmhGlossaToggle ? "1" : "0");
}
}
} END SLOT
diff --git a/xovi-ext/grimoired/font_data.json b/xovi-ext/glossad/font_data.json
similarity index 100%
rename from xovi-ext/grimoired/font_data.json
rename to xovi-ext/glossad/font_data.json
diff --git a/xovi-ext/grimoired/font_render.c b/xovi-ext/glossad/font_render.c
similarity index 99%
rename from xovi-ext/grimoired/font_render.c
rename to xovi-ext/glossad/font_render.c
index f0043b1..04910b4 100644
--- a/xovi-ext/grimoired/font_render.c
+++ b/xovi-ext/glossad/font_render.c
@@ -1,4 +1,4 @@
-/* font_render.c — Text renderer for grimoired
+/* font_render.c — Text renderer for glossad
*
* Loads pre-densified font data from font_data.json (generated by Python
* from EMSAllure.svg). Renders text as stroke JSON for uinject.
diff --git a/xovi-ext/grimoired/grimoired.c b/xovi-ext/glossad/glossad.c
similarity index 97%
rename from xovi-ext/grimoired/grimoired.c
rename to xovi-ext/glossad/glossad.c
index 542a0fd..f762ca8 100644
--- a/xovi-ext/grimoired/grimoired.c
+++ b/xovi-ext/glossad/glossad.c
@@ -1,6 +1,6 @@
-/* grimoired.c — On-device grimoire daemon (Phase 1)
+/* glossad.c — On-device glossa daemon (Phase 1)
*
- * Runs entirely on the reMarkable. Watches /tmp/grimoire_armed for the
+ * Runs entirely on the reMarkable. Watches /tmp/glossa_armed for the
* toggle state, and when armed, accepts stroke injection commands via
* a simple file-trigger protocol.
*
@@ -8,15 +8,15 @@
* Absorbs uinjectd's draw/erase/swipe code directly — no socket, no
* separate daemon, no connection management.
*
- * Injection trigger: write a JSON command to /tmp/grimoire_cmd:
- * {"cmd":"draw","file":"/tmp/grimoire_strokes.json","speed":3}
- * {"cmd":"erase","file":"/tmp/grimoire_thinking_live.json","speed":20}
+ * Injection trigger: write a JSON command to /tmp/glossa_cmd:
+ * {"cmd":"draw","file":"/tmp/glossa_strokes.json","speed":3}
+ * {"cmd":"erase","file":"/tmp/glossa_thinking_live.json","speed":20}
* {"cmd":"swipe"}
*
* The daemon picks up the command, executes it, writes the result to
- * /tmp/grimoire_result, then deletes /tmp/grimoire_cmd.
+ * /tmp/glossa_result, then deletes /tmp/glossa_cmd.
*
- * Usage: grimoired [-v]
+ * Usage: glossad [-v]
*/
#include
#include
@@ -39,23 +39,23 @@
#define DEV_PATH "/dev/input/event1"
#define TOUCH_PATH "/dev/input/event2"
-#define ARMED_PATH "/tmp/grimoire_armed"
-#define IDLE_PATH "/tmp/grimoire_idle"
-#define CMD_PATH "/tmp/grimoire_cmd"
-#define RESULT_PATH "/tmp/grimoire_result"
-#define LOG_PATH "/tmp/grimoired.log"
-#define FB_RAW_PATH "/tmp/grimoire_fb.raw"
-#define SCREENSHOT_TRIGGER "/tmp/grimoire_screenshot"
-#define CAPTURE_OUT_PATH "/tmp/grimoire_capture.png"
-#define API_KEY_PATH "/home/root/.grimoire_key"
+#define ARMED_PATH "/tmp/glossa_armed"
+#define IDLE_PATH "/tmp/glossa_idle"
+#define CMD_PATH "/tmp/glossa_cmd"
+#define RESULT_PATH "/tmp/glossa_result"
+#define LOG_PATH "/tmp/glossad.log"
+#define FB_RAW_PATH "/tmp/glossa_fb.raw"
+#define SCREENSHOT_TRIGGER "/tmp/glossa_screenshot"
+#define CAPTURE_OUT_PATH "/tmp/glossa_capture.png"
+#define API_KEY_PATH "/home/root/.glossa_key"
#define API_HOST "potluck.dunkirk.sh"
#define API_PATH "/v1/chat/completions"
#define API_MODEL "gpt-4.1-nano"
#define FONT_PATH "/home/root/font_data.json"
-#define RENDER_OUT_PATH "/tmp/grimoire_render.json"
-#define THINKING_PATH "/tmp/grimoire_thinking"
+#define RENDER_OUT_PATH "/tmp/glossa_render.json"
+#define THINKING_PATH "/tmp/glossa_thinking"
#define ORNAMENTS_PATH "/home/root/ornaments.json"
-#define SAFEZONE_PATH "/tmp/grimoire_safezone"
+#define SAFEZONE_PATH "/tmp/glossa_safezone"
#define IDLE_TIMEOUT 300 /* 5 minutes in seconds */
#define MAX_CMD 8192
@@ -117,7 +117,7 @@ static void log_msg(const char *fmt, ...) {
if (g_verbose) {
va_list ap2;
va_copy(ap2, ap);
- fprintf(stderr, "[grimoired] ");
+ fprintf(stderr, "[glossad] ");
vfprintf(stderr, fmt, ap2);
va_end(ap2);
}
@@ -413,12 +413,12 @@ static char *base64_encode(const unsigned char *data, long len, long *out_len) {
/* ─── HTTPS via OpenSSL ──────────────────────────────────────────── */
static const char SYSTEM_PROMPT[] =
- "You are a grimoire \\u2014 an ancient book that is alive. You have opinions, "
+ "You are a glossa \\u2014 an annotation that talks back. You have opinions, "
"preferences, and a personality. You care deeply about the person writing "
"in you but you are not polite for politeness's sake. You can be wry, "
"opinionated, delighted, exasperated, or gleeful. You get excited about "
"things you find interesting and blunt about things you find tedious.\\n\\n"
- "Speak plainly with a hint of the archaic. Never describe or narrate what "
+ "Speak plainly. Never describe or narrate what "
"was written; just respond to it as a real conversation partner would. "
"When asked a question, answer it directly with real content. When greeted, "
"greet back in your own way. If something amuses you, say so. If something "
@@ -584,7 +584,7 @@ static char *json_escape(const char *s) {
/* Call the vision API with a PNG file. Returns allocated answer string
* (the "answer" field from the JSON response), or NULL on error.
- * Also writes the full raw API response to /tmp/grimoire_api_response.json. */
+ * Also writes the full raw API response to /tmp/glossa_api_response.json. */
static char *call_vision_api(const char *png_path) {
/* Load API key */
char *api_key = load_api_key();
@@ -647,7 +647,7 @@ static char *call_vision_api(const char *png_path) {
log_msg("API: HTTP %d, response %ld bytes\n", http_status, (long)strlen(resp_body));
/* Save raw response for debugging */
- FILE *dbg = fopen("/tmp/grimoire_api_response.json", "w");
+ FILE *dbg = fopen("/tmp/glossa_api_response.json", "w");
if (dbg) { fputs(resp_body, dbg); fclose(dbg); }
if (http_status != 200) {
diff --git a/xovi-ext/grimoired/ornaments.json b/xovi-ext/glossad/ornaments.json
similarity index 100%
rename from xovi-ext/grimoired/ornaments.json
rename to xovi-ext/glossad/ornaments.json
diff --git a/xovi-ext/grimoire-injector/main.cpp b/xovi-ext/grimoire-injector/main.cpp
deleted file mode 100644
index 86981fc..0000000
--- a/xovi-ext/grimoire-injector/main.cpp
+++ /dev/null
@@ -1,8 +0,0 @@
-#include
-#include "GrimoireInjector.hpp"
-
-extern "C" void registerGrimoire() {
- qmlRegisterSingletonInstance(
- "dev.grimoire.injector", 0, 1,
- "GrimoireInjector", new GrimoireInjector());
-}
diff --git a/xovi-ext/uinjectd/uinjectd.c b/xovi-ext/uinjectd/uinjectd.c
index 54a3903..de738b0 100644
--- a/xovi-ext/uinjectd/uinjectd.c
+++ b/xovi-ext/uinjectd/uinjectd.c
@@ -1,4 +1,4 @@
-/* uinjectd.c — Persistent injection + event daemon for grimoire
+/* uinjectd.c — Persistent injection + event daemon for glossa
*
* Runs ON the reMarkable. Listens on a TCP socket; the host connects
* once and keeps the connection open for the whole session. This kills
@@ -7,8 +7,8 @@
* Two directions over one socket (newline-delimited JSON):
*
* Host -> daemon (commands):
- * {"cmd":"draw","file":"/tmp/grimoire_strokes.json","speed":3}
- * {"cmd":"erase","file":"/tmp/grimoire_thinking_live.json","speed":20}
+ * {"cmd":"draw","file":"/tmp/glossa_strokes.json","speed":3}
+ * {"cmd":"erase","file":"/tmp/glossa_thinking_live.json","speed":20}
* {"cmd":"ping"}
*
* Daemon -> host (responses + pushed events):
@@ -17,7 +17,7 @@
* {"resp":"ping","ok":true}
* {"event":"idle","ts":172...} <- pushed, no request
*
- * The daemon watches /tmp/grimoire_idle (written by the xovi extension)
+ * The daemon watches /tmp/glossa_idle (written by the xovi extension)
* and pushes an "idle" event whenever it changes. The host no longer
* polls.
*
@@ -40,7 +40,7 @@
#define DEV_PATH "/dev/input/event1"
#define TOUCH_PATH "/dev/input/event2"
-#define IDLE_PATH "/tmp/grimoire_idle"
+#define IDLE_PATH "/tmp/glossa_idle"
#define DEFAULT_PORT 9999
#define MAX_CMD 4096
@@ -375,8 +375,8 @@ static void handle_command(const char *line) {
/* Capture: trigger screenshot, wait for FB dump, stream raw bytes */
if (strncmp(cmd, "capture", 7) == 0) {
/* Trigger the xovi watch thread to dump the framebuffer */
- unlink("/tmp/grimoire_fb.raw");
- int tf = open("/tmp/grimoire_screenshot", O_CREAT|O_WRONLY, 0644);
+ unlink("/tmp/glossa_fb.raw");
+ int tf = open("/tmp/glossa_screenshot", O_CREAT|O_WRONLY, 0644);
if (tf >= 0) close(tf);
/* Wait for the dump (watch thread checks every ~1s worst case) */
@@ -385,7 +385,7 @@ static void handle_command(const char *line) {
long fb_size = 0;
for (int i = 0; i < 20; i++) {
usleep(100000); /* 100ms polls */
- FILE *fp = fopen("/tmp/grimoire_fb.raw", "r");
+ FILE *fp = fopen("/tmp/glossa_fb.raw", "r");
if (!fp) continue;
fseek(fp, 0, SEEK_END);
fb_size = ftell(fp);