Something went wrong. Try again.
Monorepo for Aesthetic.Computer aesthetic.computer
Something went wrong. Try again.
Markdown
Prompt Tooltip System Plan #
Overview #
Create an intelligent tooltip/overlay system that displays command documentation, parameter hints, and validation feedback while typing in the AC prompt. Uses MatrixChunky8 font for a compact, pixel-perfect aesthetic.
Implementation Status: ✅ PHASE 1 COMPLETE #
What's Working #
- Tooltip state tracking in
prompt.mjs(lines 237-256) - Dual param system support:
colonParams[]andspaceParams[] updateTooltipState(): Parses text, finds matching doc, determines cursor contextpaintTooltip(): Renders signature, description, and suggestions- Docs fetching:
tooltipDocspopulated fromnet.requestDocs() - Several commands documented with colon/space params:
notepat[:wave][:octave] [melody...]tone[:wave] [frequency]tezos <action> [network]line[:thickness]camera[:mode]clock[:divisor]
AC's Dual Param System #
command:colon1:colon2 space1 space2
└───────┘ └──────────┘
colon[0,1] params[0,1]
- Colon params: Parsed from
tokens[0].split(":")→colon[]array - Space params: Parsed from
tokens.slice(1)→params[]array - Example:
notepat:square:5 twinkle→ colon=["square","5"], params=["twinkle"]
Current State Analysis #
Existing Infrastructure #
-
docs.js(Netlify function)- Contains comprehensive API documentation (
docs.api) - Contains prompt command documentation (
docs.prompts) - Structure:
{ sig, desc, colon?, params?, examples?, done, hidden? }
- Contains comprehensive API documentation (
-
prompt.mjsTooltip SystemtooltipStateobject tracks current command, params, cursor contextupdateTooltipState(text, cursorPos)parses and updates statepaintTooltip($, inputText)renders the tooltip overlay- Called every paint frame when input is active
-
Command Parsing (in parse.mjs)
const colonSplit = tokens[0].split(":"); tokens[0] = colonSplit[0]; // Command name colonParam = colonSplit.slice(1); // Colon params array params = tokens.slice(1); // Space params array -
Cursor Position Access
const cursorPos = prompt.textPos(); // Character index in text const screenPos = prompt.pos(undefined, true); // { x, y, w, h }
Phase 2: TODO #
Enhancements Needed #
Commands Needing Documentation #
$(the painting piece) - has colon scale paramreplay[:show]moods[:scale]oldline[:thickness]
Original Architecture (Reference) #
desc: "Record your screen.",
params: {
duration: {
type: "number",
required: false,
default: 5,
desc: "Recording duration in seconds (suffix 'f' for frames)",
examples: ["5", "10", "30f"]
},
options: {
type: "flags",
values: ["mic", "nomic", "baktok"],
desc: "Recording options"
}
}
}, keep: { sig: "keep <$code>", desc: "Mint KidLisp code as NFT.", params: { code: { type: "string", required: true, prefix: "$", desc: "KidLisp piece code to mint" } } }, // ... etc }
### 2. Tooltip State Machine
```javascript
// In prompt.mjs
let tooltipState = {
visible: false,
command: null, // Current command being typed
params: [], // Parsed params so far
currentParamIndex: 0, // Which param cursor is in
suggestions: [], // Valid values for current param
error: null, // Validation error message
position: { x: 0, y: 0 }
};
3. Tooltip Parser #
function parseForTooltip(text, cursorPosition) {
const tokens = text.split(" ");
const command = tokens[0].split(":")[0]; // Strip colon params
const colonParams = tokens[0].split(":").slice(1);
const params = tokens.slice(1);
// Find which token the cursor is in
let charCount = 0;
let currentTokenIndex = 0;
for (let i = 0; i < tokens.length; i++) {
if (cursorPosition <= charCount + tokens[i].length) {
currentTokenIndex = i;
break;
}
charCount += tokens[i].length + 1; // +1 for space
}
return {
command,
colonParams,
params,
currentTokenIndex,
isInCommand: currentTokenIndex === 0,
currentParamIndex: currentTokenIndex - 1
};
}
4. Tooltip Renderer #
function paintTooltip($, tooltipState, cursorPos) {
if (!tooltipState.visible) return;
const FONT = "MatrixChunky8";
const CHAR_W = 4;
const CHAR_H = 8;
const PADDING = 2;
const MARGIN_Y = 4;
// Position below cursor
const tooltipY = cursorPos.y + cursorPos.h + MARGIN_Y;
const tooltipX = cursorPos.x;
// Build tooltip content
let lines = [];
// Line 1: Command signature
if (tooltipState.command?.sig) {
lines.push({ text: tooltipState.command.sig, color: [180, 180, 180] });
}
// Line 2: Current parameter hint
if (tooltipState.currentParam) {
const param = tooltipState.currentParam;
let hint = `${param.name}`;
if (param.type === "enum") {
hint += `: ${param.values.join(" | ")}`;
} else if (param.type === "number") {
hint += `: <number>`;
}
if (!param.required) hint = `[${hint}]`;
lines.push({ text: hint, color: [100, 200, 255] });
}
// Line 3: Description or error
if (tooltipState.error) {
lines.push({ text: `⚠ ${tooltipState.error}`, color: [255, 100, 100] });
} else if (tooltipState.currentParam?.desc) {
lines.push({ text: tooltipState.currentParam.desc, color: [150, 150, 150] });
}
// Calculate dimensions
const maxWidth = Math.max(...lines.map(l => l.text.length)) * CHAR_W;
const totalHeight = lines.length * CHAR_H + (lines.length - 1) * 2;
// Clamp to screen bounds
const finalX = Math.min(tooltipX, $.screen.width - maxWidth - PADDING * 2);
const finalY = Math.min(tooltipY, $.screen.height - totalHeight - PADDING * 2);
// Draw background
$.ink(0, 0, 0, 200).box(
finalX - PADDING,
finalY - PADDING,
maxWidth + PADDING * 2,
totalHeight + PADDING * 2
);
// Draw border
$.ink(60, 60, 60).box(
finalX - PADDING,
finalY - PADDING,
maxWidth + PADDING * 2,
totalHeight + PADDING * 2,
"outline"
);
// Draw lines
lines.forEach((line, i) => {
$.ink(...line.color).write(
line.text,
{ x: finalX, y: finalY + i * (CHAR_H + 2) },
undefined, undefined, false, FONT
);
});
}
Implementation Steps #
Phase 1: Documentation Updates (docs.js) #
- Add
paramsschema to all existing prompts - Document new commands:
tezos connect/disconnect/statuskeep $codemoodchannel- All other undocumented prompts
Phase 2: Tooltip State Management (prompt.mjs) #
- Add tooltip state variables
- Create
updateTooltipState(text, cursorPos)function - Call on every
prompt:text:replaceevent - Parse current input and match against docs
Phase 3: Tooltip Rendering (prompt.mjs paint) #
- Add
paintTooltip()function - Render after prompt text, before overlays
- Handle screen edge clamping
- Animate fade-in/out
Phase 4: Validation System #
- Type checking (enum, number, string)
- Required param validation
- Show errors inline with red color
- Prevent invalid submissions with feedback
Phase 5: Enhanced Features #
- Tab completion for params - Tab through enum values
- Inline suggestions - Ghost text for likely completions
- Command history hints - Show recent uses of command
- Keyboard navigation - Arrow keys to select suggestions
Visual Design #
┌─────────────────────────────────────┐
│ > tezos connect█ │ ← Cursor here
│ │
│ ┌─────────────────────────────────┐ │
│ │ tezos <subcommand> [network] │ │ ← Signature (gray)
│ │ network: ghostnet | mainnet │ │ ← Current param (cyan)
│ │ Connect wallet to network │ │ ← Description (dim)
│ └─────────────────────────────────┘ │
└─────────────────────────────────────┘
Error state:
┌─────────────────────────────────────┐
│ > tezos blah█ │
│ │
│ ┌─────────────────────────────────┐ │
│ │ tezos <subcommand> │ │
│ │ subcommand: connect|disconnect │ │
│ │ ⚠ Invalid: "blah" │ │ ← Error (red)
│ └─────────────────────────────────┘ │
└─────────────────────────────────────┘
Commands Needing Documentation #
Priority additions to docs.prompts:
// Wallet/Blockchain
tezos: { subcommands: connect, disconnect, status }
keep: { params: $code }
// Recording
tape: { params: duration, mic, nomic, baktok, cut }
cut: {}
// Social
mood: { params: emoji }
scream: { params: message }
me: {}
// Painting
done: {}
yes: {}
print: {}
mint: {}
p: {} // alias for pain
pain: {}
dl: { params: scale }
download: { params: scale }
// Coding
code: { params: name }
edit: { params: piece }
run: { params: code }
channel: { params: channel_name }
// Settings
nonotifs: {}
notifs: {}
selfie: {}
cam: {}
// Navigation
docs: {}
email: { params: address }
handle: { params: new_handle }
Files to Modify #
-
system/netlify/functions/docs.js- Add
paramsschema to all prompts - Document all missing commands
- Add
-
system/public/aesthetic.computer/disks/prompt.mjs- Add tooltip state management
- Add
parseForTooltip()function - Add
updateTooltipState()function - Add
paintTooltip()in paint function - Modify
prompt:text:replacehandler
-
system/public/aesthetic.computer/lib/type.mjs(optional)- Expose additional cursor position info if needed
Future Enhancements #
- Fuzzy matching - "tez" suggests "tezos"
- Command aliases - Map "tz" to "tezos"
- Context-aware hints - Different suggestions based on app state
- Learning system - Prioritize frequently used commands
- Multilingual tooltips - Match prompt translations
- Voice hints - TTS for accessibility
Dependencies #
- MatrixChunky8 font (already loaded)
- docs.js endpoint (already exists)
- Cursor position API (already exists)
Timeline Estimate #
- Phase 1 (Docs): 2-3 hours
- Phase 2 (State): 1-2 hours
- Phase 3 (Render): 2-3 hours
- Phase 4 (Validation): 2-3 hours
- Phase 5 (Enhancements): 4-6 hours
Total: ~12-17 hours