Agent recipes
Copy complete agent workflows for discovery, SVG generation, tactile backgrounds, Design Lab sequences, safe source edits, brand setup and checked exports.
Each recipe includes discovery and a completion check. Set BASE_URL to the Glyphfield origin, which is http://localhost:3012 for a local development server.
Discover before generating
BASE_URL=http://localhost:3012
curl -fsS "$BASE_URL/api/agent" | jq '{version, schemaVersion, resources, interfaces}'
curl -fsS "$BASE_URL/api/labs" | jq '.plugins[] | {id, name, capabilities}'
curl -fsS "$BASE_URL/api/materials" | jq '{count, defaults, engines, sharedBy}'
curl -fsS "$BASE_URL/api/identities" | jq '.identities[] | {id, name}'
curl -fsS "$BASE_URL/api/generate" | jq '{schemaVersion, kinds}'Most discovery routes allow caching for five minutes (Cache-Control: public, max-age=300). Read GET /api/generate again before a request if the cached copy may be older.
Generate and save a raw SVG
curl -fsS -X POST "$BASE_URL/api/generate" \
-H 'Content-Type: application/json' \
-d '{
"kind": "template",
"template": "slides",
"slideLayout": "statement",
"texture": "dark",
"title": "One system. Every surface.",
"identity": { "preset": "gt" },
"output": "raw"
}' \
-o one-system.svg
test -s one-system.svgThe task is complete when the file exists and is not empty. A 200 status alone does not prove that.
Generate a tactile background
curl -fsS -X POST "$BASE_URL/api/generate" \
-H 'Content-Type: application/json' \
-d '{
"kind": "background",
"identity": { "preset": "gt" },
"settings": {
"width": 1600,
"height": 900,
"style": "grain-gradient",
"gradient": "mesh",
"colorA": "#F5F5F2",
"colorB": "#181818",
"colorC": "#7058FF",
"surfaceMaterial": "embossed-paper",
"surfaceDepth": 36,
"surfaceRoughness": 72,
"surfaceScale": 44,
"grain": 12
},
"output": "raw"
}' \
-o tactile-background.svgCreate and render a Design Lab sequence
Design Lab is the Studio's layered composition tool. First generate the composition document:
const baseUrl = 'http://localhost:3012';
const response = await fetch(`${baseUrl}/api/generate`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
kind: 'design-sequence',
identity: { preset: 'gt' },
ratio: 'wide',
backgroundColor: '#111216',
includeBrandMark: true,
texts: [
{ value: 'Open source', weight: 500 },
{ value: 'Every language. One source.', weight: 400 },
],
shader: {
materialId: 'paper-gem-smoke',
shaderSize: 0.8,
opacity: 1,
},
effect: {
kind: 'bayer',
opacity: 0.72,
foreground: '#F5F5F2',
background: '#111216',
},
sequence: { cutCount: 10, finalHoldMs: 5000, pace: 'accelerating' },
export: { width: 1920, fps: 30, quality: 'best', gifLoop: 'seamless' },
}),
});
if (!response.ok) throw new Error(await response.text());
const generated = await response.json();Then open /studio?tool=material in the browser and run:
function readyStudio() {
return new Promise((resolve) => {
try {
if (window.glyphfield?.studio) return resolve(window.glyphfield.studio);
} catch {
// The tool is still loading. Wait for the ready event.
}
window.addEventListener('glyphfield:studio-api-ready', () => resolve(window.glyphfield.studio), { once: true });
});
}
const studio = await readyStudio();
if (studio.activeTool() !== 'material') throw new Error('Open /studio?tool=material first.');
await studio.applySource(generated.document);
const artifact = await studio.invoke('design.export', {
format: 'mp4',
mode: 'shader-sequence',
download: true,
});
if (!(artifact.blob instanceof Blob) || artifact.blob.size === 0) {
throw new Error('Design Lab returned an empty export.');
}The Browser API covers only the active tool's workspace, so it cannot click the Studio sidebar. To change tools, load /studio?tool=<tool id>&project=<project id>, wait for the API again and read window.glyphfield.studio again.
Edit an existing composition safely
const studio = window.glyphfield.studio;
const source = JSON.parse(studio.readSource());
const firstText = Object.values(source.elements)
.find((element) => element.kind === 'text');
if (!firstText) throw new Error('No text layer exists.');
firstText.content = 'Updated by an agent';
firstText.style.opacity = 0.88;
await studio.applySource(source);
const applied = JSON.parse(studio.readSource());
if (applied.elements[firstText.id].content !== 'Updated by an agent') {
throw new Error('The source did not round-trip.');
}Keep the unknown fields of the document you read. Edit that document in place instead of rebuilding the canvas envelope.
Set up a brand and export its tokens
Validate without a browser, then apply in the Studio. Brand setup with an agent describes the full workflow.
curl -fsS "$BASE_URL/api/brand/validate" | jq '{schemaVersion, mergeRules, logoSlots: [.logoSlots[].id]}'
curl -fsS -X POST "$BASE_URL/api/brand/validate" \
-H 'Content-Type: application/json' \
-d '{ "mode": "patch", "identity": { "tagline": "Weather you can build on.", "colors": [{ "id": "emphasis", "hex": "#1F6FEB" }] } }' \
| jq '{ok, issues}'// On /studio?tool=identity&project=<id>
const studio = window.glyphfield.studio;
const patch = { tagline: 'Weather you can build on.', colors: [{ id: 'emphasis', hex: '#1F6FEB' }] };
await studio.invoke('identity.apply', { identity: patch });
const report = await studio.invoke('identity.audit');
await studio.invoke('identity.save');
const tokens = await studio.invoke('identity.export.kit', { format: 'tailwind' });Use a local file
In Design Lab, the file input with the accessible label Choose logos for the canvas adds each file as a logo layer:
// fileHandle comes from a file picker the user approved.
const picked = await fileHandle.getFile();
const file = new File([picked], 'mark.svg', { type: 'image/svg+xml' });
window.glyphfield.studio.set('Choose logos for the canvas', file);Create a File only from a source the user authorized. Wait until the new layer appears in the source or on the canvas before exporting.
Export every supported format
for (const format of ['png', 'jpg', 'gif', 'mp4']) {
const artifact = await window.glyphfield.studio.invoke('design.export', {
format,
download: true,
});
console.log(format, artifact.fileName, artifact.blob.size);
}Do not run these exports in parallel. They share live canvases and browser encoders. Export one format, check it, then start the next.
Failure handling
- For an HTTP failure, read
error.code,error.fieldanderror.message. - Do not retry unchanged input after a validation error.
- For a Browser API failure, call
describe()andcontrols()again, because the active tool may have changed. - If the browser cannot encode MP4, report the failure and keep the source document. Do not substitute GIF.
- If WebGL is unavailable, use an HTTP
backgroundSVG only when it still meets the request.
See API errors and limits for every error code.
Tactile backgrounds
Generate deterministic SVG backgrounds with gradients, grain, dither, patterns and physical surface textures from a brand identity through the HTTP API.
Identities and custom assets
Choose a built-in brand identity for a generation request, override its name, colors and logo, and embed local images as base64 data URLs.