Skip to content

Dev

Dev mode keeps the websites, games and apps a project makes: a launch page, a portfolio, a client preview, a small game, a server or tool that goes with the work. Each one is a folder under web/ in the project, so it travels with the project and shows up in Asset mode like anything else.

The front page

Click Dev in the top bar. The front page has the kinds of things Dev keeps down the left, and the kind you pick on the right with its own buttons. A number next to a kind says how many the project has.

  • Everything: the lot in one list, newest first. New opens a menu of everything you can start.
  • Websites: New website makes a blank site with a home page and a stylesheet. New page adds a page to one of the project's websites, and so does the page icon on a website's row. From reference starts a site from an existing page: give it the page's address or pick files (HTML, CSS, screenshots, PDFs). Kitlig keeps the reference inside the site's reference folder. Turning it into a design document, a theme and a clone with your own content is the next step of this mode; the page itself is never copied into your site.
  • Games and layouts: New game and New 2D game make a Kitlig Play scene, covered under Games. New layout makes a scene in millimetres for laying out CAD parts and 3D Kitlig Assets at their real size, covered under Product layouts.
  • Apps: New app makes a Node.js server, React or Next.js app, Electron window or Python app that Kitlig runs for you, covered under Apps.
  • CAD parts: New CAD part makes a part for printing or manufacture, built from sketches and steps, covered in CAD.
  • Shaders and shows: saved GLSL shaders and the cue lists that run a show from them, with New shader, New show and an import for each.

Click a row to open it. A kind with nothing in it says what you can start there.

Source control at the bottom of the list opens Git for the whole project or for one website, game, app or folder, covered in Source control with Git. The branch shows next to it once the project has a repository. An open site has a Git button in its bar that goes to the same place.

A website

A website has two kinds of page. A Blocks page is built in the visual builder from blocks; Kitlig writes its HTML for you. A Code page is plain HTML you write yourself. New websites start with a Blocks home page and a theme; pick Code in the New website or New page dialog for a hand-written page. Both kinds sit in the same folder and link the same stylesheets.

The builder

Opening a Blocks page shows the palette and the layers tree on the left, the page in the middle, and the inspector on the right.

  • Palette: click a block to add it. It lands inside the selected block when that block holds children (a section, container, stack, grid or footer), after the selected block otherwise, or at the end of the page when nothing is selected. The Library tab holds the project's components.
  • Layers: the page as a tree. Click to select and scroll the preview to the block; drag a row onto another to move it (top edge: before, bottom edge: after, middle: inside a container). The eye hides a block without deleting it.
  • Preview: click a block to select it, double-click to jump to its text in the inspector. Switch between phone, tablet and desktop widths; the inspector then edits the styles for that width. Wireframe shows the layout as grey boxes. Ctrl+Z and Ctrl+Y undo and redo, Ctrl+D duplicates, Del removes the selection.
  • Inspector: the Block tab has the block's content (text, image, link, level, items) and its styles in groups (layout, size, spacing, text, surface) with the breakpoint switch All, Tablet+, Desktop+. Styles are CSS values; the suggestions offer the theme's tokens (var(--kb-accent), var(--kb-space-6)) so a theme change restyles the page. The Page tab holds the title, description and extra head or body HTML. The Theme tab is below.
  • Code opens the page's document as JSON under the preview. Edit it and Apply, or copy it out for an agent.
  • Changes save on their own a moment after you stop; the status at the right of the toolbar says saved.

Actions

Blocks can behave without any code. Select a block and, in the inspector's Actions section, click Add: an action pairs a trigger with an effect.

  • Triggers: click, hover, enters the viewport, a scroll range, page load, after a delay, a form submit, or a custom event.
  • Effects: show, hide or toggle a block (animated with the theme's motion unless you turn that off), add, remove or toggle a class, scroll to a block, go to a link, set text, an attribute or a CSS variable, emit an event, play or pause a Lottie block.
  • On picks the block the effect applies to: this block or any other on the page. Hover and viewport triggers can reverse the effect when the pointer or the block leaves.

A hidden block (the eye in the layers tree) plus a button with a click → toggle action is a disclosure; a section with enters the viewport → show is a reveal. Kitlig writes a small runtime, scripts/kitlig-blocks.js, into the site the first time a page uses actions; the exported site needs nothing else.

Animation

Any block can be keyframed, with the same keyframe model the Keyframes drawer uses on the timeline. In the inspector's Animation section:

  1. Pick what plays it: On page load (once, or Loop, after an optional delay), With scrolling (the block's travel through the viewport, or the whole page, scrubs it), or When triggered (an action's Play animation effect starts it).
  2. Drag the Scrub slider to a time; the preview freezes every animation on the page at that moment.
  3. On a channel (Move X, Move Y, Scale, Rotate, Opacity, Blur, Tracking) click + key: a keyframe with the channel's current value lands at the scrub time. Change its time, value and easing (ease in out, ease in, ease out, linear, hold) in the row, or remove it.

Kitlig samples the curves into a CSS @keyframes rule for the block, so a load animation needs no script in the exported page and plays in any browser. Scroll and trigger animations use the same rule with a small runtime, scripts/kitlig-anim.js. Everything respects the reader's reduced-motion setting.

A Lottie block plays a Lottie file from the site's assets with the bundled player; the Assistant can put a timeline Lottie clip on a page for you.

Page to video

To video in the builder's toolbar renders the page to an mp4 asset: a hidden browser steps the page's animations frame by frame at the size, length and frame rate you choose, and ffmpeg encodes the frames. Scroll the page while recording moves from the top to the bottom over the length, which is how scroll animations and reveal snippets get on tape. The file lands in video/generated and drops onto the timeline like any render.

Page tab: snippets, CSS and script

The Page tab holds the title and description, extra head and body HTML, and three more things:

  • Snippets: ready scripts with a settings form each. Smooth scroll, lightbox for images, back to top, countdown, cookie notice, an analytics tag (Plausible or Google Analytics 4), reveal on scroll, and external links in new tabs. Each is generated from its settings into the page, so nothing is fetched from Kitlig later.
  • Page CSS: rules for this page only, after the theme and site stylesheets.
  • Page script: JavaScript that runs at the end of the body, after the blocks, the actions runtime and the snippets. Check page reports its errors.

Custom code blocks

A Custom code block holds your own HTML, CSS and JavaScript. Inline (the default), the CSS is scoped to the block and the script runs with root set to the block's element, so it can reach the rest of the page. Tick Sandboxed to run it in its own iframe instead: it cannot read or change the page, which is the right choice for code you did not write yourself. An Embed block does the same for another page's address.

From a reference page to your own

A site started with + From reference keeps the page it came from. Under Reference in the site's left column:

  1. Extract design document measures the page in a hidden browser (colours with their usage, fonts and sizes, spacing, radii, shadows, breakpoints, container width, buttons, motion, a section inventory, screenshots at phone, tablet and desktop widths) and has your configured AI model write a design document: palette roles, the type system, layout patterns per section, components, motion language, image treatment and tone of copy. It opens as reference/design.md, and the measurements stay in reference/facts.json. Without a model key you get the measured document alone.
  2. Apply its theme compiles the document into the site's theme. Licensed fonts map to bundled or system stacks that read the same way.
  3. Build a page in this look… makes a new Blocks page from the document's structure with your content: Same design, my content keeps the sections and has the model write copy from your brief; Same structure, another theme swaps the look for a preset; Remix reorders under the same tokens. The reference's own text and images are never used.
  4. Compare open page takes fresh screenshots of your page beside the reference's, lists how fonts, colours, body size, section count and width differ, and gives a rough similarity score.

The same steps exist as an operation, Design from Page in the Sandbox and Workflow pickers, which creates the site from an address in one go, and as Assistant tools.

Note

Extraction reads style and structure only. Copy, photographs and font files belong to the page's owner; bring your own.

Themes

A theme is the site's colours (background, surface, text, muted, accent, text on accent, border), fonts for headings, body and code, the type scale, the spacing unit, radii, shadows, motion and the page width. Kitlig compiles it to styles/theme.css as CSS variables that every block class and generated page uses. Pick a preset (Kitlig Dark, Paper, Studio) to start, then adjust; the preview follows every change live and the file updates a moment later.

Components

Select a block and click the package icon in the inspector to save it, with its children, to the project's component library. Its headings, texts, image sources, button labels and links become props, so each instance you place from the Library tab can say something different while the layout stays shared. Editing the master in its JSON updates every instance on the next build.

Code pages

Opening a Code page shows the page in a live preview with the code editor underneath.

  • The preview runs on a small local server that Kitlig starts for the project, on its own address, so a page's scripts run in the page and never inside Kitlig. Switch between phone, tablet and desktop widths, or press reload.
  • The editor opens the page's HTML, the stylesheet, or the reference source. Save (or Ctrl+S) writes the file and reloads the preview. Only text files open here.
  • Check page loads the page in a hidden browser window and lists what its console said, with every request that failed (a missing stylesheet, a broken image path) and the page's title and height. Fix what it shows, save, and check again.
  • Pages are plain HTML and CSS. Anything you write, paste, or ask the Assistant to write works as it would on any site.

Games: Kitlig Play

New game under Games and layouts makes a Kitlig Play game: a folder with scene.json, a scripts folder, an assets folder and a page that boots the runtime (three.js rendering, a fixed-step loop, keyboard, mouse, gamepad and touch input, a small physics with gravity, colliders, triggers and a character controller, 3D audio, timers, tweens and an HTML overlay). The starter scene has a ground, a player you can already walk and jump with (WASD or arrows, Space), a camera that follows, a sun and a pickup.

Entities and components

A game is entities with components, the way Unity does it. Each entity has a name, a transform, an optional parent and an ordered list of components:

  • Mesh Renderer (a primitive or a GLB model with colour, texture and shadows), Light, Camera, Rigid Body, Collider, Audio Source, Trigger (fires scripts and events when something enters), Spawner (instances a template entity on an interval), Character Controller, Orbit Camera, Follow Camera, UI Overlay (HTML over the canvas) and Script.
  • Script is just another component, and an entity can carry as many as it needs: Health, Shooter and Patrol on one enemy, each with its own fields, enabled switch and place in the order. They run in list order; no inheritance, no one-script-per-object.
  • A Template entity is a blueprint: inactive in the scene, instanced by Spawner components and by scripts.

The left column is the Hierarchy (click to select, the eye disables) and the Scripts list. The right column is the inspector for the selected entity: transform, parent, tags, then each component with its fields. Add components from the menu at the bottom; the arrows reorder them. With nothing selected the inspector shows the scene settings (background, ambient light, gravity, shadows, pointer lock) and the asset list.

Scripts

+ Lua or + JS makes a script and opens it under the game. A script defines any of start, update(dt), fixedUpdate(dt), lateUpdate(dt), onTriggerEnter(other), onTriggerExit(other), onCollision(other), onEvent(name, data) and onDestroy, and has three things in scope: self (this entity's id), fields (the values set on the Script component in the inspector) and api, the same API in both languages (API in the editor's toolbar lists it): entities, transforms, component props, input, physics, audio, timers and tweens, events, the overlay, the camera. Lua 5.4 runs on a WebAssembly VM shipped with the runtime; JavaScript runs as is. Errors show in Check game with the script's name and line.

Attach a script to an entity with a Script component and pick it; the script's declared fields appear right there. Save (Ctrl+S) restarts the game.

Input

Games read the keyboard (WASD and arrows for movement, Space to jump, any key by name in scripts), the mouse (position, movement, buttons and wheel; Orbit Camera drags and zooms with it; a Character Controller with Mouse look turns with it, under pointer lock when you choose locked), gamepads (left stick to move, right stick to turn, A to jump, every button and axis by index in scripts) and touch. The Assistant can play with all of them through game_input, including a virtual gamepad.

Touch controls

On a phone or tablet a game shows on-screen controls: a stick under the left thumb, buttons on the right, and a Full screen button. They stand in for the keyboard and mouse, so a game made for WASD and the mouse plays on touch without changing a script. The stick drives the movement axes and holds W, A, S and D, and each button holds a key or a mouse button while pressed. The settings live under Touch controls in the scene settings:

  • Show: Auto shows them on touch devices when the scene has a Character Controller or buttons of its own; Always and Never do what they say.
  • Stick: movement, or none.
  • Drag the right side to look: turns the camera like mouse look, for first-person games, with its own speed.
  • Buttons: up to eight, each with a label, the key or mouse button it holds, and Toggle for things like sprint. The first one is drawn bigger.

To try them on a computer, add ?touch=1 to the game's address. While they show, the game's page carries the CSS class kp-touch-on, so a HUD can move its corners clear of the thumbs, and scripts can ask api.isTouch() or hide the controls with api.setTouchVisible(false) on a results screen.

Loading screens

A game can show a loading screen whenever it changes the whole scene, so players see progress instead of a frozen frame or a half-built level. Open App settings (the settings icon in the Game view toolbar) and pick a Loading screen:

  • None (swap scenes directly): the default. Scenes change the way they always have.
  • Built-in (progress bar): a plain screen with a title (the app name unless you type one), an optional logo from the game folder, a bar, a status line and a percentage. You choose the background, bar and text colours.
  • Loading scene: a scene of your own runs on top while the next scene loads underneath. It can be anything a scene can be: a spinning logo, tips, a character idling, a short animation.

Create loading scene writes a starter one to scenes/loading.json, with a camera, a spinning cube, an overlay with a bar, and a Lua script already listening for progress, then selects it. Open it in the scene editor and make it yours.

The other settings:

  • Show while the first scene loads: also cover the game's very first load, not only later scene changes.
  • Close when loaded: close by itself once everything is ready.
  • Show at least: a fast load still shows the screen this long, so it doesn't flash.
  • fade: how long the screen takes to fade out.
  • give up after: close anyway if loading takes longer than this. 0 waits for as long as it takes.

Kitlig reports progress on its own. The bar moves through fetching the scene file, every model, texture and sound the scene lists (loaded side by side, so the total is known up front), building the entities, and starting the scripts. The status line names what is loading.

A level that does its own setup in start() can add that work to the same bar. api.addLoadingTask("Spawning waves", 1) returns a task; report it with api.setLoadingTask(task, 0.5, "Spawning waves") and close it with api.finishLoadingTask(task). The screen stays up until every task is finished. A weight of 1 counts as much as the whole scene load.

A loading scene hears what is happening through onEvent:

  • loading:start with the scene being loaded,
  • loading:progress with value (0 to 1) and info (the status line),
  • loading:finished once the scene and every task are done,
  • loading:minDisplayElapsed once Show at least has passed.

To play an outro, call api.holdLoading() in the loading scene's start(), then api.closeLoading() when the outro ends. The game's own scripts get loading:closed when the screen is gone, which is a good moment to start music or a countdown.

api.loadScene("level2", {instant = true}) skips the screen for one change, and api.loadScene("boss", {loading = "scenes/boss-loading.json"}) uses a different loading scene for one change. To try a game without its loading screen, add ?loading=0 to its address.

Note

The game keeps running underneath while the loading screen is up, like most engines do. Scripts in the new scene start as soon as it is built, so hold anything that should wait for the player (a timer, enemies waking up) until loading:closed.

On a phone or another device

Device in the toolbar of a game or a website shows a QR code. Scan it with a phone, a tablet or another computer and the game or page opens there, touch controls included. The link works for 12 hours and goes through the phone companion, so Settings ▸ MCP Server needs the server and Phone companion on. Other devices on your Wi-Fi reach it when Listen on network is on; with Remote access they reach it from anywhere.

The phone companion also has a Sites & games section: play or open every game and website of the project full screen, share a link, make a new game or website from a name and a sentence, and keep building it by chatting with the Game Builder or Web Builder from the phone. Those conversations also appear in the desktop Assistant.

The scene editor

A game opens in the scene editor: the scene drawn without scripts or physics, with a grid, a camera you orbit with the mouse (drag to turn, wheel to zoom, right-drag to pan) and gizmos on the selected entity. Click an entity in the view or in the hierarchy to select it; cameras, lights, triggers and empty entities show as outlines so they can be picked too. W, E and R (or the toolbar) switch the gizmo between move, rotate and scale; the magnet snaps to half units, 15 degrees and tenths of scale; F frames the selection. Dragging a gizmo writes the transform into the inspector and the scene file; editing a number in the inspector moves the entity in the view. Play runs the real game in the same spot; Stop returns to the editor.

Playing and checking

In play mode the game runs live in the middle of the view; click it to give it focus. Restart reloads it; Restart on save does that after every change. Check game boots the game in a hidden browser and reports runtime errors, console errors and what api.log printed, with every entity's position.

The Assistant has the same abilities: it creates games, adds entities and components, writes scripts, and plays what it built with keys in a hidden browser, looking at screenshots and positions to see whether the player moved or the pickup fired. The Game Builder persona is tuned for this.

Game from Prompt

Game from Prompt in the Sandbox and Workflow pickers (under Web) writes a whole small game from a brief with your configured AI model: the scene with a player, camera, lights, ground, triggers and HUD, and the Lua scripts behind it. Kitlig boots the result in a hidden browser and gives the model one round to fix any error it reports. The game appears in Dev mode like one you made by hand.

Export

A website or game is a static folder. Export zip in the header zips web/<slug>/ into the project's exports folder with nothing Kitlig-specific inside; unzip it on itch.io, your own host or the phone companion and it runs. Nothing is fetched from Kitlig at play time.

Note

Physics is a small built-in (axis-aligned boxes, gravity, triggers) made for prototypes and small games. Keyframing component fields in the editor is not there yet; scripts animate with api.tween meanwhile.

Product layouts

A layout is a Kitlig Play scene measured in millimetres, for seeing how a product fits together before you design its case. Make one with New layout under Games and layouts, or switch an existing scene's Mode to Product layout (mm). The grid is in 10 mm squares, the move gizmo snaps to 1 mm, and the camera works close up. Cameras and lights draw as small markers so they don't fill the view.

Everything CAD in a layout sits under CAD: a menu above the hierarchy, and a CAD submenu when you right-click a row. Game scenes don't show either, so a game isn't cluttered with tools it doesn't need. To turn them on in a scene, set its Mode to Product layout (mm).

The CAD menu has:

  • Add CAD part: the project's CAD parts. A part comes in as its own model, which Kitlig writes beside the part (cad/<name>.glb) a moment after each change you make in CAD.
  • Add board: a circuit board at its real size, from the built-in list or From a KiCad file… (see Boards from KiCad). A board comes in as a small CAD part of its own, a board part, so it carries its connectors and screw holes into an enclosure. Adding the same board again reuses its part.
  • Add model: the project's GLB and glTF Kitlig Assets.
  • Create footprint…, Create enclosure…, Split into its bodies (or Update its bodies), Add a joint… and Open in CAD, for the row you've selected.
  • Check the fit, Parts list…, Print plate… and Render with AI…, for the whole layout (see below).

In the inspector the position reads Pos (mm), so you can type exact amounts.

Groups

Hold Ctrl or Shift and click rows in the hierarchy to pick several. Right-click one and choose Group (it reads Put in a group with one row picked). The group sits at the middle of its parts and they stay exactly where they were. Ungroup puts them back under the group's parent, still in place. Only rows under the same parent can be grouped, and a group with components of its own can't be ungrouped.

Footprints

Right-click a part or a group and choose CAD then Create footprint…. Give a clearance in millimetres, or 0 for the exact outline. Kitlig traces the outline it casts on the floor, makes a new CAD part with that outline as a sketch, and opens it. The outline keeps the layout's place: CAD's X is the layout's X. Extrude it into a base, offset it, or design a case round it.

The outline is traced on a fine grid, so it's true to within about a tenth of a millimetre on a hand-sized product; the message after it says how close. Curves come out as a few straight lines.

Enclosures

Right-click a group (or one board) and choose CAD then Create enclosure…. Set the wall thickness, the gap inside, the corner radius and the lid: a lip and groove, snap latches, screw posts, or no lid. Kitlig makes a new CAD part with the boards and models where they sit in the layout, an Enclosure step round them, and the lid. It puts the case into the layout too, round the boards, and opens it in CAD.

Boards bring their connectors and screw holes, so the case gets an opening where each connector faces a wall and a post under each hole. A lid needs whole walls where the halves meet, so the seam goes just above the highest connector opening, and the roof rises to make room for the lid when a connector is the tallest thing inside.

Only a board's turn about upright goes into CAD. A board tilted or scaled in the layout goes in level and at its real size, and the message after says so. Models that aren't boards (CAD parts with a solid, and Kitlig Assets) go in as models to fit round, without openings or posts.

Joints and motion

A joint lets one part move against the rest: a lid on a hinge, a drawer or a battery door on a slider. Kitlig moves the part through its range and tells you where it runs into something, so you find out the lid hits the wall before you print it.

A case made with Create enclosure… is one model with the lid as its second body. To move the lid on its own:

  1. Pick the case and choose CAD then Split into its bodies. The case keeps its place and its two bodies come in under it as Base and Lid (a part in more pieces gives Body 1, Body 2 and so on).
  2. Pick Lid and choose CAD then Add a joint….
  3. Choose Hinge: it turns or Slider: it slides, where it goes, and how far it moves, then click Add joint. Along the back bottom edge (a lid) puts a hinge at the seam, where the lid's outer wall meets the base, not at the bottom of the lip inside it.

The part's joint shows at the top of the inspector:

  • Drag the slider to move the part. It previews as you drag and stays where you let go.
  • From and To set the range, in degrees for a hinge and millimetres for a slider. A positive turn lifts the side away from the hinge, the way a lid opens.
  • Play motion runs it through its whole range and back.
  • Check for collisions moves it from where it is to each end of its range and stops at the first thing it runs into. It names the part it hit and offers to set the range to where it moves clear. Parts resting flat against each other, as a lid rests on its base, don't count, and nor do faces that touch where the part sits closed, so the answer is the same wherever the part starts.
  • Let it fall lets the part's weight move it until it rests on something or reaches the end of its range: a lid falls shut or falls open, depending on which side of the hinge its weight is.

A collision check is honest about how parts really fit. A lid with snap latches can't open on a hinge, since its hooks sit in the base's windows, and a lip with very little clearance can catch on the front wall as it swings. When a part can't move at all, the message says why.

If you move a part by hand after giving it a joint, the panel says so. Click Set the joint again here to make where it is now the joint's starting place. Joints are saved in the layout's assembly.json, so they stay out of the scene and out of any game made from it.

Note

Collisions are checked against each part's triangles in steps small enough that no point of the part moves more than a millimetre between two checks, and a hit is narrowed down to where it first happens. Something thinner than a millimetre, met edge on, could still slip between two checks. A split body's model follows the part: a moment after each change you make in CAD, its bodies are written again too. Update its bodies does it by hand.

Checking the fit

Check the fit tests every part in the layout against every other, where they stand: a board pushing through a wall, a connector running into a standoff, a lid too tight to close. If anything crosses, a list names both parts and roughly where, in millimetres, with buttons that pick either part.

Parts that only rest against each other don't count, and nor do overlaps thinner than a fiftieth of a millimetre, far finer than anything prints. A case's own bodies, split from one CAD part, were made to fit each other, so their lip and groove aren't listed either.

Note

The check looks for surfaces that cross. A part sitting wholly inside another, with no surface of one passing through the other, isn't found.

Parts list

Parts list… builds every CAD part in the layout and lists what the product needs:

  • each printed part or body, with its material and its weight in grams, worked out from its volume and the material's density,
  • each board, with its notes,
  • other models,
  • the screws and heat-set inserts the cases' screw connectors take, with how deep their holes are.

The same part placed more than once is one line with a count. Save as CSV… writes it for a spreadsheet or a supplier. The product page gets the same list.

Print plate… puts every printed body in the layout into one 3MF file for your slicer. Each body is turned onto the side that needs the least support, from the overhang angle in the part's printer profile, and the bodies are packed in rows onto the bed of the first part with a printer profile (256 mm across when none has one). A lid usually ends up upside down, on its flat top.

When everything doesn't fit on one bed, the rest sit beside it in the same file, and your slicer's Arrange gives each plate of its own. The message after saving says how many plates it takes and names anything bigger than the bed.

Note

Bodies lie square to the bed: a part longer than the bed won't be turned to lie across its diagonal.

Rendering with AI

Render with AI… turns the layout into a picture of the real product. It takes a clean view of the layout as you're looking at it, without the grid, markers or gizmo, and sends it to an image model with a prompt that keeps the product exactly as drawn and makes it look manufactured.

  1. Turn and zoom the layout's view to the angle you want. The dialog shows the picture it will send; Retake takes it again after you move the view.
  2. Pick a Setup: where and how it's shot. The built-in ones are Studio, white, Studio, dark, On a desk, Maker's workbench, Outdoors, Launch hero and In a hand.
  3. Pick the Model. Nano Banana 2.1 Edit is the default; any image edit model in Kitlig that takes several pictures and a prompt is in the list, with its price.
  4. Under Materials, give each part a look: Matte PLA print, Silk PLA print, Injection moulded, Anodised aluminium, Circuit board and more. Each starts from the part's CAD material, and boards start as circuit boards. To say it in your own words instead, type in Or describe it. Keep its colour from the layout holds the colour you gave the part.
  5. Type anything else into More for this render, such as "a coffee cup beside it" or "warmer light", and add Reference image pictures for this render only.
  6. Click Render. The picture lands in the dialog under Renders and in your assets.

Show the whole prompt shows exactly what goes to the model. The dialog remembers your choices for each layout, in the layout's render.json.

Your own setups

New setup makes a setup of your own: a name, a prompt describing the setting, light and mood, the picture shape, and up to eight reference images of the look you're after. Your setups are kept with Kitlig rather than the project, so every project has them. Edit and Delete change them, Share… saves one as a .kitligrender file with its pictures inside, and Import… brings one in from someone else.

Warning

A render costs what the model costs, about five cents a picture with Nano Banana 2.1 Edit at its standard size. The model is told to keep the product as drawn, but image models can still change small details, such as text or the number of vents. Check a render before you use it to sell the product.

Agents and the layout

An agent connected to Kitlig's MCP server can do all of this too:

  • joint_split splits a case into its bodies, joint_add gives a part a hinge or a slider, joint_set moves it, and joint_check_collisions and joint_let_fall run the same checks as the buttons. joint_list, joint_update, joint_rehome and joint_remove cover the rest.
  • layout_check_fit, layout_bom (with a CSV if it gives a path) and layout_print_plate (to a 3MF) do the same as the menu.
  • layout_render_options lists the setups, looks and models, and layout_render makes a render, keeping the agent's choices as the layout's render settings.
  • layout_screenshot shows it the layout.

Each tool opens the layout under Dev, so keep Kitlig's window open and showing while an agent works on it.

Product pages

Make a product page… at the bottom of the CAD menu turns the layout into a web page that shows the product in 3D. Every model in the layout goes in, placed as it is, and each part says what it is: a CAD part with its material, or a board with its notes. The page appears under Websites like any other.

On the page, visitors can turn and zoom the product, hover a part to light it, and click it (in the view or in the parts list) for its name, size in millimetres, material and notes; the other parts fade back. Explode pulls each assembly apart: the biggest part stays put and the rest come out of it. The eye beside a part hides it. Clicking a part changes the page's link to end in #part=Name, so a link can open on a part.

Parts with a joint in the layout move on the page too: a button such as Open Group enclosure Lid swings the lid open on its hinge through its range, and turns into Close once it's open. A slider's button slides it out and in. Parts list shows the layout's parts list, with Download CSV.

The page is plain files: index.html, product.json (the parts, which you can edit by hand), the models in models/ and the viewer in scripts/. Export zip and upload the folder to any web host. Once a layout has a page, Update the product page writes it again after you change the layout; it keeps your index.html.

Opening a part in CAD

Right-click a CAD part in the layout and choose CAD then Open in CAD, or pick it and use the CAD menu. The layout stays open behind it: the Back button at the top left reads Layout and returns you there. Kitlig Assets don't have this, since they aren't parts with a history.

Note

The layout shows a part's new shape the next time it loads its models. Click Reload in the toolbar if it still shows the old one.

Apps

An app is a project folder Kitlig runs as a process: a Node.js server, a React app, a Next.js app, an Electron window or a Python app. Firmware projects are the exception: they build here and run on a board. Kitlig keeps the files, runs the app on a free port, shows its output, and previews the pages it serves. The code is yours; nothing in the folder is specific to Kitlig except site.json, which records the name and the run command.

Runtimes

Kitlig bundles neither Node.js nor Python. It looks for them on your machine (your PATH, the usual install folders, nvm and volta) and you can point at an install in Settings ▸ Tools & Apps ▸ Dev runtimes. The New app dialog shows what was found.

Missing one? The Dev mode step of the first-run tour and Settings ▸ Tools & Apps ▸ Dev runtimes have an Install Node.js and an Install Python button. On Windows it runs winget install --id OpenJS.NodeJS.LTS -e (or Python.Python.3.12); on a Mac with Homebrew, brew install node (or python@3.12). Each installs the project's own official package, and the exact command is shown before you click. On Linux, and where neither tool is available, you get the official download page and the command for your distribution to paste into a terminal. Both are separate open-source programs (Node.js under the MIT licence, Python under the PSF licence) and not part of Kitlig.

Note

Without a Node.js install, Kitlig runs dependency-free Node apps with its own runtime, so the Node.js server template works on a bare machine. Installing packages (npm), Electron apps and Python apps need the real installs. The Docker image carries Node.js and Python.

Templates

Template What you get Before the first run
Node.js server An HTTP server on node:http with a JSON API (/api/health, /api/time, /api/echo) and a static public/ folder. Nothing: it runs at once.
React app A Vite + React single-page app with hot reload. Install (react, vite).
Next.js app An App Router project with a page and an API route. Install (next, react). The first page load compiles.
Electron app A desktop window: main, preload and a renderer page. Install (downloads Electron). Needs a real Node.js install and a display, so it does not run headless.
Python app An http.server app with a JSON API and a static public/ folder, standard library only. Nothing. Packages added to requirements.txt go into a .venv with Install.
Firmware An Arduino sketch for an ESP32, ESP8266 or Arduino board, as a PlatformIO project. See Firmware. PlatformIO. The first build downloads the board's toolchain.

Every template reads its port from the PORT environment variable and binds 127.0.0.1; Kitlig picks a free port for each run. The README in each folder has the command to run the app by hand.

Running an app

Open the app and click Run. The pill in the toolbar goes from Starting… to Running once the port answers; a server app then appears in the preview at phone, tablet or desktop width, with Check page loading it in a hidden browser to list console errors and failed requests. Stop ends the whole process tree; the restart button stops and runs again. Install (or Reinstall) runs the template's install command with its output in view, and is refused while the app runs.

The Output tab below holds everything the process printed, with Kitlig's own lines (the command, ready at, exits) in brass. Follow keeps the newest line in view; copy or clear it from the same bar. The Editor tab edits the open file with Ctrl+S to save. Node's --watch, Vite and Next reload on their own after a save; the Python template restarts the process instead (restartOnSave in the app's settings).

The file tree hides node_modules, .venv, .next, dist and other dependency and build folders. They are never edited through Kitlig and never go into Export zip, so an exported app is small and installs its own packages where it lands.

Warning

An app runs with your user's permissions, like running it from a terminal. Read code an agent or a template wrote before running it, and keep secrets out of the folder: it travels with the project and with exports.

Closing the project or quitting Kitlig stops every app.

Firmware

A Firmware project is code that runs on a board instead of on your computer: an Arduino sketch for an ESP32, ESP8266 or Arduino board. The folder is a standard PlatformIO project, with your code in src/main.cpp and the board and libraries in platformio.ini, so it also opens in VS Code.

Set up PlatformIO. Click Install PlatformIO in the project, in the Dev mode step of the first-run tour, or in Settings ▸ Tools & Apps ▸ Dev runtimes. It needs Python 3.10 or newer. Kitlig installs pioarduino, the community build of PlatformIO Core, into its own folder (.kitlig-platformio in your home folder), so a PlatformIO setup you already use in VS Code isn't touched. You can also point at your own copy, as long as it can build the ESP32 platform below.

Build and upload.

  1. In New app, pick Firmware, choose a board and click Create.
  2. Edit src/main.cpp. The starter sketch blinks an LED and prints to the serial port.
  3. Click Build. The first ESP32 build downloads its toolchain, which uses about 10 GB of disk and took over 20 minutes in our test. Arduino boards are much quicker. After that, builds take seconds. The Output tab shows compiler errors, and the Flash and RAM bars show how much of the board you've used.
  4. Plug in the board, pick its port in the toolbar and click Upload.

Add libraries under lib_deps in platformio.ini. To change boards, use the Board picker, or Find another board to search everything PlatformIO knows. It only changes the board and platform lines, so your own settings stay.

Serial monitor. The Serial tab reads and writes the port, like the monitor in the Arduino IDE. Pick a baud rate, click Connect, and type in the box to send. Choose a line ending, or tick Hex to send raw bytes like 01 FF 2A. Reset board restarts the board so you can catch its startup output. You can leave the monitor connected during an upload: Kitlig closes the port for the upload and reconnects after.

Flash a ready-made file. Flash .bin writes a finished firmware file to an ESP32 or ESP8266 without building anything, which is how stock firmware such as a WLED release goes on a board. It doesn't need PlatformIO. Use address 0x0 for a merged image and 0x10000 for an app-only image; the firmware's release notes say which you have. A build here writes a merged image too, as firmware.factory.bin in the .pio folder. Erase the whole chip first also clears saved settings such as Wi-Fi details.

Note

ESP32 boards use the community pioarduino platform, because the official PlatformIO platform stays on the older Arduino core. Kitlig pins a tested release in each new project. It isn't an official Espressif or PlatformIO product. PlatformIO, the toolchains and the libraries are separate programs under their own licences and download to your computer. None of them ship with Kitlig.

Warning

If Upload or Flash .bin can't connect, check that the cable carries data, not just power, and that no other program has the port open. Some boards need you to hold BOOT while connecting. Some USB chips need a driver on Windows and Mac. On Linux, add yourself to the dialout group. In the Docker image, pass the port through with --device or Kitlig won't see the board.

With the Assistant

The Assistant has the same abilities: it checks which runtimes are available, creates an app from a template, installs, starts and stops it, reads its output, calls its endpoints over HTTP and looks at its pages in a hidden browser, so it can test what it wrote before handing it back. The App Builder persona is tuned for this; "a small API that lists the project's renders with a page that shows them" or "a Python tool that renames the exports by date" are the kind of brief it takes.

With the Assistant

The Assistant (and any agent connected over MCP) has the same abilities as this view: it lists the project's websites, games and apps, creates one or adds a page, writes whole files, takes a screenshot of a page at a chosen width, reads the console, and opens the result in Dev mode for you. Ask for the page in plain words ("a one-page portfolio with my three best renders and a contact form"), point it at the media with @ mentions, and it builds, looks, and fixes before handing back. The Web Builder persona in the Agents list is set up for exactly this; see Assistant.

When a page comes from a reference, the Assistant reads the saved source for structure and rhythm only. Your copy and your images go in; the reference page's text, pictures and fonts stay out.

Note

Animation on pages uses its own compact keyframe editor for now; the timeline's dope sheet and graph editor do not open in Dev mode yet, though the data is the same shape.

Shaders

New shader on the Dev front page opens a shader on its own: the code beside a live preview, with the inputs under it. The button by Save stacks them top and bottom instead. Every shader you save is listed on the front page, with a filter for this project or all projects.

Keeping them. The picker in the toolbar says where a shader lives. This project keeps it with the project. All projects keeps it with Kitlig, so it appears wherever you work; pictures and models it points at stay behind, because they belong to the project. The download button writes a .kitligshader file to share, and Import on the front page reads one.

Using them. Saved shaders appear under My shaders in the timeline's Generators, and agents can list them and add them too. A clip keeps its own copy and follows the shader: save the shader and linked clips in this project take the new code, with their own values, keyframes and pictures kept. Clips in other projects take it when you press Update in the Clip panel. Editing a clip's code by hand ends the link for that clip, and Unlink does it on purpose.

The clock. Fixed runs a set length at a frame rate, with a scrub bar and Loop. Infinite just keeps running, for a live set. Full screen (or double-click the picture) fills the screen, and Esc comes back.

Performance

Performance in the toolbar swaps the inputs for the live show. All of it saves with the shader, and none of it starts by itself: opening a shader, even one someone sent you, turns nothing on.

  • Feeds put a camera or another app's Spout or Syphon picture on a texture input, or a microphone on a Sound input. Choose them, then press Start feeds.
  • Flags are the buttons you play: Toggle, Bang (on while held) or Fader.
  • Rules join a signal to an action. A signal is an OSC address (* and ? work within a part), a DMX channel, a flag, a key, a beat or a sound level. The action sets an input or a flag, sends OSC or DMX, or calls a script function. From and to rescale the value.
  • Network sets the OSC port to listen on, Art-Net in, and the targets you send to. Go Live opens the ports, after Kitlig asks once each time it runs; Stop closes them. It listens to this computer only until you tick Listen to the network.
  • Cues are the moments of a show, fired in order with Go. See Cues.
  • Spout out (Syphon out on a Mac) sends the picture to other apps on this computer. See Sharing the picture.
  • Script is JavaScript with no access to your files or the network except through its own calls. It runs when you press Run.
on('beat', () => flag('flash', 1))
on('osc', '/puppet/mouth', (value) => set('mouth', value))
on('frame', (time) => dmx('Rig', 0, 1, Math.sin(time) * 0.5 + 0.5))
functions.cue = (value) => osc('Lights', '/go', value)

on also takes flag, key, level, cue and dmx (on('dmx', universe, channel, fn)). set(name, value) sets an input, flag(id, value) a flag, osc(target, address, ...values) and dmx(target, universe, channel, value) send to a target by name, log(...) writes to the Log, and anything in functions can be called by a rule. go(), back() and cue('Drop') run the cue list, and in a show load('Sunrise', 2) brings up a saved shader by name with a two second fade.

Warning

A shader from someone else can carry rules and a script that send to your lights. Read them before you press Go Live or Run.

Cues

A cue is a moment you can fire. Go fires the next one, the arrow goes back, the lightning bolt on a row fires that cue, and Hold cancels the next automatic cue and anything still waiting while the picture stays.

  • Follow is the seconds until the next cue fires by itself. Leave it at 0 to wait for Go. With Loop on, the list starts again after the last cue, so a gallery piece can run all day.
  • Reactions, under the arrow on a cue, are what it sets off: send OSC or DMX, set an input or flag, call a script function, or fire another cue, each after a wait you choose.

From outside. Any show answers these OSC addresses once it is live, with no setup, so a lighting desk or a stream deck can run it:

Address What it does
/kitlig/go Fires the next cue
/kitlig/back Goes back a cue
/kitlig/stop Holds
/kitlig/cue Fires a cue by its name or number, given as the message's value

A value of 0 on the first three is a button coming back up, and does nothing. To fire cues from anything else, make a rule with Go, Back or Fire cue as its action.

To the outside. A rule that starts When Cue fires tells other equipment. Name a cue, or use * for any, and the value it passes on is the cue's number in the list. Set the rule's From and to ranges to cover your list, so that number comes through unchanged.

Sharing the picture

Kitlig shares pictures with other apps on the same computer through Spout on Windows and Syphon on a Mac.

Sending. Set a name and size in Spout out and press Send. Resolume, TouchDesigner, OBS and the like then list it under that name. Keep Kitlig's window on screen while you send: a minimised window stops drawing, unless a show has output windows open.

Receiving. Anything another app is sending appears in the list under Feeds for a texture input. Pick it and press Start feeds. If that app isn't running yet, the picture arrives when it starts.

Shows

New show on the Dev front page opens a cue list beside the picture. Where a shader's cues only fire reactions, a show's cues change the shader, so one show can run a whole night.

Pick a shader for each cue, and a Fade in seconds. The next shader loads out of sight and dissolves in over the one playing, and the fade reaches Spout and Syphon too. Space is Go, and Full screen fills the screen with the picture.

What stays up. The ports, targets, flags, rules, script and output in the show's own Performance panel run all the way through. Each shader adds its own feeds, flags, rules, targets and script while it's on screen, and its inputs go back to their saved values when it comes up. A shader's own cue list is ignored in a show: only the show's runs.

Starting it. Nothing starts when a show opens. Press Send, Start feeds, Go Live and Run for what you need, then Go. Those presses hold for as long as the show is open, so a shader a cue brings up joins in without asking again, and its script runs if Run is on. Leaving the show stops all of it.

Sharing. The download button writes a .kitligshow file with the shaders its cues, rules and mapping name, and Import beside the Shows list reads one. They arrive as new copies, so nothing of yours is overwritten. Pictures and models stay behind, as they do for a shader, and shaders named only inside a script don't travel: use a cue or a rule for those.

Projection mapping

The Mapping tab of a show puts it on real screens and projectors, on real things.

  • Outputs are windows. Add one for each projector and pick its display, or pick All displays for one window across every screen. Each output has its own resolution.
  • Sources are what you can show: the Show picture that your cues put up, a Test pattern for lining up, and anything you add: a saved shader, a camera, another app over Spout or Syphon, a picture or a video. Cameras and other apps open when you press Start feeds.
  • Surfaces put a source on an output. An output can hold as many as you like, each with its own source, so one projector can cover several objects. Top of the list draws on top. Crop picks part of the source, and Add blend suits two projectors overlapping.

Warping. With a surface selected, drag its handles on the picture. The arrow keys nudge the handle you last touched by a pixel, or ten with Shift. Corner pin is true perspective from four corners. Bezier grid gives you a mesh to bend: Across and Down add or remove lines without changing the shape, and Smooth curves runs curves through the points rather than straight lines between them. Click a point to see its Bezier handles and pull them to shape the curve; the opposite handle follows, unless you hold Alt to make a corner. Automatic curves forgets the handles you've pulled. Adding or removing grid lines does too.

Masks. Pick Pen and click round a shape, dragging as you click for a curve. Click the first point or press Enter to finish, Backspace to take back a point, Esc to give up. Masks stay on the output, not the picture, so one drawn round a statue stays on the statue while you warp what's under it. Select one to move its points and handles; hold Alt on a handle to make a sharp corner. Cut out shows everything but the shape, and Soft edge feathers it. The scissors make a new surface from the shape, so you can give it a source of its own, and Bake to picture saves the masks as a black and white image.

Undo. Ctrl+Z and Ctrl+Shift+Z, or the arrows in the toolbar, step through everything on this side. A whole drag is one step. With the pen out, Ctrl+Z takes back the last point.

Saving a mapping. A mapping saves with its show. The save button in the toolbar also writes it to a .kitligmap file on its own, with its outputs, surfaces, masks, scans and the shaders it shows, and the open button loads one into any show, replacing what's there (Undo brings it back). Keep one per venue. Pictures and videos stay behind, so those sources ask for theirs again, and check each output is on the right display.

On the wall. Open windows puts each output on its screen as a small window, with the selected surface's grid drawn on it, so you can line up by looking at the real thing. Identify shows each output's name on its screen. Performance fills every output's screen, with no guides and no cursor. Hold Esc for a second to come back: a tap does nothing, so a stray key can't end a show. Space and your key rules still work out there.

Auto map

Auto map lets a camera do the lining up. Point a camera at the projection, add it under Sources, and press Scan. Kitlig flashes black and white stripes on the output for about twenty seconds and works out exactly which projector pixel lands where. Then it makes the surfaces for you:

  • Wall, a surface whose corners make a picture look square from where the camera stands, however the projector is angled.
  • Object 1, 2…, one surface per thing standing off the wall, already cut to its outline, showing the test pattern so you can check the fit.

It finds objects by measuring them: a projector and a camera see the room from different places, so anything in front of the wall shifts against it. Nothing needs calibrating, and it costs nothing to run.

For a good scan:

  • Keep the camera and the projector still, and put them a little apart. The further apart they are, the better it feels depth. Side by side at the same spot, nothing stands out.
  • Dim the room, and turn off the camera's auto exposure if you can.
  • If the stripes come out wrong, raise Wait: a webcam can be several frames behind. A soft camera or a distant wall wants Coarse.

The scan opens the output full screen if it isn't open already, and Cancel stops it. Afterwards:

  • Sensitivity finds more or fewer objects, and the outlines update on the stage as you move it. Make surfaces replaces the ones the last scan made, and leaves your own alone. Undo works here too.
  • The backdrop in the toolbar shows the Camera view as the projector sees it, or the Depth, behind the handles, so you can draw masks right on the real thing. Black patches in the camera view are the shadows objects cast from the projector: the projector can't reach those.
  • Both pictures are in the list under Sources, already lined up with the output.
  • Depth from can ask an AI depth model instead, for shapes too shallow to stand out, like relief on the wall. It uses your Fal account and runs on the scan's camera picture, so it needs a scan from this session and an open scene.

A scan is saved with the mapping, so it's there next time. If anything moves, scan again.

Warning

A scan flashes the whole output. Warn anyone in the room who might be affected by flashing light, and don't run it on an audience.

Web remote

Web remote in Performance puts the running show in the Kitlig phone app, under Live show. It needs Phone companion on in Settings. Tick Show the picture for a small live view, and Allow control for Go, Back, Hold, the cue list and your flags. Without control, a phone can watch and nothing else.

It sits behind the phone app's login, and you can give it a password of its own: useful when a crew has the app but shouldn't run the show. The password stays on this computer and never goes in a show. Turning the remote off, changing the password or leaving the show locks every phone out again.

Warning

The phone app talks plain HTTP unless you've set up a secure address, so on a shared network a password can be read in passing. Keep a remote on a network you trust.

Warning

A show runs other shaders' rules and scripts as it reaches them. Read what's in a show someone sent you before you press Go Live or Run.