Monorepo for Aesthetic.Computer
aesthetic.computer
KidLisp Integration with Aesthetic Computer Painting API#
Executive Summary#
This document outlines a comprehensive plan to integrate kidlisp support into the aesthetic computer's common painting API. The goal is to enable a new kidlisp() function that creates isolated kidlisp rendering contexts within normal JavaScript pieces, allowing for dynamic lisp-based graphics generation.
Current Architecture Analysis#
1. KidLisp System (/lib/kidlisp.mjs)#
Core Components:
KidLispclass: Main interpreter with environment management- Global environment with painting commands (
ink,wipe,line,box, etc.) - Embedded layer system with buffer isolation
- Performance optimizations and caching
- Source code compilation and evaluation
Key Features:
- Multiple environment support with
getGlobalEnv() - Embedded buffer rendering via
createEmbeddedLayerFromSource() - API wrapping with buffer switching via
page()function - Color processing and graphic primitives
- Isolation through separate
kidlispInstanceper layer
2. Common Painting API (/lib/disk.mjs)#
Core Components:
$commonApi: Main API object with all system functions$paintApi: Core painting functions (write,form, etc.)$paintApiUnwrapped: Direct graphics functions (ink,wipe,line, etc.)Paintingclass: Buffer management withapi.painting()factory
Key Features:
painting(width, height, callback): Creates isolated paint bufferspage(buffer): Switches active painting context- API composition with buffer-specific wrappers
- Screen and buffer management through
$activePaintApi
3. Piece Structure (e.g., wipppps.mjs)#
Interaction Pattern:
function paint({ wipe, ink, line, box, painting, page, paste, ... }) {
// Pieces receive destructured painting functions
// Functions operate on current active buffer
}
Implementation Plan#
Phase 1: Core kidlisp() Function#
1.1 Function Signature#
kidlisp(x, y, width, height, source, options = {})
Parameters:
x, y: Position to paste the kidlisp bufferwidth, height: Dimensions of the kidlisp rendering buffersource: KidLisp source code stringoptions: Configuration object
1.2 Integration Point#
Add to $paintApiUnwrapped in /lib/disk.mjs:
const $paintApiUnwrapped = {
// ... existing functions
kidlisp: function(x, y, width, height, source, options = {}) {
return renderKidLispBuffer(x, y, width, height, source, options);
}
};
Phase 2: KidLisp Buffer Manager#
2.1 Buffer Creation and Isolation#
function renderKidLispBuffer(x, y, width, height, source, options = {}) {
// 1. Create isolated kidlisp instance
const kidlispInstance = new KidLisp();
// 2. Create isolated painting buffer
const kidlispBuffer = $activePaintApi.painting(width, height, (bufferApi) => {
// 3. Create wrapped API for kidlisp
const kidlispAPI = createKidLispAPIWrapper(bufferApi, options);
// 4. Execute kidlisp code in isolated context
try {
const parsedCode = kidlispInstance.parse(source);
kidlispInstance.evaluate(parsedCode, kidlispAPI, kidlispInstance.getGlobalEnv());
} catch (error) {
console.error('KidLisp execution error:', error);
// Render error message in buffer
bufferApi.wipe(64, 0, 0); // Dark red background
bufferApi.ink(255, 255, 255).write('ERROR', 10, 10);
}
});
// 5. Paste buffer to main canvas
$activePaintApi.paste(kidlispBuffer, x, y);
return kidlispBuffer; // Allow for further manipulation
}
2.2 API Wrapper Creation#
function createKidLispAPIWrapper(bufferApi, options = {}) {
const kidlispEnv = new KidLisp().getGlobalEnv();
// Merge buffer API with kidlisp environment
const wrappedAPI = {
// Core graphics from buffer API
...bufferApi,
// KidLisp-specific commands
...kidlispEnv,
// Screen context (bounded to kidlisp buffer)
screen: {
width: bufferApi.screen?.width || 256,
height: bufferApi.screen?.height || 256,
pixels: bufferApi.screen?.pixels
},
// Restricted API (no system access)
system: undefined,
net: undefined,
// Configurable options
...options.additionalAPI
};
return wrappedAPI;
}
Phase 3: Enhanced Features#
3.1 Caching System#
const kidlispCache = new Map();
function getCachedKidLispResult(source, width, height) {
const cacheKey = `${source}-${width}x${height}`;
return kidlispCache.get(cacheKey);
}
function setCachedKidLispResult(source, width, height, buffer) {
const cacheKey = `${source}-${width}x${height}`;
kidlispCache.set(cacheKey, buffer);
}
3.2 Animation Support#
kidlisp(x, y, width, height, source, {
frame: paintCount, // Pass frame number for animations
time: performance.now(), // Pass time for time-based effects
animated: true // Enable per-frame evaluation
});
3.3 Error Handling and Debugging#
kidlisp(x, y, width, height, source, {
debug: true, // Show debug info
errorMode: 'visual', // 'visual', 'console', 'silent'
fallback: '(wipe red)' // Fallback code on error
});
Phase 4: Performance Optimizations#
4.1 Lazy Evaluation#
- Only recompile kidlisp when source changes
- Cache parsed AST for repeated calls
- Implement dirty checking for animated content
4.2 Buffer Pooling#
const bufferPool = [];
function getPooledBuffer(width, height) {
const existing = bufferPool.find(b => b.width === width && b.height === height);
if (existing) {
bufferPool.splice(bufferPool.indexOf(existing), 1);
// Clear buffer for reuse
existing.api.wipe(0, 0, 0, 0);
return existing;
}
return createNewBuffer(width, height);
}
4.3 Selective Rendering#
kidlisp(x, y, width, height, source, {
renderWhen: (frame) => frame % 10 === 0, // Only render every 10th frame
staticCache: true // Cache static content
});
Implementation Sequence#
Step 1: Basic Integration (Week 1)#
- Add basic
kidlisp()function to$paintApiUnwrapped - Implement
renderKidLispBuffer()with minimal features - Create
createKidLispAPIWrapper()for API isolation - Test with simple kidlisp programs:
(wipe blue),(ink red) (box 10 10 50 50)
Step 2: Buffer Management (Week 2)#
- Implement proper buffer isolation using existing
painting()system - Add error handling and visual error reporting
- Test buffer compositing and transparency
- Validate API isolation (no system access from kidlisp context)
Step 3: Advanced Features (Week 3)#
- Add caching system for performance
- Implement animation support with frame/time parameters
- Add debugging and error visualization options
- Performance profiling and optimization
Step 4: Integration Testing (Week 4)#
- Test with complex kidlisp programs
- Validate integration with existing pieces like
wipppps.mjs - Performance testing with multiple concurrent kidlisp buffers
- Memory leak detection and cleanup
Usage Examples#
Basic Usage#
// In any aesthetic computer piece
function paint({ kidlisp, ... }) {
// Simple static kidlisp graphic
kidlisp(100, 100, 64, 64, '(wipe blue) (ink yellow) (box 10 10 40 40)');
}
Animation#
function paint({ kidlisp, paintCount, ... }) {
// Animated kidlisp content
kidlisp(0, 0, 256, 256, `
(wipe black)
(ink rainbow)
(def t ${paintCount})
(circle (+ 128 (* 50 (cos (* t 0.1)))) 128 20)
`, { frame: paintCount });
}
Multiple Buffers#
function paint({ kidlisp, ... }) {
// Background layer
kidlisp(0, 0, screen.width, screen.height, '(wipe "fade:blue-purple")');
// Foreground elements
kidlisp(50, 50, 100, 100, '(ink white) (circle 50 50 30)');
kidlisp(200, 50, 100, 100, '(ink red) (box 0 0 100 100)');
}
Technical Considerations#
Security#
- KidLisp contexts must be isolated from system APIs
- No access to
net,system,store, or other sensitive functions - File system access restrictions
Performance#
- Buffer creation overhead mitigation through pooling
- Smart caching based on source code and parameters
- Frame-rate-aware rendering for animations
Memory Management#
- Automatic cleanup of unused buffers
- Garbage collection integration
- Memory usage monitoring and limits
Compatibility#
- Maintain backward compatibility with existing pieces
- No breaking changes to current painting API
- Progressive enhancement model
TODO Progress Tracking#
Current Sprint: Basic Prototype Testing ✅ STARTED#
- Create kidlisp-in-js.mjs based on blank.mjs template
- Add KidLisp import and initialization
- Implement basic kidlispBasic() prototype function
- Add buffer creation with kidlisp evaluation
- Test the piece in browser and debug any issues
- Validate kidlisp parsing and evaluation works
- Test API isolation and error boundaries
- Confirm painting buffer integration works
Next Sprint: Core Functionality#
- Refine kidlisp() function signature and behavior
- Add proper error handling and visual feedback
- Implement buffer caching for performance
- Test complex kidlisp programs and graphics
- Validate memory management and cleanup
- Performance profiling and optimization
Future Sprints: Production Integration#
- Integrate kidlisp() into common API (disk.mjs)
- Add to $paintApiUnwrapped for all pieces
- Documentation and examples
- Integration testing across multiple pieces
- Performance benchmarks and optimization
Implementation Notes#
Phase Status#
- Phase 1: Basic Prototype - ✅ IN PROGRESS
- Phase 2: API Integration - ⏳ PENDING
- Phase 3: Production Implementation - ⏳ PLANNED
Current Prototype: kidlisp-in-js.mjs#
Created a test piece that:
- Imports KidLisp class from ../lib/kidlisp.mjs
- Initializes kidlisp instance in boot()
- Tests buffer creation with kidlisp evaluation
- Implements prototype kidlispBasic() function
- Includes error handling and visual feedback
Ready to test in browser and iterate on the implementation!
Future Enhancements#
- Interactive KidLisp: Mouse/touch event forwarding to kidlisp buffers
- 3D KidLisp: Integration with form system for 3D graphics
- Network KidLisp: Remote kidlisp code execution and sharing
- KidLisp Compiler: AOT compilation for performance-critical applications
- Visual KidLisp Editor: In-browser code editor with live preview
This integration would provide a powerful way to embed dynamic, programmable graphics within aesthetic computer pieces while maintaining isolation and performance.