Clock Sigil Shortcodes (*) Implementation Plan#
STATUS: ✅ IMPLEMENTED - 2025.06.14
Summary#
The * sigil for clock.mjs melodies has been implemented. You can now:
- Type
*bakoin the prompt to load a cached melody - Visit URLs like
prompt.ac/*bakooraesthetic.computer/*bako - Share melodies via QR codes that appear in the corner (same as
$for KidLisp)
Code Changes Made#
- store-clock.mjs (NEW) - API for storing/retrieving melodies
- index.mjs - Added
*xxxURL routing andclock:xxxredirects - parse.mjs - Added
*sigil detection to route to clock piece - clock.mjs - Added async boot, API fetch for
*code, melody caching - disk.mjs - Extended QR corner display for clock pieces with
*sigil
Pronounceable Codes#
Uses CVCV pattern (consonant-vowel-consonant-vowel) with:
- 70% pure vowels (aeiou)
- 30% single-syllable digits (1,2,3,4,5,6,8,9)
Examples: bako, milu, de4a, to2i
Overview#
Add a new * sigil for clock.mjs melodies, similar to existing sigils:
$→ KidLisp pieces (e.g.,$roz,$cow)#→ Paintings (e.g.,#waf,#abc)!→ Video/Tapes (e.g.,!xyz, video piece prefix)
New: * → Clock melodies (e.g., *bah, *cdefg)
Current Sigil Architecture#
KidLisp ($) - Reference Implementation#
The $ sigil is the most complete implementation and serves as our reference:
-
URL Routing (index.mjs#L210-225)
- Handles
kidlisp:code→ redirects to$codeformat - Direct
/$xxxpaths load the KidLisp piece
- Handles
-
Storage API (store-kidlisp.mjs)
- POST: Stores source code, generates unique short code (nanoid)
- GET: Retrieves source by code
- Supports authenticated (user-linked) and anonymous storage
- Hash-based deduplication
- MongoDB collection:
kidlisp
-
Parser Support (parse.mjs)
- Detects KidLisp source patterns
- Decodes URL-encoded source
- Routes to appropriate piece
-
Corner QR Code (disk.mjs)
- Displays QR code linking to
prompt.ac/$code - Tappable to toggle fullscreen QR
- Auto-generated when piece is cached
- Displays QR code linking to
-
Authorship & Uniqueness
- Hash-based deduplication (identical code → same shortcode)
- User ID stored when authenticated
- Anonymous pieces allowed (no user field)
Painting (#) - Simpler Implementation#
- Storage: painting-code.mjs
- Collection:
paintings(links code → slug/user) - URL Pattern:
/#abcorpainting~#abc
Video/Tape (!)#
!: Video piece prefix (triggers video.mjs loading for tapes)
Proposed Clock (*) Implementation#
1. Storage API: store-clock.mjs#
Create new Netlify function at system/netlify/functions/store-clock.mjs:
// Store Clock Melody, 2026.01.02
// Caches clock melody strings and generates pronounceable short codes for QR codes
// Pronounceable code generation (CVCV pattern for singability)
// Examples: bako, milu, dena, tofi, raku
const CONSONANTS = 'bdfghjklmnprstvwz'.split(''); // 17 consonants (no hard-to-pronounce)
const VOWELS = 'aeiou'.split(''); // 5 vowels
function generatePronounceable(length = 4) {
let code = '';
for (let i = 0; i < length; i++) {
const chars = i % 2 === 0 ? CONSONANTS : VOWELS;
code += chars[Math.floor(Math.random() * chars.length)];
}
return code;
}
// Collection: 'clocks' in MongoDB
// Schema:
{
code: string, // Short unique code (e.g., "bah", "xyz")
melody: string, // The melody string (e.g., "cdefgab", "{square}ceg dfa")
hash: string, // SHA256 of melody for deduplication
user: string, // User ID (optional, for authorship)
handle: string, // User handle at time of save (optional)
when: Date, // Creation timestamp
hits: number, // View count
kept: object // NFT/Tezos integration (future)
}
Endpoints:
POST /api/store-clock- Store melody, return codeGET /api/store-clock?code=xxx- Retrieve melody by codeGET /api/store-clock?recent=true&limit=N- List recent clocks
2. URL Routing Updates#
In index.mjs:
Add handling for * prefix similar to $:
// Handle clock:code URL pattern and convert to *code format
if (slug.startsWith("clock:") && slug.length > 6) {
const code = slug.slice(6);
const newSlug = `*${code}`;
return respond(302, `Redirecting to /${newSlug}`, {
"Content-Type": "text/html",
Location: `/${newSlug}`,
});
}
// Handle *xxx clock codes
if (slug.startsWith("*") && slug.length > 1) {
const code = slug.slice(1);
// Fetch clock melody from API
const clockData = await fetch(`/api/store-clock?code=${code}`);
if (clockData.melody) {
// Redirect to clock piece with melody parameter
return respond(302, `Redirecting to /clock~${clockData.melody}`, {
Location: `/clock~${encodeURIComponent(clockData.melody)}`,
});
}
}
3. Parser Updates#
In parse.mjs:
Add clock sigil detection:
// Check for clock shortcode (*xxx)
if (tokens[0] && tokens[0].startsWith("*") && tokens[0].length > 1) {
tokens.unshift("clock"); // Route to clock piece
}
4. Clock Piece Updates#
In clock.mjs:
Add auto-caching and QR display support:
// On boot, if melody provided:
// 1. Cache the melody via store-clock API
// 2. Store the returned code for QR display
// 3. Display corner QR linking to prompt.ac/*code
let cachedCode = null;
async function cacheMelody(melody, api) {
try {
const response = await fetch('/api/store-clock', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ melody })
});
const data = await response.json();
cachedCode = data.code;
return data.code;
} catch (e) {
console.warn('Failed to cache clock melody:', e);
}
}
5. HUD/QR Corner Display#
In disk.mjs:
Extend QR corner logic to support clock pieces:
// Detect clock piece with cached code
const isClockPiece = currentPath === "clock" || currentPath?.startsWith("clock~");
const isClockWithCode = isClockPiece && cachedClockCode;
// Generate QR for clock pieces
if (isClockWithCode) {
const url = `https://prompt.ac/*${cachedClockCode}`;
// Use same QR rendering as KidLisp pieces
}
6. Prompt Piece Integration#
In prompt.mjs:
Add * handling in halt function:
// Handle *xxx clock shortcode
if (text.startsWith("*") && text.length > 1) {
const code = text.slice(1);
// Fetch and jump to clock melody
const response = await fetch(`/api/store-clock?code=${code}`);
if (response.melody) {
jump(`clock~${response.melody}`);
return true;
}
}
Database Schema#
Collection: clocks#
{
_id: ObjectId,
code: String, // Unique short code (indexed, unique)
melody: String, // Full melody string
hash: String, // SHA256 hash (indexed, unique for dedup)
user: String, // Auth0 user ID (optional, sparse index)
handle: String, // User handle at save time
when: Date, // Creation timestamp (indexed)
hits: Number, // View count
kept: { // NFT integration (future)
network: String,
contract: String,
tokenId: String
}
}
Indexes#
await collection.createIndex({ code: 1 }, { unique: true });
await collection.createIndex({ hash: 1 }, { unique: true });
await collection.createIndex({ user: 1 }, { sparse: true });
await collection.createIndex({ when: -1 });
await collection.createIndex({ hits: -1 });
Implementation Order#
Phase 1: Core Storage#
- Create
store-clock.mjsfunction - Add MongoDB collection and indexes
- Implement POST (store) endpoint
- Implement GET (retrieve) endpoint
- Add hash-based deduplication
Phase 2: URL Routing#
- Update
index.mjsfor*xxxrouting - Update
parse.mjsfor*sigil detection - Handle
clock:xxx→*xxxredirects
Phase 3: Clock Piece Integration#
- Add melody auto-caching to clock.mjs boot
- Store cached code for QR display
- Pass cached code to HUD system
Phase 4: QR Display#
- Extend disk.mjs QR corner logic for clock pieces
- Add clock detection alongside KidLisp detection
- Test QR generation with
prompt.ac/*codeURLs
Phase 5: Prompt Integration#
- Add
*handling in prompt.mjs halt() - Test
*bahcommand input - Test URL bar navigation to
/*bah
Phase 6: Polish#
- Add authorship display (corner label)
- Add anonymous vs authenticated distinction
- Add hit counting
- Test edge cases (empty melody, special chars, etc.)
Files to Modify#
| File | Changes |
|---|---|
system/netlify/functions/store-clock.mjs |
NEW - Clock storage API |
system/netlify/functions/index.mjs |
Add * routing, clock: redirect |
system/public/aesthetic.computer/lib/parse.mjs |
Add * sigil detection |
system/public/aesthetic.computer/lib/disk.mjs |
Extend QR corner for clock |
system/public/aesthetic.computer/disks/clock.mjs |
Add caching, QR support |
system/public/aesthetic.computer/disks/prompt.mjs |
Add * command handling |
URL Patterns#
| Pattern | Description |
|---|---|
/*bah |
Direct URL to clock shortcode |
/clock:bah |
Legacy format, redirects to /*bah |
/clock~cdefgab |
Direct melody (no caching) |
prompt.ac/*bah |
QR code destination |
Edge Cases#
- Empty melody - Reject with 400 error
- Very long melody - Limit to 10,000 chars (like KidLisp)
- Special characters - URL encode in redirects
- Duplicate melody - Return existing code (hash match)
- Invalid code - Return 404 with helpful message
- Rate limiting - Consider for POST endpoint
Testing Checklist#
-
*bahin prompt navigates to clock piece -
/*bahURL loads correct melody - QR code appears in corner during clock playback
- QR links to
prompt.ac/*code - Anonymous storage works (no auth)
- Authenticated storage links to user
- Duplicate melodies return same code
- Hit counter increments on GET
- Long melodies are handled properly
- Special chars in melody work correctly
Future Considerations#
- Tezos "Keep" Integration - Like KidLisp, allow clock melodies to be "kept" as NFTs
- Feed/Discovery - Add clocks to the TV feed system
- Embed in KidLisp - Allow
(*code)syntax to play clocks within KidLisp - Collaboration - Multiple users contributing to same clock
- Versioning - Track edits to saved clocks
- Disambiguation Page - When accessing
/bako(no sigil), show a disambiguation page listing all matching codes across sigil types:- 🎵
*bako- Clock melody - 🎨
$bako- KidLisp piece - 🖼️
#bako- Painting - Auto-redirect if only one type exists
- 🎵