# Glide — agent guide Glide is a browser video editor at https://glide.29court.com/ Tagline: "Video editing without keyframes. Just move things." You (an AI agent) can drive Glide directly. There is no server API and no account: the editor runs entirely in the page, and it exposes a JavaScript API, `window.GlideAgent`, in the page at https://glide.29court.com/. Open that page in a browser (or any environment that runs the page's JavaScript), wait for `window.GlideAgent` to exist, and call its methods. Every method acts on the same project the human sees on screen, autosaves to the browser's localStorage, and is undoable with the editor's undo. Machine-readable manifest: https://glide.29court.com/agent.json This guide as plain text: https://glide.29court.com/agent ## The model in 30 seconds - Stage: 1280 x 720 logical pixels. Object positions are CENTER coordinates (x: 0..1280, y: 0..720). - A project has a name, a duration in seconds (2..1800, default 8), objects (shapes, text, images) and video clips on a magnetic timeline. - Objects do not have animation tracks you edit by hand. Each object carries keyframes: { t, x, y, scale, rotation, opacity, easing }. Writing a keyframe at time t with a transform is the whole animation system: Glide interpolates between keyframes with the easing named on the earlier keyframe. Easings: "linear", "easeIn", "easeOut", "easeInOut". - Object fields: id, type ("rect" | "ellipse" | "text" | "image"), label, w, h (base size in px, multiplied by keyframe scale), fill (hex color, shapes), text + fontSize + color (text objects), src (data URL, images), keys (keyframes, sorted by t). - Video clips stream from a local File (blob URL). They are never uploaded and never read into memory. After a page reload a clip keeps its trims and keyframes but must be relinked by handing the same File to addVideoFromFile again. ## Quick start (paste into the page's JS context) ```js const G = window.GlideAgent; G.newProject({ name: "Agent demo", duration: 6 }); const title = G.addObject("text", { text: "Hello from an agent", x: 640, y: 360, fontSize: 72 }); G.setKeyframe(title.id, 0, { x: 140, y: 360, opacity: 0 }); G.setKeyframe(title.id, 1.5, { x: 640, y: 360, opacity: 100 }); G.setKeyframe(title.id, 5, { x: 640, y: 300, scale: 1.25, easing: "easeOut" }); console.log(G.sampleAt(title.id, 0.75)); // interpolated transform mid-flight console.log(G.getState()); // full project, JSON-safe const out = await G.exportMP4(); // { filename, bytes, type, blob, url, frames, audio } ``` ## window.GlideAgent — methods Reading state - `G.version` — API version string ("1.0.0"). - `G.capabilities()` — stage size, object types, easings, export formats. - `await G.ready()` — capabilities plus live checks (e.g. WebCodecs MP4 encoding support in this browser). - `G.getState()` — the whole project as JSON-safe data: { v, name, duration, objects, clips, playhead, playing, selectedId }. - `G.getObject(id)` — one object or clip by id, or null. - `G.getKeyframes(id)` — the object's keyframes, sorted by t. - `G.sampleAt(id, t)` — the interpolated transform at time t: { t, x, y, scale, rotation, opacity, easing } or null. - `G.getPlayhead()` — current playhead time in seconds. Project - `G.newProject({ name?, duration? })` — replaces the current project with an empty one. No confirmation prompt (that is the human button's job); the previous project remains reachable via the editor's undo. Returns the new state. - `G.loadProject(projectOrJson)` — loads a project in getState() format (objects + clips). Media cannot travel in JSON: clips load unlinked and need their File again via addVideoFromFile. Returns the new state. - `G.setName(name)`, `G.setDuration(seconds)` — clamped to 2..1800. Objects - `G.addObject(type, props?)` — type: "rect" | "ellipse" | "text" | "image". props may include x, y (position of the first keyframe), label, text, fill, color, fontSize, w, h, and src (a data URL, image type only). Adds one keyframe at t=0. Returns the created object. - `G.updateObject(id, props)` — changes label, text, fill, color, fontSize, w, h (and src for images) without touching keyframes. Returns the updated object. - `G.setKeyframe(id, t, transform)` — THE animation call. Writes (or updates, within 1/30s) the keyframe at time t. transform may include any of x, y, scale, rotation (degrees), opacity (0..100), easing; omitted fields keep the value the object has at time t. Returns the keyframe written. - `G.deleteKeyframe(id, t)` — removes a keyframe (an object always keeps at least one). Returns true if one was removed. - `G.deleteObject(id)` — deletes an object or a clip. Returns true/false. - `G.select(idOrNull)` — selects an object in the UI. Playback - `G.setPlayhead(t)` — scrubs (clamped to 0..duration). Returns the time. - `G.play()`, `G.pause()`, `G.stop()` (pause + back to 0). Video clips - `await G.addVideoFromFile(file)` — pass a File or Blob with a video MIME type, exactly what a file input or drag-and-drop would give the editor. Appends the clip to the magnetic timeline (or relinks an unlinked clip with the same name+size+modified fingerprint). Returns the clip summaries. Playback position, trims and speed live on the clip: { start, clipDur, in, out, speed, fileName } — read them with getState(); trims are edited in the UI or via loadProject. - `G.getClips()` — clip summaries (no blob URLs, they are session-only). Export - `await G.exportMP4(opts?)` — offline WebCodecs render (fast, includes clip audio) in browsers that support it. Resolves to { filename, bytes, type, blob, url, frames, audio, seconds } where `blob` is the MP4 file and `url` is an object URL for it; the editor also offers its own download button when the render finishes. Throws if this browser has no WebCodecs encoder — then use exportGIF, or G.openExportPanel() and let the human take the real-time fallback render. - `await G.exportGIF(opts?)` — { fps (5..30, default 15), width (default 640), dither (default true) }. Same result shape; GIFs loop and carry no audio. - `G.openExportPanel()` — opens the human export dialog. - `G.lastExportStats()` — frame-source statistics of the last render, or null. - `G.help()` — { version, doc, manifest, methods } for discovery. ## Starter prompt (copy into any AI chat) "You are helping me use Glide, the video editor at https://glide.29court.com/. Glide has an agent API: first read https://glide.29court.com/agent for the full guide (manifest at https://glide.29court.com/agent.json), then open the app page in a browser and drive it through window.GlideAgent — add objects with addObject, animate by writing keyframes with setKeyframe, read state with getState/sampleAt, and export with exportMP4/exportGIF, which resolve to the rendered file. Video files are never uploaded; clips stream from a local File and need relinking after a reload." ## Honest limits - No server side exists: nothing here works without the page open in a browser-like environment, and there is no webhook or headless render farm. Export renders on the visitor's machine. - MP4 export needs WebCodecs (Chrome/Edge and recent Safari). GIF export works anywhere the editor runs. - Video and audio files are never uploaded to 29Court; an agent cannot conjure a user's local file — it can only use a File the page has been given (file picker, drag-and-drop, or a blob the agent itself fetched into the page). - Share links (?p=) refuse projects with images or video clips; agents should move projects as getState() JSON instead. Glide runs on 29Court code only: no third-party libraries.