Open SlideClark · Raw markdown

SlideClark: guide for AI assistants

Version 4.0.0 · canonical copy: https://slideclark.com/ai-guide.md · also inside the app: SlideClark.guide()

SlideClark (called Pitchcraft until October 2026) is a browser presentation studio at https://slideclark.com/app. A deck is plain JSON. You write or edit that JSON, the user opens it in SlideClark, edits it visually and presents it. There is no server: everything is validated and rendered in the user's browser. This guide is generated from the same specs the app runs on, so it is always accurate for version 4.0.0.

Plain-text routes. If your tool rewrites URLs, equals signs or long output, fetch this guide as plain markdown (https://slideclark.com/ai-guide.md) or together with the schema in one file (https://slideclark.com/llms-full.txt). In the page, SlideClark.guide(9) returns one section at a time.

Three ways to build a slide, and you can mix them in one deck.

  1. Template layout: fill in fields such as headline and items. Fast and consistent. Best for plain text, lists and simple charts (section 4).
  2. Blank layout with objects: text, shapes, images and icons placed at x/y/w/h (section 6).
  3. Custom slide: your own HTML, CSS and JavaScript (section 9). This is the full-capability route. It can do any layout, brand styling, diagram, animation or canvas. When the look of a slide matters, write a custom slide.

1. Which job are you doing?

  1. You are a chat window (ChatGPT, Claude, Gemini, Copilot, etc.) and you cannot touch the user's open SlideClark. Produce a deck file (section 2) for the user to import. Follow sections 3 to 10.
  2. You are an AI inside the user's browser (a browser agent or assistant with the SlideClark tab open). Edit the live deck with the SlideClark API (section 11). Read sections 3 to 10 first so your edits are valid.

2. Delivering a deck (chat windows)

3. Deck format

{ "format": "slideclark", "version": 3,
  "meta": { "name": "Deck title", "theme": "studio", "numbers": false, "transition": "fade" },
  "slides": [ { "id": "s1", "layout": "title", "...": "layout fields" } ] }

Themes

4. Layouts

Every slide has exactly one layout. Pick the layout whose fields match your content. Fields not listed for a layout are ignored.

Free-form

Story

Data

Structure

Visual

Custom

Icon names (for icon fields and icon objects): bolt, layers, sparkles, chart, lock, globe, wand, cursor, clock, check, users, user, target, rocket, shield, cpu, box, link, star, type, image, table, pie, terminal, flag, presentation, heart, key, puzzle, git, compass, mail, feather, gauge, edit, tag, map, file, code, download, upload, eye, palette, grid, play

Text markup (every text field, including text in objects)

bold, italic, ==accent highlight== and ` code . Use ==highlight==` on one or two words of a headline. Line breaks inside free-form text objects are kept; generated fields are single-line.

5. Choosing between template, free-form and custom

Decide per slide. The three routes mix freely, so a deck can be mostly templates with a few custom slides, or custom all the way through.

If the user said nothing about style, a good default is templates for the plain slides and custom slides for the two or three that carry the story.

6. Free-form objects

objects is an array, drawn in order: later items are on top. The stage is 1280 wide, 720 tall, origin top-left, all units are pixels, rot is degrees clockwise. Maximum 120 objects per slide.

Common fields: id (unique on the slide; generated if you omit it), type, x, y, w, h (optional for text: it grows with its content), rot, opacity (0 to 1), shadow (true), name (label shown in the editor's layers list), flipH / flipV (mirror), locked (the editor will not move or edit it), group (objects sharing a group id select and move together), link (https://, mailto: or #slide-id, followed when presenting), alt (alternative text for shapes, icons and lines).

A slide can also be hidden from the presentation with "hidden": true (it stays in the editor and is skipped when presenting and exporting to PDF).

typeextra fields
texttext, font, size (px), weight (100 to 900), italic, underline, caps (uppercase), align (left, center, right, justify), valign (top, middle, bottom; only when h is set), color, lh (line height multiple), ls (letter spacing in em)
shapeshape, fill, fill2 + gradAngle (a two-colour gradient), stroke, strokeW, dash (solid, dashed, dotted), radius (rect only), and all the text fields above for text inside the shape. Put a label in the shape's own text; do not lay a separate text object over it
linekind (straight, elbow for right-angle corners, curve), stroke, strokeW, dash, arrowStart / arrowEnd (none, triangle, stealth, open, dot, diamond), vert (elbow and curve leave vertically instead of horizontally), bend (0.05 to 0.95: where the middle run sits), from / to (glue an end to another object: "objectId:t", :r, :b or :l; the line follows when that object moves). The start is the top-left of the box and the end the bottom-right, unless flipH / flipV mirror it
imagesrc (https URL or data:image/...), alt (always write it), fit (cover, contain, fill), radius, stroke, strokeW
iconicon (name from the list in section 4), color

Shapes: rect (Rectangle), round (Rounded rectangle), ellipse (Ellipse), triangle (Triangle), diamond (Diamond), hexagon (Hexagon), star (Star), arrow (Right arrow), chevron (Chevron), arrowleft (Left arrow), arrowup (Up arrow), arrowdown (Down arrow), arrowboth (Left-right arrow), pentagon (Pentagon), octagon (Octagon), parallelogram (Parallelogram), trapezoid (Trapezoid), plus (Cross), callout (Speech bubble), donut (Ring), cylinder (Cylinder), heart (Heart), line (Line (old)), connector (Arrow line (old)). For a diagram, glue connectors to boxes with from / to rather than guessing coordinates: { "type": "line", "kind": "elbow", "from": "a:r", "to": "b:l", "arrowEnd": "triangle", "stroke": "var(--muted)", "strokeW": 3 }. Their x, y, w, h are recomputed from the glue.

Fonts (font): body (Theme body), display (Theme heading), inter (Inter), bricolage (Bricolage Grotesque), serif (Instrument Serif), syne (Syne), mono (JetBrains Mono), arial (Arial), georgia (Georgia), times (Times New Roman), verdana (Verdana), trebuchet (Trebuchet MS), courier (Courier New), dmsans (DM Sans), manrope (Manrope), plusjakartasans (Plus Jakarta Sans), spacegrotesk (Space Grotesk), outfit (Outfit), montserrat (Montserrat), worksans (Work Sans), sora (Sora), figtree (Figtree), urbanist (Urbanist), poppins (Poppins), raleway (Raleway), nunito (Nunito), lato (Lato), rubik (Rubik), archivo (Archivo), epilogue (Epilogue), ibmplexsans (IBM Plex Sans), josefinsans (Josefin Sans), quicksand (Quicksand), cabin (Cabin), playfairdisplay (Playfair Display), lora (Lora), fraunces (Fraunces), sourceserif4 (Source Serif 4), cormorantgaramond (Cormorant Garamond), librebaskerville (Libre Baskerville), dmserifdisplay (DM Serif Display), oswald (Oswald), anton (Anton), bebasneue (Bebas Neue), abrilfatface (Abril Fatface), pacifico (Pacifico), lobster (Lobster), caveat (Caveat), spacemono (Space Mono), ibmplexmono (IBM Plex Mono), firacode (Fira Code), inconsolata (Inconsolata). Any other plain family name (letters, digits, spaces and - . _ & +) also works but only renders if installed on the viewer's machine, so prefer the keys. They are all bundled and load on demand.

Colours (color, fill, stroke): hex (#1a1a2e), rgb()/rgba(), a plain colour name, or a theme token that follows the deck theme and the slide background. Prefer tokens so the slide survives a theme change: var(--fg) text, var(--muted) muted text, var(--shape) accent, var(--on-shape) on accent, var(--card) card, var(--slide-bg) background, #ffffff white, #000000 black, var(--c1) palette 1, var(--c2) palette 2, var(--c3) palette 3, var(--c4) palette 4, var(--c5) palette 5, var(--c6) palette 6.

Defaults when a field is omitted:

Rules for good free-form slides:

7. Tweaks: moving and restyling a template slide's own elements

Every editable text in a template slide has a path (headline, body, kicker, items.1.title) and every card or row has an item key (items.1). tweaks nudges or restyles them without leaving the layout:

"tweaks": { "headline": { "dx": 40, "dy": -20, "size": 96, "color": "var(--shape)" }, "items.1": { "dx": 0, "dy": 24 } }

dx and dy are pixel offsets. Text fields also accept font, size, weight, italic, underline, caps, align, color, lh, ls. Tweaks are optional: do not add them unless the user asks for a specific move or restyle.

8. Design rules

Writing style

Slides are read in seconds, so weak writing shows. Write natural, precise British English, the way a knowledgeable person with one specific point to make would write it. Aim for clarity and accuracy, not polish, enthusiasm or impact. Swapping banned words for synonyms is not enough: avoid the patterns underneath (artificial contrast, neat triads, manufactured punchiness, inflated abstraction, repeated summaries).

Titles and headings

Start and end

Words

Sentences and structure

Claims and tone

9. Custom layout (HTML, CSS, JavaScript)

{ "id": "s5", "layout": "custom", "headline": "short name", "custom": { "html": "...", "css": "...", "js": "...", "interactive": false } }

Text width: theme fonts are wide

Headline fonts differ a lot. The Contrast theme sets headlines in uppercase Syne ExtraBold, roughly twice the width of Editorial's serif. Do not assume a character is half its font size. Estimate with these averages (em per character, measured on mixed English text; multiply by the font size in px to get the width of one character):

themeheadline fontem per character, headlineem per character, body
studioBricolage Grotesque0.470.48
editorialInstrument Serif0.330.48
contrastSyne, UPPERCASE1.010.48
auroraBricolage Grotesque0.470.48
brutalSyne0.770.48

Characters per line is about box width / (font size x em). Example: a 900 px box at 64 px in Contrast fits about 900 / (64 x 1.01) = 13 characters per line; in Editorial it fits about 42. Size from the widest theme the deck might use, or measure: SlideClark.measureText("Quarterly results", { font: "display", size: 72, w: 900 }) returns the real width, height and line count in the current theme. Long words never wrap, so check the longest word.

Checking a custom slide

SlideClark.audit() cannot see inside a custom slide (the slide is a sandboxed iframe), so it returns checked: false for those. Use await SlideClark.auditAll(): it runs each custom slide in a hidden sandbox, waits for its js and fonts, and measures the rendered text. It reports text-off-slide, outside-safe-area, clipped (hidden by an overflow:hidden container), text-wider-than-box, text-overlap and script-error. It checks text only: it cannot judge colour contrast, images or canvas drawings, so still look at a screenshot when you can.

Writing a custom slide without a file (browser AIs)

SlideClark.addCustomSlide({
  html: '<div class="wrap"><h1>Hello</h1><canvas id="c" width="600" height="300"></canvas></div>',
  css: '.wrap{position:absolute;inset:0;padding:90px} h1{font:800 96px var(--font-d);margin:0}',
  js: 'const c=document.getElementById("c").getContext("2d"); c.fillStyle="#5b4bff"; c.fillRect(0,0,300,150);',
  interactive: false
}, undefined, "Hello");                       // returns the slide index
SlideClark.setCustom(2, { css: "h1{color:var(--acc)}" });   // patch one field later
SlideClark.setMeta({ css: "@font-face{...} .logo{...}" });   // brand CSS shared by every custom slide

The machine-readable description of all of this is the JSON Schema: SlideClark.schema(), or https://slideclark.com/slideclark.schema.json.

10. Worked example

This deck is validated against the importer when the guide is built.

{
  "format": "slideclark",
  "version": 3,
  "meta": {
    "name": "Quarterly review",
    "theme": "studio",
    "numbers": false,
    "transition": "fade"
  },
  "slides": [
    {
      "id": "s1",
      "layout": "title",
      "kicker": "Q3 review",
      "headline": "Growth, **on purpose**",
      "body": "What worked, what did not, and what we do next",
      "notes": "Open with the headline number."
    },
    {
      "id": "s2",
      "layout": "blank",
      "notes": "One big number, placed by hand.",
      "objects": [
        {
          "id": "label",
          "type": "text",
          "x": 80,
          "y": 90,
          "w": 700,
          "text": "Revenue growth",
          "size": 28,
          "weight": 700,
          "caps": true,
          "ls": 0.08,
          "color": "var(--shape)"
        },
        {
          "id": "big",
          "type": "text",
          "x": 80,
          "y": 150,
          "w": 720,
          "text": "**42%**",
          "size": 220,
          "weight": 800,
          "font": "display",
          "lh": 1
        },
        {
          "id": "card",
          "type": "shape",
          "shape": "round",
          "x": 820,
          "y": 150,
          "w": 380,
          "h": 300,
          "fill": "var(--shape)",
          "text": "Sample data: replace with your number",
          "size": 30,
          "color": "var(--on-shape)"
        },
        {
          "id": "rule",
          "type": "shape",
          "shape": "line",
          "x": 80,
          "y": 520,
          "w": 1120,
          "h": 14,
          "stroke": "var(--muted)",
          "strokeW": 3
        },
        {
          "id": "note",
          "type": "text",
          "x": 80,
          "y": 560,
          "w": 1000,
          "text": "Quarter on quarter, all regions. Source: [NEEDS EVIDENCE]",
          "size": 26,
          "color": "var(--muted)"
        }
      ]
    },
    {
      "id": "s3",
      "layout": "closing",
      "kicker": "Next",
      "headline": "Three bets for Q4",
      "body": "We will know by December.",
      "tweaks": {
        "headline": {
          "dy": -10
        }
      }
    }
  ]
}

11. Editing the live deck in the browser (browser AIs)

When SlideClark is open in the tab you control, use the global SlideClark object (for example through the page's JavaScript console). The old name Pitchcraft is kept as an alias of the same object, so a script written for it still runs. There is no separate "AI import" button because you do not need one: SlideClark.importText(json) loads a whole deck, SlideClark.addCustomSlide(...) adds an HTML/CSS/JS slide, and SlideClark.schema() / SlideClark.manifest() describe everything. (Humans use the AI button, then Import.) Every call is validated and undoable (the user can press Ctrl+Z). ref is a slide id ("s3") or a 0-based index.

Read

Deck

Slides

Objects

Present

History

Workflow:

  1. SlideClark.guide() (this document; SlideClark.guide(9) for one section) and SlideClark.getDeck() to understand the current state. If your tool mangles URLs or equals signs in long output, use the plain-text copies named at the top of this guide.
  2. Make the smallest change that does what was asked. Prefer updateObject, setPath, setCustom and setTweak over replacing whole slides.
  3. await SlideClark.auditAll() afterwards: every slide's problems list should be empty and checked should be true. Fix what it reports. SlideClark.audit() is the instant version and marks custom slides checked: false.
  4. Stop when the slide visibly updates. Do not reload the page (unsaved work lives in the tab and autosaves locally).

Direct DOM route (read-only, useful for finding things): every slide is <section data-slide-id="s1" data-layout="title">; every editable text has data-path; free-form objects are .ob[data-obj="<id>"]. Custom slides render in a sandboxed iframe, so edit their custom.html/custom.css/custom.js strings instead.

Examples:

SlideClark.addSlide("blank");                                    // returns the new index
SlideClark.addObject(2, { type: "text", text: "Q3 results", x: 80, y: 80, w: 900, size: 72, weight: 700, font: "display" });
SlideClark.addObject(2, { type: "shape", shape: "round", x: 80, y: 260, w: 360, h: 200, fill: "var(--shape)", text: "**42%** growth", color: "var(--on-shape)" });
SlideClark.updateObject(2, "o1", { x: 120, size: 64 });
SlideClark.setTweak("s1", "headline", { dx: 0, dy: -30, size: 88 });
SlideClark.setPath("s3", "items.0.value", "42");

12. Checklist before you answer