Supported public APIs for publishing creative work and reading public Aesthetic Computer data
Model Context Protocol server for compatible assistants to create, validate, and publish Aesthetic Computer pieces
package: @aesthetic.computer/mcp
install: npx @aesthetic.computer/mcp
publish_piece — Publish a JavaScript piece to aesthetic.computer
input: {"source":"string","name":"string (optional)"}
output: {"code":"string","url":"string","cached":"boolean"}
publish_kidlisp — Publish KidLisp code to aesthetic.computer
input: {"source":"string"}
output: {"code":"string","url":"string","cached":"boolean"}
publish_clock — Publish a clock melody to aesthetic.computer
input: {"source":"string"}
output: {"code":"string","url":"string","cached":"boolean"}
get_api_info — Fetch the full API documentation
input: {}
output: API documentation object
preview_kidlisp — Validate KidLisp syntax without publishing
input: {"source":"string"}
output: {"valid":"boolean","errors":"string[]","warnings":"string[]","stats":"object"}
aesthetic-computer://piece-template — Starter template for a new aesthetic.computer piece with all lifecycle functions
aesthetic-computer://kidlisp-reference — Quick reference guide for KidLisp syntax and common functions
aesthetic-computer://piece-examples — Examples drawn from popular published pieces
create-piece — Guided prompt for creating an aesthetic.computer piece
args: name (required), description (required)
create-kidlisp — Guided prompt for creating a KidLisp piece
args: description (required)
{
"mcpServers": {
"aesthetic-computer": {
"command": "npx",
"args": ["-y", "@aesthetic.computer/mcp"],
"env": {
"AC_TOKEN": "optional-bearer-token"
}
}
}
}
{
"mcpServers": {
"aesthetic-computer": {
"command": "npx",
"args": ["-y", "@aesthetic.computer/mcp"]
}
}
}
{
"mcpServers": {
"aesthetic-computer": {
"command": "npx",
"args": ["-y", "@aesthetic.computer/mcp"]
}
}
}
https://aesthetic.computer/api/store-kidlisp
Publish KidLisp code anonymously and get a short URL for sharing
Authentication: Optional (Bearer token for authenticated users)
{
"source": {
"type": "string",
"required": true,
"description": "KidLisp source code (max 50,000 characters)",
"example": "(wipe blue)\n(ink red)\n(box 10 10 50 50)"
}
}
{
"code": {
"type": "string",
"description": "Short code for accessing the piece (e.g. 'abc123')"
},
"cached": {
"type": "boolean",
"description": "True if code already existed (deduplication)"
}
}
Create a simple animated piece with KidLisp
curl -X POST https://aesthetic.computer/api/store-kidlisp \
-H "Content-Type: application/json" \
-d '{
"source": "(wipe blue)\n(ink yellow)\n(circle (/ w 2) (/ h 2) 100)"
}'
const response = await fetch("https://aesthetic.computer/api/store-kidlisp", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
source: "(wipe blue)\n(ink yellow)\n(circle (/ w 2) (/ h 2) 100)"
})
});
const { code, cached } = await response.json();
console.log(`View at: https://aesthetic.computer/${code}`);
import requests
response = requests.post(
"https://aesthetic.computer/api/store-kidlisp",
json={
"source": "(wipe blue)\n(ink yellow)\n(circle (/ w 2) (/ h 2) 100)"
}
)
data = response.json()
print(f"View at: https://aesthetic.computer/{data['code']}")
{
"code": "xyz789",
"cached": false
}
https://aesthetic.computer/api/store-clock
Publish a clock melody string and get a pronounceable short code
Authentication: Optional (Bearer token for authenticated users)
{
"source": {
"type": "string",
"required": true,
"description": "Clock melody string (max 10,000 characters)",
"example": "c4 d4 e4 f4 g4"
},
"melody": {
"type": "string",
"required": false,
"description": "Legacy field name (use 'source' instead)"
}
}
{
"code": {
"type": "string",
"description": "Pronounceable short code (e.g. 'bako', 'milu')"
},
"cached": {
"type": "boolean",
"description": "True if melody already existed (deduplication)"
}
}
Store a musical sequence for the clock piece
curl -X POST https://aesthetic.computer/api/store-clock \
-H "Content-Type: application/json" \
-d '{
"source": "c4 e4 g4 c5 g4 e4 c4"
}'
const response = await fetch("https://aesthetic.computer/api/store-clock", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
source: "c4 e4 g4 c5 g4 e4 c4"
})
});
const { code, cached } = await response.json();
console.log(`Listen at: https://aesthetic.computer/clock~${code}`);
import requests
response = requests.post(
"https://aesthetic.computer/api/store-clock",
json={
"source": "c4 e4 g4 c5 g4 e4 c4"
}
)
data = response.json()
print(f"Listen at: https://aesthetic.computer/clock~{data['code']}")
{
"code": "bako",
"cached": false
}
https://aesthetic.computer/api/chat-messages
Read recent messages from a chat channel. `system` backs the main `/chat` piece; `clock` backs `laer-klokken` (r8Dio). Results are chronological (oldest → newest) within each page. Paginate further back with `before`.
Authentication: None (public read)
instance · stringsystem. Values: system, clock, all.limit · number50.before · stringsearch · stringq · stringfrom · string{
"instance": {
"type": "string",
"description": "Echoes the queried channel."
},
"search": {
"type": "string",
"description": "Echoes the search term when supplied; omitted otherwise."
},
"count": {
"type": "number",
"description": "Number of messages in this page."
},
"messages": {
"type": "array",
"description": "Chronological (oldest → newest).",
"items": {
"id": {
"type": "string",
"description": "Mongo ObjectId string."
},
"from": {
"type": "string",
"description": "`@handle` of the sender, or `anon` if unresolved."
},
"text": {
"type": "string",
"description": "Message body as posted."
},
"when": {
"type": "string",
"description": "ISO timestamp."
},
"instance": {
"type": "string",
"description": "Source channel for this message."
},
"hearts": {
"type": "number",
"description": "Heart-reaction count from the shared `hearts` collection."
}
}
},
"nextBefore": {
"type": "string",
"description": "ISO timestamp of the oldest message in this page — pass as `before=` to fetch the previous page. `null` when the page is empty."
}
}
Default channel is `system`.
curl "https://aesthetic.computer/api/chat-messages"
const res = await fetch("https://aesthetic.computer/api/chat-messages");
const { messages } = await res.json();
for (const m of messages) console.log(m.when, m.from, m.text);
import requests
data = requests.get("https://aesthetic.computer/api/chat-messages").json()
for m in data["messages"]:
print(m["when"], m["from"], m["text"])
curl "https://aesthetic.computer/api/chat-messages?from=%40jeffrey&limit=1"
const res = await fetch("https://aesthetic.computer/api/chat-messages?from=%40jeffrey&limit=1");
const { messages } = await res.json();
console.log(messages.at(-1));
import requests
data = requests.get("https://aesthetic.computer/api/chat-messages",
params={"from": "@jeffrey", "limit": 1}).json()
print(data["messages"][-1] if data["messages"] else None)
curl "https://aesthetic.computer/api/chat-messages?instance=clock&limit=100"
const res = await fetch(
"https://aesthetic.computer/api/chat-messages?instance=clock&limit=100"
);
const { messages, nextBefore } = await res.json();
console.log(messages.length, "messages; older page cursor:", nextBefore);
import requests
data = requests.get(
"https://aesthetic.computer/api/chat-messages",
params={"instance": "clock", "limit": 100},
).json()
print(len(data["messages"]), "messages; older page cursor:", data["nextBefore"])
Use `nextBefore` from each response to walk back in time.
curl "https://aesthetic.computer/api/chat-messages?instance=clock&limit=100&before=2026-04-20T00%3A00%3A00Z"
async function* allClockMessages() {
let before;
while (true) {
const url = new URL("https://aesthetic.computer/api/chat-messages");
url.searchParams.set("instance", "clock");
url.searchParams.set("limit", "100");
if (before) url.searchParams.set("before", before);
const res = await fetch(url);
const page = await res.json();
if (page.count === 0) break;
yield page.messages;
before = page.nextBefore;
}
}
import requests
def all_clock_messages():
before = None
while True:
params = {"instance": "clock", "limit": 100}
if before:
params["before"] = before
page = requests.get("https://aesthetic.computer/api/chat-messages",
params=params).json()
if page["count"] == 0:
break
yield page["messages"]
before = page["nextBefore"]
curl "https://aesthetic.computer/api/chat-messages?instance=all&search=music&limit=25"
const url = new URL("https://aesthetic.computer/api/chat-messages");
url.search = new URLSearchParams({ instance: "all", search: "music", limit: "25" });
const { messages } = await fetch(url).then((res) => res.json());
console.log(messages);
import requests
data = requests.get(
"https://aesthetic.computer/api/chat-messages",
params={"instance": "all", "search": "music", "limit": 25},
).json()
print(data["messages"])
https://aesthetic.computer/api/store-piece
Publish a JavaScript piece (.mjs) anonymously by providing source code as a string. No S3 credentials needed - the server handles storage automatically.
Authentication: Optional (Bearer token for authenticated users)
{
"source": {
"type": "string",
"required": true,
"description": "JavaScript piece source code (max 100,000 characters). Must contain a supported lifecycle export or a default export.",
"example": "export function boot($) { $.wipe('blue'); }\nexport function paint($) { $.ink('red'); $.box(10, 10, 50, 50); }"
},
"name": {
"type": "string",
"required": false,
"description": "Optional name for the piece (used for code generation)"
}
}
{
"code": {
"type": "string",
"description": "Short code for accessing the piece (e.g. 'drift', 'wave')"
},
"cached": {
"type": "boolean",
"description": "True if code already existed (deduplication)"
},
"url": {
"type": "string",
"description": "Full URL to view the piece"
}
}
Create a piece with basic drawing
curl -X POST https://aesthetic.computer/api/store-piece \
-H "Content-Type: application/json" \
-d '{
"source": "export function boot($) {\n $.wipe("blue");\n}\n\nexport function paint($) {\n $.ink("red");\n $.box(10, 10, 50, 50);\n}",
"name": "red-box"
}'
const source = `export function boot($) {
$.wipe("blue");
}
export function paint($) {
$.ink("red");
$.box(10, 10, 50, 50);
}`;
const response = await fetch("https://aesthetic.computer/api/store-piece", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
source,
name: "red-box"
})
});
const { code, url, cached } = await response.json();
console.log(`View at: ${url}`);
import requests
source = """export function boot($) {
$.wipe("blue");
}
export function paint($) {
$.ink("red");
$.box(10, 10, 50, 50);
}"""
response = requests.post(
"https://aesthetic.computer/api/store-piece",
json={
"source": source,
"name": "red-box"
}
)
data = response.json()
print(f"View at: {data['url']}")
{
"code": "red-box",
"cached": false,
"url": "https://aesthetic.computer/red-box"
}
Create a piece with user interaction
curl -X POST https://aesthetic.computer/api/store-piece \
-H "Content-Type: application/json" \
-d '{
"source": "let x = 0;\n\nexport function boot($) {\n x = $.screen.width / 2;\n}\n\nexport function paint($) {\n $.wipe("black");\n $.ink("yellow");\n $.circle(x, $.screen.height / 2, 20);\n}\n\nexport function act($) {\n if ($.event.is("touch")) x = $.event.x;\n}"
}'
const source = `let x = 0;
export function boot($) {
x = $.screen.width / 2;
}
export function paint($) {
$.wipe("black");
$.ink("yellow");
$.circle(x, $.screen.height / 2, 20);
}
export function act($) {
if ($.event.is("touch")) x = $.event.x;
}`;
const response = await fetch("https://aesthetic.computer/api/store-piece", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ source })
});
const { code, url } = await response.json();
console.log(`View at: ${url}`);
import requests
source = """let x = 0;
export function boot($) {
x = $.screen.width / 2;
}
export function paint($) {
$.wipe("black");
$.ink("yellow");
$.circle(x, $.screen.height / 2, 20);
}
export function act($) {
if ($.event.is("touch")) x = $.event.x;
}"""
response = requests.post(
"https://aesthetic.computer/api/store-piece",
json={"source": source}
)
data = response.json()
print(f"View at: {data['url']}")
{
"code": "touch",
"cached": false,
"url": "https://aesthetic.computer/touch"
}
https://aesthetic.computer/api/track-media
Register an uploaded painting, piece, or tape and receive a short code. The file must already exist in Aesthetic Computer storage.
Authentication: Optional (Bearer token for authenticated users)
{
"slug": {
"type": "string",
"required": true,
"description": "S3/storage path where the file was uploaded"
},
"ext": {
"type": "string",
"required": true,
"enum": [
"png",
"mjs",
"lisp",
"lua",
"zip",
"mp4"
],
"description": "Media type: PNG painting; MJS, Lisp, or Lua piece; ZIP web tape; or finished MP4 native tape"
},
"metadata": {
"type": "object",
"required": false,
"description": "Optional metadata (for tapes: totalDuration in seconds, max 30s)",
"properties": {
"totalDuration": {
"type": "number",
"description": "Duration in seconds (tapes only, max 30)"
}
}
}
}
{
"code": {
"type": "string",
"description": "Short code for accessing the media"
}
}
After uploading .mjs file to S3, register it in the database
curl -X POST https://aesthetic.computer/api/track-media \
-H "Content-Type: application/json" \
-d '{
"slug": "2026/02/12/my-piece.mjs",
"ext": "mjs"
}'
// Step 1: Upload your .mjs file to S3 (requires credentials)
// Step 2: Register the uploaded file
const response = await fetch("https://aesthetic.computer/api/track-media", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
slug: "2026/02/12/my-piece.mjs",
ext: "mjs"
})
});
const { code } = await response.json();
console.log(`View at: https://aesthetic.computer/${code}`);
import requests
# After uploading your .mjs file to S3
response = requests.post(
"https://aesthetic.computer/api/track-media",
json={
"slug": "2026/02/12/my-piece.mjs",
"ext": "mjs"
}
)
data = response.json()
print(f"View at: https://aesthetic.computer/{data['code']}")
{
"code": "abc456"
}
Register a painting image after uploading to S3
curl -X POST https://aesthetic.computer/api/track-media \
-H "Content-Type: application/json" \
-d '{
"slug": "2026/02/12/my-painting.png",
"ext": "png"
}'
const response = await fetch("https://aesthetic.computer/api/track-media", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
slug: "2026/02/12/my-painting.png",
ext: "png"
})
});
const { code } = await response.json();
console.log(`View at: https://aesthetic.computer/${code}`);
import requests
response = requests.post(
"https://aesthetic.computer/api/track-media",
json={
"slug": "2026/02/12/my-painting.png",
"ext": "png"
}
)
data = response.json()
print(f"View at: https://aesthetic.computer/{data['code']}")
{
"code": "def789"
}
Register a recording after uploading ZIP to S3
curl -X POST https://aesthetic.computer/api/track-media \
-H "Content-Type: application/json" \
-d '{
"slug": "2026/02/12/my-recording.zip",
"ext": "zip",
"metadata": {
"totalDuration": 15.5
}
}'
const response = await fetch("https://aesthetic.computer/api/track-media", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
slug: "2026/02/12/my-recording.zip",
ext: "zip",
metadata: {
totalDuration: 15.5 // seconds (max 30)
}
})
});
const { code } = await response.json();
console.log(`Watch at: https://aesthetic.computer/${code}`);
import requests
response = requests.post(
"https://aesthetic.computer/api/track-media",
json={
"slug": "2026/02/12/my-recording.zip",
"ext": "zip",
"metadata": {
"totalDuration": 15.5 # seconds (max 30)
}
}
)
data = response.json()
print(f"Watch at: https://aesthetic.computer/{data['code']}")
{
"code": "ghi012"
}