Skip to content

GraphPaper 0.6: ink-and-paper UI and editable spatial knowledge graphs - #10

Merged
AronAxe merged 13 commits into
mainfrom
feat/graph-studio-v0.6
Oct 8, 2026
Merged

AronAxe merged 13 commits into
mainfrom
feat/graph-studio-v0.6

Conversation

@AronAxe

@AronAxe AronAxe commented Oct 8, 2026 •

Copy link
Copy Markdown
Owner

Implemented

The real application UI now has charcoal/ink-blue surfaces, an offline-bundled scan of actual squared graph paper in the sidebar, and a spatial knowledge-graph editor. The scan is Calsidyrose's licensed CC BY 2.0 image with visible attribution.

  • Actual XYZ layout and perspective projection, canvas orbit, Shift-pan, wheel zoom, draggable nodes, fit/spread/reset, minimap, and flat 2D mode. The renderer uses crisp SVG rather than a new WebGL dependency.
  • Distinct node shapes/colors and relationship colors, patterns, direction arrows and labels. Bounded overview, full-graph search, filters and one/two-hop focus declutter without deleting stored graph data.
  • Click/edit nodes and connections, add/connect/delete with explicit confirmation, persistent graph-only undo, stale-save rejection and unsaved-edit guards. Source anchors, source documents, manuscripts, voice and writing instructions remain intact.
  • Existing Polemic/Science, reusable voice graphs and bounded JEV requests remain. No model calls are needed for navigation or manual editing.

Verified

Successful pre-merge release-candidate run: https://github.com/AronAxe/GraphPaper/actions/runs/37806576162 . Exact tested revision: fb03077f0cb5c332e6d47b50f13a18d6428c7fb4.

  • 299 automated Windows Python tests, no skips/failures; six Node geometry tests passed.
  • All seven real-HTTP browser suites passed, including the synthetic 600-node dense overview, full-graph search, editing, undo and responsive layouts.
  • 28 checks passed against the actual compiled Windows executable, including native mouse input, public Graphify extraction, graph orbit/edit/connect/delete/undo, voice reuse, native Save As and pending-edit persistence on close. No JavaScript errors or recursion errors.
  • Independently opened the hosted native report and its real application screenshot. The sidebar asset is actual paper, not a generated mockup. An earlier runner failed the CDP startup attachment before testing UI; publication remained blocked. The later exact-source native run completed successfully without weakening the gate.

Quality matrix: https://github.com/AronAxe/GraphPaper/actions/runs/37806575973 . Windows/Linux Python 3.12/3.13 and browser jobs passed. Documentation checks passed.

All changes and tests use a disposable ChatGPT working container and GitHub-hosted runners. No access to the user's computer, manuscripts, credentials or model accounts. No image generation. Provider responses are synthetic fixtures, not a claim of live writing quality validation.

Release

Merge triggers the main-branch v0.6 workflow, which revalidates and publishes only the archive that passes compiled-native checks and uploaded-checksum verification. Temporary source-transfer files/workflows have been removed from the final tree; the old v0.5 release workflow is superseded.

@AronAxe
AronAxe marked this pull request as ready for review October 8, 2026 16:18
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-08T16:21:29.431512Z fb03077 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@AronAxe
AronAxe merged commit 00cab75 into main Oct 8, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fb03077f0c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread ui/graph_studio.js
function gsConnectDialog(from,to){gsGuard(()=>showModal('Connect two ideas','Direction and relationship are yours to specify.',`<label for="gs-new-source">From</label><select id="gs-new-source">${gsEndpointOptions(from||state.node||state.p.graph.nodes[0]?.id)}</select><label class="mt12" for="gs-new-target">To</label><select id="gs-new-target">${gsEndpointOptions(to||state.p.graph.nodes[1]?.id)}</select><label class="mt12" for="gs-new-relation">Relationship</label><input id="gs-new-relation" list="gs-relations" value="related_to" maxlength="80">${gsRelationList()}<label class="mt12" for="gs-new-notes">Notes</label><textarea id="gs-new-notes" maxlength="2000"></textarea>`,btn('Create connection','gs-create-edge','branch','primary')));}
const gsPreviousAction=handleAction;
handleAction=async function(el){const a=el.dataset.action;
if(GS.dirty&&['tab','home','new','open-project','run-graph','run-angles','pin','unpin','exclude','clear-exclusions','brief'].includes(a)){gsGuard(()=>gsPreviousAction(el));return;}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Guard every rerendering action while graph fields are dirty

When an inspector field has unsaved changes, actions omitted from this allowlist can still invoke the original handler and rerender the application. For example, saving a project rename, saving settings, or changing a source role calls render() in ui/app.js, replacing the inspector with stored graph values and silently discarding the user's edits; GS.dirty remains true, so a later save prompt cannot recover the lost values. Route all actions that can rerender or replace project state through gsGuard while the inspector is dirty.

Useful? React with 👍 / 👎.

Comment thread ui/graph_math.js
Comment on lines +16 to +19
let candidates=g.nodes.filter(n=>(!o.kind||kind(n.kind)===o.kind)&&(!o.focus||neighborhood.has(n.id))&&(!search||matched.has(n.id)));
const rank=n=>(n.id===o.selected?1e7:0)+(path.has(n.id)?1e6:0)+(pins.has(n.id)?1e5:0)+(degree.get(n.id)||0);
candidates.sort((a,b)=>rank(b)-rank(a)||String(a.id).localeCompare(String(b.id)));
const nodes=candidates.slice(0,limit),ids=new Set(nodes.map(n=>n.id));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Apply relationship filters before enforcing the node budget

On graphs larger than the selected node limit, nodes are ranked and truncated before o.relation is applied to the edges. If all endpoints of the requested relationship family are low-degree nodes outside the initial 60/100/180-node slice, selecting that relationship reports zero connections even though matching edges exist in the graph. Filter or prioritize the matching edges' endpoints before slicing the node candidates so the connection filter can expose matches anywhere in the graph.

Useful? React with 👍 / 👎.

Comment thread ui/graph_studio.js
function gsEdgeStyle(value){const family=GraphMath.relation(value);if(family!=='association')return {...GS_REL[family],key:family};let h=0;for(const c of String(value||''))h=(h*31+c.charCodeAt(0))>>>0;const index=h%GS_OTHER.length;return {name:String(value),color:GS_OTHER[index],dash:['2 5','7 4','1 3','8 3 2 3','4 4',''][index],key:'other-'+index};}
function gsViewRender(){const inspector=$('.gs-inspector');render();if(GS.dirty&&inspector&&$('.gs-inspector'))$('.gs-inspector').replaceWith(inspector);}
function gsDefaults(){return {mode:'3d',yaw:.28,pitch:-.15,zoom:1,panX:0,panY:0,limit:60,kind:'',relation:'',hops:0,spread:1,fit:true};}
function gsEnsure(){if(!state.p)return;if(GS.pid===state.p.id)return;GS.pid=state.p.id;GS.view=gsDefaults();GS.positions=Object.create(null);GS.dirty=false;GS.linkFrom=null;GS.canUndo=false;GS.drag=null;try{const saved=JSON.parse(storage.getItem('graphpaper.spatial.'+GS.pid)||'null');if(saved){for(const key of ['yaw','pitch','zoom','panX','panY','spread'])if(Number.isFinite(saved.view?.[key]))GS.view[key]=GraphMath.clamp(saved.view[key],key==='zoom'?.12:-1e5,key==='zoom'?5:1e5);GS.view.spread=GraphMath.clamp(GS.view.spread,.5,3);GS.view.mode=saved.view?.mode==='2d'?'2d':'3d';GS.view.fit=false;for(const [id,p] of Object.entries(saved.positions||{}).slice(0,5000))if(['x','y','z'].every(k=>Number.isFinite(p[k])&&Math.abs(p[k])<1e6))GS.positions[id]=p;}}catch{}const pid=GS.pid;api('/projects/'+pid+'/graph/edit-status').then(s=>{if(GS.pid===pid){GS.canUndo=s.can_undo;const b=$('[data-action="gs-undo"]');if(b)b.disabled=!GS.canUndo||busy();}}).catch(()=>{});}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Refresh undo availability after replacing the graph

gsEnsure only fetches edit status when the project ID changes, so GS.canUndo remains true after the same project's graph is imported or rebuilt. In that scenario the rendered Undo button stays enabled even though the backend correctly rejects the old history because its after_hash no longer matches the replacement graph, leaving users with an action that consistently returns a conflict. Recheck or clear undo state whenever graph contents are replaced.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant