Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
69c1d0b
Fix rapid typing and history drawer regressions
flyingrobots Jun 30, 2026
6b19f75
Test history drawer Echo switching regression
flyingrobots Jun 30, 2026
54b7a1d
Fix save barrier behind queued text edits
flyingrobots Jun 30, 2026
4c52cad
Fix: preserve queued edit cache before save
flyingrobots Jun 30, 2026
7399f16
Fix: block queued save after edit obstruction
flyingrobots Jun 30, 2026
34dfd2a
Fix: coalesce repeated queued saves
flyingrobots Jun 30, 2026
805ae23
Fix: capture insert receipt sequence before await
flyingrobots Jun 30, 2026
8f6f5f9
Fix: use byte offsets in Echo window fixture
flyingrobots Jun 30, 2026
099551b
Fix: tighten reading cache guard
flyingrobots Jun 30, 2026
da6d394
Fix: inject text operation sequencer
flyingrobots Jun 30, 2026
273bac0
Fix: stop queued edits after obstruction
flyingrobots Jun 30, 2026
4e0c5d4
Fix: avoid stale queued export reuse
flyingrobots Jun 30, 2026
f4074a0
Fix: scope text obstructions by buffer
flyingrobots Jun 30, 2026
7b7f334
Fix settings chrome and edit refresh pressure
flyingrobots Jun 30, 2026
9b630b3
Fix queued save obstruction assertion
flyingrobots Jun 30, 2026
2caf872
Fix malformed multi-range obstruction stub
flyingrobots Jun 30, 2026
793436c
Assert ignored export emits no checkpoint
flyingrobots Jun 30, 2026
e82e595
Fix unknown dependent edit blocker label
flyingrobots Jun 30, 2026
8c04f7f
Fix settings drawer fallback sizing
flyingrobots Jun 30, 2026
f7b1dfe
Assert settings selected row token
flyingrobots Jun 30, 2026
fd23b38
Cover empty settings focus movement
flyingrobots Jun 30, 2026
d8237ff
Tighten sequencer ownership guard
flyingrobots Jun 30, 2026
ec1f05c
Fix sequencer import boundary
flyingrobots Jun 30, 2026
7a9779e
Centralize settings close key
flyingrobots Jun 30, 2026
f8aaaee
Use text operation target identity
flyingrobots Jun 30, 2026
3dd2556
Fix remaining obstruction stub shapes
flyingrobots Jun 30, 2026
71a1e7a
Split Echo app typing sequencing specs
flyingrobots Jun 30, 2026
9be42f6
Fix workspace app import budget
flyingrobots Jun 30, 2026
b87ef03
Fix Echo harness multi-range obstruction
flyingrobots Jun 30, 2026
d97389f
Admit final queued edit before export obstruction
flyingrobots Jun 30, 2026
b24815f
Refresh highlighting after intermediate edits
flyingrobots Jun 30, 2026
7c146cc
Fix intermediate edit helper budget
flyingrobots Jun 30, 2026
4ee060c
Fix title scene bunny power angle
flyingrobots Jul 1, 2026
df3e62b
Fix title scene default composition
flyingrobots Jul 1, 2026
0ccc95b
Fix title scene review gaps
flyingrobots Jul 1, 2026
f10f7c5
Fix title scene readability
flyingrobots Jul 1, 2026
ef48e65
Fix title scene mirror composition
flyingrobots Jul 1, 2026
1199918
Fix title scene mirror view
flyingrobots Jul 1, 2026
beac493
Fix title camera Braille ghosting
flyingrobots Jul 1, 2026
183f97b
Fix title mirror material scene
flyingrobots Jul 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 38 additions & 2 deletions scenes/bunny.jedit-scene
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"camera": {
"position": [0, 1.45, -2.55],
"targetObject": "stanford-bunny"
"position": [-1.05, 0.46, 2.15],
"target": [-1.05, 1.2, -0.24]
},
"environment": {
"background": [2, 3, 7],
Expand Down Expand Up @@ -65,6 +65,42 @@
"color": [148, 232, 124],
"reflectivity": 0.13
},
{
"label": "chrome-left-orb",
"kind": "sphere",
"position": [-1.42, 0.62, -1.55],
"radius": 0.48,
"height": 0.96,
"footprintRadius": 0.48,
"color": [218, 237, 255],
"reflectivity": 0.94,
"transparency": 0.04,
"refractiveIndex": 1.18
},
{
"label": "chrome-crown-orb",
"kind": "sphere",
"position": [0.12, 1.05, -1.95],
"radius": 0.58,
"height": 1.16,
"footprintRadius": 0.58,
"color": [236, 244, 255],
"reflectivity": 0.96,
"transparency": 0.03,
"refractiveIndex": 1.2
},
{
"label": "chrome-right-orb",
"kind": "sphere",
"position": [1.5, 0.68, -1.52],
"radius": 0.5,
"height": 1.0,
"footprintRadius": 0.5,
"color": [204, 226, 255],
"reflectivity": 0.92,
"transparency": 0.05,
"refractiveIndex": 1.16
},
{
"label": "amber-glass-tower",
"kind": "cube",
Expand Down
44 changes: 44 additions & 0 deletions scenes/continuum-gate.jedit-scene
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"camera": {
"position": [0, 4.2, 3.4],
"target": [0, 1.25, 0]
},
"environment": {
"background": [2, 3, 7],
"floor": {
"kind": "grid",
"dark": [2, 3, 7],
"light": [68, 90, 100],
"gridScale": 1.2,
"fadeDistance": 34
}
},
"objects": [
{
"label": "stanford-bunny",
"kind": "mesh",
"mesh": "bunny",
"offset": [-0.95, 0, 2.84],
"localYaw": { "phase": 2.94, "angularSpeed": 0 },
"radius": 1.02,
"footprintRadius": 1.02,
"height": 2.35,
"color": [82, 98, 104],
"reflectivity": 0.1,
"transparency": 0,
"refractiveIndex": 1
},
{
"label": "chrome-mirror-sphere",
"kind": "sphere",
"position": [0, 1.25, 0],
"radius": 1.18,
"height": 2.36,
"footprintRadius": 1.18,
"color": [236, 244, 255],
"reflectivity": 0.99,
"transparency": 0.005,
"refractiveIndex": 1.06
}
]
}
14 changes: 7 additions & 7 deletions spec/fixtures/title-scene-visual-witness.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"⢕⢵⢝⢵░▓█▒⠕⢅⢕⢵⢝⢽⢕⢥⠝⢽⢝⢽⢝⢝⠕⢅⠕⢅⠕⢽⢝⢽⢝⢵⠝⢕⠝⢵⢝⢵⠕⢅⠕⠭",
"⡕⡅⡝⡕██▓░⡕⣥⣝⣽⣝⣽⣝⡍⡕⡅⡕⡍⡝⣅⡕⡅⡕⡅⡕⣽⣝⣽⣝⣽⣝⡅⡕⡅⡕⡅⡕⡥⣕⣭"
],
"foregroundDigest": "cf49e7a0fdb9d729",
"foregroundDigest": "0be1378fba7ca909",
"backgroundDigest": "65a24ea998becce0"
},
{
Expand All @@ -42,7 +42,7 @@
"⠕⢅⢝⢅⠕⢅⠕⢅⢕⢵⢝⢵⢝⢽⠝⢝⠝⢽⢝⢽⠕⢅⠕⢅⠕⢅⢝⢵⢕⢅⠕⢵⢝⢵⢝⢵⢝⢅⠕⢅⠝⠭",
"⣕⡵⣝⡵⣕⡅⣕⣵⣝⣽⣝⣽⣝⡍⡕⡅⡕⡅⡝⣅⡕⡅⡕⡅⡕⣽⣝⣽⣝⣽⣝⡍⡝⡵⣝⡵⣝⡅⡕⡅⡕⣭"
],
"foregroundDigest": "6b666ae8f7c6f251",
"foregroundDigest": "acaad4c34d0e5484",
"backgroundDigest": "d56a3f804cc5b610"
},
{
Expand All @@ -52,10 +52,10 @@
"glyphRows": [
" ",
" 55 ",
" ,,,XH5,Xi,,,,,,,, ",
",,,,,iiiiiiiiiiiiG5#B9Miiiiiiiiiiiiii,,,,i",
" ,,,XH2,Xi,,,,,,,, ",
",,,,,iiiiiiiiiiiiG3#B9Miiiiiiiiiiiiii,,,,i",
"iiiiiiiiiiiiiiiiiSSS#HhhS2h33iiiiiiiiiiii2",
"iiiiiiiiirii#Brrr#G35AXsrMMMM2riiiiiiiiii2",
"iiiiiiiiirii#Brrr#G35AAsrMMMM2riiiiiiiiii2",
"iiiiriiiriii32i;rAr2XsXiX3AAAXXiiiiiiiiir5",
",rri,;iri,irs;rr:;,,Xri;:3AAAMi:i,rrii:i, ",
"iri,irri,,,sr;,:sssr:is,,5AA2:irrri,:iii, ",
Expand All @@ -65,7 +65,7 @@
",,r:,,,,rsssss;r;sss,,,,,;ssr;,ssssss,,,, ",
"Xs2s5;X555555,;,;,;Xr,;,;A55555;rrAs5;;,;;"
],
"foregroundDigest": "e7baf08de00f5c17",
"foregroundDigest": "c6c7e3ff04d5fe00",
"backgroundDigest": "4cc8acca331fa313"
},
{
Expand All @@ -88,7 +88,7 @@
"⠕⢅⢕⢵⢕⢅⠕⢅⢕⢵⢝⢵⢝⢽⠕⢝⠝⢽⢝⢝⠕⢅⠕⢅⠕⢽⢕⢥⢕⢅⠕⢵⢝⢵⢝⢵⢕⢅⠝⢕⠝⠭",
"⣕⡵⣝⡵⣝⡵⣕⣵⣝⣽⣝⣽⡝⡅⡕⡅⡕⡍⣝⣅⡕⡅⡕⡅⡕⣽⣝⣽⣝⣽⣕⡝⡝⣵⣝⡵⣝⡅⡕⡅⡕⣭"
],
"foregroundDigest": "fd4770907df4d58d",
"foregroundDigest": "9db9b0c054e3e9ff",
"backgroundDigest": "7e30be255634420e"
}
]
38 changes: 33 additions & 5 deletions spec/settings-drawer.spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,17 @@ test('settings drawer renders structured rows and highlights the selected row',
const text = surfaceText(surface);

assert.match(text, /Settings/);
assert.match(text, /F2\/Esc close/);
assert.match(text, /● English Current/);
assert.match(text, /F2\/Esc\/q close/);
assert.match(text, /\[x\] English/);
assert.match(text, /↻ Theme/);
assert.match(text, /☑ Footer/);
assert.match(text, /↻ Markdown preview/);
assert.match(text, /↻ Diagnostics Open/);
assert.equal(surface.get(2, 8).char, '›');
assert.equal(surface.get(2, 8).fg, theme.cursor.normal.fg);
assert.equal(surface.get(2, 8).bg, theme.cursor.normal.bg);
assert.ok(text.includes('› ↻ Theme'));
Comment thread
flyingrobots marked this conversation as resolved.
const selectedMarker = surface.get(2, 8);
assert.equal(selectedMarker.char, '›');
assert.equal(selectedMarker.fg, theme.cursor.normal.fg);
assert.equal(selectedMarker.bg, theme.cursor.normal.bg);
});

test('settings drawer keeps the focused row visible when section headers consume short drawers', async () => {
Expand All @@ -81,3 +83,29 @@ test('settings drawer keeps the focused row visible when section headers consume

assert.match(surfaceText(surface), /› ↻ Markdown preview Source/);
});

test('settings drawer always returns the requested positive surface size', async () => {
const { drawer, settings, themes } = await loadDrawerModules();
const theme = themes.availableJeditThemes()[0];
const rows = settings.jeditSettingsRows({
i18n: createI18nMock(),
jeditTheme: theme,
footerVisible: true,
markdownPreviewActive: true,
diagnosticsAvailable: true,
viewMode: 'source',
});

for (const [width, height] of [[1, 1], [2, 2], [5, 3], [42, 20]]) {
const surface = drawer.renderSettingsDrawer({
rows,
selectedIndex: 0,
theme,
width,
height,
});

assert.equal(surface.width, width);
assert.equal(surface.height, height);
}
});
24 changes: 18 additions & 6 deletions spec/settings-session.spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import { pathToFileURL } from 'node:url';
import { createI18nMock } from './i18n-mock.mjs';
import { REPO_ROOT, ensureDistBuilt } from './dist-helpers.mjs';

const KEYBINDINGS_PATH = path.join(REPO_ROOT, 'dist', 'app', 'keybindings.js');
const SESSION_PATH = path.join(REPO_ROOT, 'dist', 'app', 'settings-session.js');
const THEMES_PATH = path.join(REPO_ROOT, 'dist', 'ui', 'jedit-themes.js');

async function loadSettingsModules() {
await ensureDistBuilt();

return {
keybindings: await import(pathToFileURL(KEYBINDINGS_PATH).href),
settings: await import(pathToFileURL(SESSION_PATH).href),
themes: await import(pathToFileURL(THEMES_PATH).href),
};
Expand Down Expand Up @@ -46,8 +48,8 @@ test('jedit settings rows expose theme, footer, and markdown preview preferences
assert.deepEqual(
rows.map((row) => [row.label, row.valueLabel, row.kind, row.checked === true]),
[
['English', 'en', settings.JEDIT_SETTING_ROW_KIND.Option, false],
['Français', 'Current', settings.JEDIT_SETTING_ROW_KIND.Option, true],
['English', '', settings.JEDIT_SETTING_ROW_KIND.Option, false],
['Français', '', settings.JEDIT_SETTING_ROW_KIND.Option, true],
['Theme', theme.name, settings.JEDIT_SETTING_ROW_KIND.Choice, false],
['Light/dark', 'Dark', settings.JEDIT_SETTING_ROW_KIND.Choice, false],
['Footer', 'On', settings.JEDIT_SETTING_ROW_KIND.Toggle, true],
Expand All @@ -57,17 +59,19 @@ test('jedit settings rows expose theme, footer, and markdown preview preferences
);
});

test('settings focus movement clamps to the available rows', async () => {
test('settings focus movement loops through the available rows', async () => {
const { settings } = await loadSettingsModules();

assert.equal(settings.moveSettingsFocusIndex(0, 1, 3), 1);
assert.equal(settings.moveSettingsFocusIndex(2, 1, 3), 2);
assert.equal(settings.moveSettingsFocusIndex(0, -1, 3), 0);
assert.equal(settings.moveSettingsFocusIndex(2, 1, 3), 0);
assert.equal(settings.moveSettingsFocusIndex(0, -1, 3), 2);
Comment thread
flyingrobots marked this conversation as resolved.
assert.equal(settings.moveSettingsFocusIndex(3, 0, 3), 2);
assert.equal(settings.moveSettingsFocusIndex(0, 1, 0), 0);
assert.equal(settings.moveSettingsFocusIndex(4, -1, 0), 0);
});

test('settings key reducer closes, moves, and activates focused settings rows', async () => {
const { settings, themes } = await loadSettingsModules();
const { keybindings, settings, themes } = await loadSettingsModules();
const theme = themes.availableJeditThemes()[0];
const baseModel = {
i18n: createI18nMock(),
Expand Down Expand Up @@ -109,6 +113,14 @@ test('settings key reducer closes, moves, and activates focused settings rows',
const [closed] = settings.updateJeditSettingsFromKey({ key: 'escape' }, baseModel, rows, handlers);
assert.equal(closed.settingsOpen, false);

const [closedWithQ] = settings.updateJeditSettingsFromKey(
{ key: keybindings.JEDIT_SETTINGS_CLOSE_KEY },
baseModel,
rows,
handlers,
);
assert.equal(closedWithQ.settingsOpen, false);

const [moved] = settings.updateJeditSettingsFromKey({ key: 'down' }, baseModel, rows, handlers);
assert.equal(moved.settingsFocusIndex, 1);

Expand Down
6 changes: 3 additions & 3 deletions spec/title-braille-sampling-policy.spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ test("title Braille sampling holds reduced quality while screen activity remains
);
});

test("title Braille sampling traces one dot while the camera moves under pressure", async () => {
test("title Braille sampling keeps full quality while the camera moves", async () => {
const sampling = await importDist(
"app",
"workspace",
Expand All @@ -190,8 +190,8 @@ test("title Braille sampling traces one dot while the camera moves under pressur
cameraMoving: true,
}),
{
phase: 2,
phaseCount: 8,
phase: 0,
phaseCount: 1,
},
);
});
Expand Down
13 changes: 10 additions & 3 deletions spec/title-scene-loader.spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -56,19 +56,23 @@ function normalize(vector) {
return vector.map((component) => component / length);
}

test("loaded mesh scenes do not expose scene-authored mesh position as ray-hit state", async () => {
test("loaded mesh scenes decode authored mesh transforms without exposing position", async () => {
const { loader, titleScene, titleMeshLibrary, titleBunnyMesh } =
await loadTitleSceneLoaderModules();
const mesh = titleMeshLibrary.createTitleBunnyMesh(
titleBunnyMesh.loadTitleBunnyMeshSource(),
);
const offset = [0.5, 0.1, -0.25];
const localYaw = { phase: 1.25, angularSpeed: 0.125 };
const scene = loader.parseTitleSceneJson(
{
objects: [
{
kind: titleScene.TITLE_SCENE_SHAPE_KIND.Mesh,
mesh: "bunny",
position: [100, 100, 100],
offset,
localYaw,
radius: mesh.footprintRadius,
footprintRadius: mesh.footprintRadius,
height: mesh.height,
Expand All @@ -80,12 +84,15 @@ test("loaded mesh scenes do not expose scene-authored mesh position as ray-hit s
{ bunny: mesh },
);
const loadedMesh = scene.objects[0];
const origin = [-1, 1.1, 4.5];
const ray = normalize([-0.05, -0.04, -1]);
const center = titleScene.titleSceneObjectFootprintCenter(loadedMesh);
const origin = [center[0], center[1] + 0.02, center[2] + 4.5];
const ray = normalize([0, -0.02, -1]);
const hit = titleScene.nearestTitleSceneObjectHit(origin, ray, scene.objects);

assert.equal(loadedMesh.kind, titleScene.TITLE_SCENE_SHAPE_KIND.Mesh);
assert.equal(Object.hasOwn(loadedMesh, "position"), false);
assert.deepEqual(loadedMesh.offset, offset);
assert.deepEqual(loadedMesh.localYaw, localYaw);
assert.ok(hit != null);
assert.equal(hit.object, loadedMesh);
});
Expand Down
Loading
Loading