Images
Close
body
reasonably
A Thinking Notebook · Raw Edition
The thought arrives.
Structure follows.
Write the thought as it arrives…
c
↑ ↓ / j k
Navigate sentence by sentence
● / c key
Quick capture — write the thought
Double-click
Edit any sentence in place
Hover header
Spine — emotional document map
Open the notebook →
or press any key
reasonably
A Thinking Notebook
Untitled · Begin below ▾
v1 · saved
↩
↪
☰
✏
Read
Write
Both
↗ Export
? Keys
Mood at writing ·
Neutral
Poignant
Perplexed
Empowered
Dark
0 chapters · 0 sentences
×
Contents
—
⇅
⇅
Step mode
Write the thought as it arrives…
c
↑
— / —
↓
×
◂
▪
▸
Compose
Arrange
Node Canvas
Chapter
###:N · Title
Chapter Header
A new section of thought.
Poster
Hero statement
Poster
The idea stated large.
Body
Narrative prose
Body
The argument forward.
Pull
Pull quote
Pull Quote
The truest sentence.
Label
Small caps tag
Label
Identity · Date
Spec
Key :: Value
Spec Row
Subject :: Value
— Break
Syntax preview…
⎘ Copy
Edit ·
body
×
Write freely — name it after
×
B
I
U
· List
1. List
How does it feel?
Neutral
Set →
Captured ·
—
Inject into chapter
or
+ New chapter
Append to end
Done ✓
body
Narrative prose
×
::
·
✦
**bold**
*italic*
~~dim~~
Enter
commit
⇧Enter
line
Esc
close
Commit →
Retype sentence
×
body
→
body
c / click bar
Quick capture
Ctrl+Z / Ctrl+Y
Undo / Redo
↑ ↓ / j k
Navigate
1–9
Jump to chapter
r
Reading mode
t
Toggle contents
Double-click sentence
Edit in place
Right-click page
Step mode
s / hover header
Spine wayfinding
?
This help
// ─── NODE GHOST OVERLAY ──────────────────────────────────────────────────── (function() { const overlay = document.getElementById('node-ghost-overlay'); const ngoTA = document.getElementById('ngo-textarea'); const ngoPill = document.getElementById('ngo-type-pill'); const TYPE_PLACEHOLDERS = { poster: 'The central declaration.', body: 'The thought, plainly stated.', pull: 'The truest sentence.', label: 'Category · Date', spec: 'key :: value', chapter: 'Chapter title', draft: 'Raw capture…' }; const TYPE_LABELS = { poster:'poster', body:'body', pull:'pull', label:'label', spec:'spec', chapter:'chapter', draft:'draft' }; let _ngoSourceInput = null; let _ngoNodeType = 'body'; let _ngoOpen = false; let _ngoBlurTimer = null; function openNodeGhost(inp, nodeType) { _ngoSourceInput = inp; _ngoNodeType = nodeType || 'body'; _ngoOpen = true; overlay.className = 'ngo-open ngo-type-' + _ngoNodeType; ngoPill.textContent = TYPE_LABELS[_ngoNodeType] || _ngoNodeType; ngoTA.placeholder = TYPE_PLACEHOLDERS[_ngoNodeType] || 'Write…'; ngoTA.value = inp.value; ngoTA.style.height = 'auto'; ngoTA.style.height = Math.min(ngoTA.scrollHeight, window.innerHeight * 0.55) + 'px'; // Suppress capture UI while ghost is active document.body.classList.add('ngo-active'); if (typeof closeCapture === 'function' && captureOpen) closeCapture(); // Update submit button label const submitBtn = document.getElementById('ngo-submit'); if (submitBtn) { const multiLine = ['body','poster','pull','draft'].includes(_ngoNodeType); submitBtn.textContent = multiLine ? 'Commit' : 'Set'; } requestAnimationFrame(() => { ngoTA.focus(); ngoTA.setSelectionRange(ngoTA.value.length, ngoTA.value.length); }); } function closeNodeGhost(refocusSource) { if (!_ngoOpen) return; _ngoOpen = false; overlay.classList.remove('ngo-open'); document.body.classList.remove('ngo-active'); if (refocusSource && _ngoSourceInput) { _ngoSourceInput.focus(); _ngoSourceInput.setSelectionRange(_ngoSourceInput.value.length, _ngoSourceInput.value.length); } _ngoSourceInput = null; } // ngo-submit button — commit and close window.ngoCommit = function() { if (!_ngoOpen || !_ngoSourceInput) { closeNodeGhost(false); return; } _ngoSourceInput.value = ngoTA.value; _ngoSourceInput.dispatchEvent(new Event('input', { bubbles: true })); closeNodeGhost(true); }; ngoTA.addEventListener('input', () => { if (!_ngoSourceInput) return; _ngoSourceInput.value = ngoTA.value; _ngoSourceInput.dispatchEvent(new Event('input', { bubbles: true })); ngoTA.style.height = 'auto'; ngoTA.style.height = Math.min(ngoTA.scrollHeight, window.innerHeight * 0.55) + 'px'; }); ngoTA.addEventListener('keydown', e => { if (e.key === 'Escape') { e.preventDefault(); closeNodeGhost(false); } const multiLine = ['body','poster','pull','draft'].includes(_ngoNodeType); if (e.key === 'Enter' && !e.shiftKey && !multiLine) { e.preventDefault(); closeNodeGhost(false); } }); document.getElementById('ngo-backdrop').addEventListener('mousedown', () => { closeNodeGhost(false); }); const canvasEl = document.getElementById('node-canvas'); if (canvasEl) { canvasEl.addEventListener('focusin', e => { if (window.innerWidth <= 720) return; const inp = e.target; if (!inp || inp.tagName !== 'INPUT') return; clearTimeout(_ngoBlurTimer); const card = inp.closest('.n-card'); if (!card) return; const badge = card.querySelector('.n-badge'); let type = badge ? badge.textContent.trim() : 'body'; if (type === 'ch') type = 'chapter'; if (type === '?') type = 'draft'; if (inp.classList.contains('n-spec-k')) type = 'spec'; openNodeGhost(inp, type); }); canvasEl.addEventListener('focusout', () => { _ngoBlurTimer = setTimeout(() => { if (!_ngoOpen) return; const active = document.activeElement; if (active && overlay.contains(active)) return; closeNodeGhost(false); }, 120); }); } overlay.addEventListener('focusin', () => clearTimeout(_ngoBlurTimer)); window.openNodeGhost = openNodeGhost; window.closeNodeGhost = closeNodeGhost; // Close ghost if viewport shrinks to mobile window.addEventListener('resize', () => { if (window.innerWidth <= 720 && _ngoOpen) closeNodeGhost(false); }); })();
⊡
Read
✏
Write
⠿
File
●
Capture