Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,25 @@ Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) · Versioning:

## [Unreleased]

## [0.6.1] - 2026-07-21

### Fixed
- **The full learning loop now fits a 320 px window.** A compact Menu replaces
the crowded action rail, the architecture Map waits for real layout
dimensions before fitting, guidance gets its own row instead of covering Map
controls, and Study becomes a full-stage reading sheet. The header, canvas,
guidance, and local-only status remain visible without horizontal overflow.
- **Modules and Find work from the Star chart.** Both global commands now render
their surface in chart mode instead of accepting a click into hidden state
that only appeared after returning to the galaxy.
- **First-run guidance no longer competes with Home calibration.** After an
audience is chosen, a required Home choice finishes before the three-step
coach opens, so there is one decision in the foreground at a time.
- **Canvas clicks no longer corrupt OrbitControls pointer state.** Codemble's
parser-owned node layout is now explicitly non-draggable, preventing the 3D
dependency's drag-end bridge from injecting a synthetic touch release into a
mouse release. A stale-pointer guard and focused contract pin the fallback.

## [0.6.0] - 2026-07-21

### Added
Expand Down
10 changes: 9 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,14 @@ Polish, then the coordinated launch (Show HN / X; lit-galaxy GIF as hero).
## Current State **[AGENT-MAINTAINED]**

**Current milestone: Phase 1 tester evidence** · Last updated: 2026-07-21 ·
Session note: the v0.6.0 architecture-depth pass is complete in five
Session note: v0.6.1 closes the four verified user-flow gaps from the
2026-07-21 usability audit: the 320 px shell reserves a usable map/study stage,
Modules and Find render from the Star chart, required Home calibration finishes
before coach marks begin, and parser-owned 3D nodes no longer install drag
controls that can corrupt OrbitControls pointer state. The release is verified
against the real bundled app at desktop and 320 px widths; the milestone does
not advance because issue #13 still requires human tester evidence. The v0.6.0
architecture-depth pass is complete in five
behavior-preserving waves: project selection owns the home-jailed filesystem
policy; project activation atomically owns parse-to-live binding and graph/map
caches; project mapping owns picker attempts, polling, retry, outage, stale
Expand Down Expand Up @@ -534,6 +541,7 @@ shows lower repeated-commit work without changing derived values.
| 2026-07-21 | Architecture boxes are named by the tail of their file path (`short_label`, map schema 3); `label` keeps the full identifier for title and aria | A box is a fixed width, so its text always truncates on a real project — and truncating a dotted region id rendered `codemble.server.app` and `codemble.server.runtime` as the same glyphs. Identical text for different modules is worse than no label, and it is exactly the kind of wrong a learner cannot detect. The path tail also survives the `__init__.py` collision a basename alone cannot |
| 2026-07-21 | The Map gains zoom, Fit, and drag-to-pan; panning rides the container's own scroll and zoom only scales the rendered size | The 2D counterpart of bounded orbit: a 960x2640 diagram in a plain scroll box showed four of nine layers and no way to see the whole shape. Scroll-based panning keeps native scrollbars, keyboard scrolling and screen-reader behaviour intact, and because every coordinate inside the SVG stays backend-computed, React remains a pure renderer of graph-owned geometry. It opens at true size rather than auto-fitting: fitting on mount measured the scroller before layout settled and landed on a scale that was neither fitted nor honest |
| 2026-07-21 | v0.6.0 deepens five private boundaries without changing the HTTP, graph, check, persistence, or learner-visible contracts: Project Selection, Project Activation, Project Mapping Run, Name Atlas, and Learner Projection | Approved by UD as five behavior-preserving waves in one release PR. The deletion test now holds at each seam, stale activation and mapping responses lose atomically, and dependency-scoped learner projections measured ~0.331 ms → ~0.001 ms per hover commit on a synthetic 1,000-node project while preserving derived outputs |
| 2026-07-21 | v0.6.1 treats Modules and Find as global surfaces, sequences first-run decisions as audience → required Home → coach, and makes the 3D parser-owned layout explicitly non-draggable | Approved by UD as implementation of every verified user-flow audit finding. Global commands must never accept hidden state, onboarding must expose one foreground decision at a time, and learners orbit the immutable graph rather than editing its coordinates. The compact shell is a structural breakpoint of the existing Formal Edo interface, not a new visual system |

## Non-Goals — do NOT build (point here when asked)

Expand Down
2 changes: 1 addition & 1 deletion codemble/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Codemble — a learning game that turns the code AI wrote for you into a galaxy
you light up by understanding it. See CLAUDE.md for the agent brief and roadmap."""

__version__ = "0.6.0"
__version__ = "0.6.1"

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions codemble/web_dist/assets/index-CsUbeE2C.css

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion codemble/web_dist/assets/index-wY0ZuS7b.css

This file was deleted.

4 changes: 2 additions & 2 deletions codemble/web_dist/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
content="Explore the parser-proven structure of your local project with Codemble."
/>
<title>Codemble · Your code, mapped</title>
<script type="module" crossorigin src="/assets/index-BWorxSL3.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-wY0ZuS7b.css">
<script type="module" crossorigin src="/assets/index-0OmvUbwQ.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CsUbeE2C.css">
</head>
<body>
<div id="root"></div>
Expand Down
2 changes: 1 addition & 1 deletion docs-site/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "codemble-docs",
"type": "module",
"version": "0.6.0",
"version": "0.6.1",
"private": true,
"scripts": {
"dev": "astro dev",
Expand Down
4 changes: 4 additions & 0 deletions docs-site/src/content/docs/star-chart.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ In a mixed project, the chart follows the current language focus. This changes
only the rows and session counts you are viewing; the underlying project graph
and persisted understanding remain intact when you return to **All**.

**Modules** and **Find** remain available while the chart is open. The module
index opens beside the chart, and `⌘K` / `Ctrl-K` opens the same project-wide
finder used by the Map and Galaxy, including modules not yet charted.

"Studied" counts the structures you have opened **in this session** and resets
when you reload — that is deliberate. Opening a file is not evidence that you
understood it, so only "Understood", which comes from passing graph-derived
Expand Down
22 changes: 16 additions & 6 deletions docs-site/src/content/docs/the-galaxy.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,19 @@ lit state — not a faster animation, none at all.
Keyboard focus carries a visible reticle in the 3D scene as well as a live text
readout, so arrow-key navigation is never a guess about where you are.

## Semantic zoom, not free flight
## Bounded orbit, not free flight

Free-flight 3D looks fun in demos and is where comprehension goes to die.
Codemble's camera moves on rails between three levels — galaxy for orientation,
system for structure, study for learning — with scripted fly-to transitions.
Reading never happens "in space": the study panel takes the foreground, and the
sky behind it recedes to the structure you are reading and its connections.
Drag to orbit the current subject and use the wheel to zoom. Panning is off,
distance and polar angle are clamped for each level, and clicking a node moves
between galaxy, system, and study with a scripted transition. The parser owns
every node position, so nodes do not drag away from the graph. Reading never
happens "in space": the study panel takes the foreground, and the sky behind it
recedes to the structure you are reading and its connections.

At narrow widths the header's secondary actions live behind **Menu**, guidance
occupies its own row below the stage, and Study becomes a full-stage scrolling
sheet. The map/canvas and the local-only status remain in the viewport instead
of being squeezed behind controls.

## Two layers, one truth

Expand Down Expand Up @@ -139,3 +145,7 @@ works whether you started from the picker or passed a path.
least one candidate. The Home you choose is remembered for the next run of the
same project, and a saved choice the parser no longer ranks is dropped rather
than restored.

On a first run with more than one honest Home candidate, Codemble asks for your
audience first, then Home, then opens the three-step coach. Those decisions do
not stack on top of one another.
39 changes: 39 additions & 0 deletions docs/releases/v0.6.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Codemble v0.6.1 — the complete loop at every width

v0.6.1 closes every verified finding from the 2026-07-21 user-flow audit. It is
a focused usability and reliability release; parser, graph, checks,
persistence, local-first behavior, and the Formal Edo visual identity are
unchanged.

## Highlights

- The full map-to-study loop now remains usable at 320 px. Secondary actions
collapse into a keyboard-accessible Menu, the Map auto-fits only after its
real dimensions settle, guidance no longer covers its controls, and Study
owns the complete reading stage.
- Modules and Find are genuinely global: both render immediately from the Star
chart and close without leaving latent UI state behind.
- First-run decisions are sequenced as audience, required Home calibration,
then coach marks.
- The 3D graph is explicitly non-draggable. This matches the parser-owned layout
contract and removes a dependency-level mouse/touch pointer collision that
could throw after a canvas click.

## Verification

- Python tests and Ruff
- Web contract suite and production SPA build
- Documentation validation and production build
- Real bundled-app browser checks at 1280×900 and 320×800
- Repeated empty-canvas clicks, node travel into Study, Star-chart Modules and
Find, first-run audience/Home/coach order, horizontal overflow, and console
errors
- Wheel/sdist build, clean `uvx` install, Graphify refresh, CI, Pages, GitHub
release assets, and PyPI publication

## Known limits

- The 3D Galaxy still requires WebGL; the parser-backed Map remains the fallback.
- Progress stays local to the machine, and Star-chart Studied counts remain
session-only by design.
- The Phase 1 milestone still requires human tester evidence in issue #13.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "codemble"
version = "0.6.0"
version = "0.6.1"
description = "A learning game that turns the code AI wrote for you into a galaxy you light up by understanding it."
readme = "README.md"
license = "Apache-2.0"
Expand Down
4 changes: 2 additions & 2 deletions web/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions web/package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"name": "codemble-web",
"private": true,
"version": "0.6.0",
"version": "0.6.1",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"check": "node scripts/check_graph_data.mjs && node scripts/check_name_atlas.mjs && node scripts/check_project_mapping.mjs && node scripts/check_learner_projection.mjs && node scripts/check_learner_session.mjs && vite build",
"check": "node scripts/check_graph_data.mjs && node scripts/check_name_atlas.mjs && node scripts/check_project_mapping.mjs && node scripts/check_learner_projection.mjs && node scripts/check_learner_session.mjs && node scripts/check_orbit_pointer_guard.mjs && vite build",
"benchmark:projection": "node scripts/benchmark_learner_projection.mjs"
},
"dependencies": {
Expand Down
34 changes: 34 additions & 0 deletions web/scripts/check_orbit_pointer_guard.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";

import { clearStaleNonTouchPointers } from "../src/orbitPointerGuard.js";

const empty = { _pointers: [], _pointerPositions: {} };
assert.equal(clearStaleNonTouchPointers(empty, { pointerType: "mouse" }), false);

const touch = { _pointers: [4, 7], _pointerPositions: { 4: { x: 1 }, 7: { x: 2 } } };
assert.equal(clearStaleNonTouchPointers(touch, { pointerType: "touch" }), false);
assert.deepEqual(touch._pointers, [4, 7]);

const stalePointers = [3, 9];
const stalePositions = { 3: { x: 20, y: 30 } };
const mouse = { _pointers: stalePointers, _pointerPositions: stalePositions };
assert.equal(clearStaleNonTouchPointers(mouse, { pointerType: "mouse" }), true);
assert.equal(mouse._pointers, stalePointers, "mutate OrbitControls' collection in place");
assert.deepEqual(mouse._pointers, []);
assert.deepEqual(mouse._pointerPositions, {});

const pen = { _pointers: [11], _pointerPositions: {} };
assert.equal(clearStaleNonTouchPointers(pen, { pointerType: "pen" }), true);
assert.deepEqual(pen._pointers, []);

assert.equal(clearStaleNonTouchPointers({}, { pointerType: "mouse" }), false);

const galaxySource = readFileSync(new URL("../src/GalaxyCanvas.jsx", import.meta.url), "utf8");
assert.match(
galaxySource,
/\.enableNodeDrag\(false\)/,
"the immutable graph must not install 3d-force-graph drag controls",
);

console.log("orbit pointer guard contract: ok");
Loading