# Fugte Widget Build Reference > The complete format for writing a Fugte widget. If you are an AI > assistant generating widget code, this file is the specification to follow. Source of truth: https://fugte.com/docs/build/ Editor: https://fugte.app/ Last updated: 2026-07-26 A Fugte widget is a small, embeddable web app made of four files. The editor previews it live, and the same source is rendered by Fugte when the widget is published, so a widget that previews correctly will almost always publish correctly. This page is the build reference. It is written to be read by people and by AI assistants: if you are asking ChatGPT, Claude, Gemini, or a coding agent to write a Fugte widget, point it here first, or paste the primer below into the conversation. You do not need any of this to use Fugte. Text, colors, images, and options are editable in the Customize tab without touching code. This is for the people (and models) writing the code underneath. ## Prompt primer for AI assistants Copy this into your AI before asking it for a widget. It is the short version of everything on this page. ```text You are writing a Fugte widget. Follow these rules exactly. A widget is four files: index.html Markup fragment: Liquid + HTML only. NO doctype, html, head, body, style, or script tags. style.css All styles. Liquid works here. script.js Vanilla JS, no imports, no build step. Liquid works here. schema.json Settings schema that generates the Customize form. Liquid context: settings. values from the Customize tab section.settings. same value, Shopify-compatible alias section.blocks repeating blocks, loop with {% for block in section.blocks %} block.settings. per-block values data. public form submissions (published widgets only) sources. server-fetched remote data Hard rules: 1. Every {{ settings.X }} needs a schema setting with id "X", and every schema setting must be used in the markup. 2. Every setting needs a "default". 3. An empty string is TRUTHY in Liquid. For text, url, image, video, color, font, icon and html settings always write {% if settings.X != blank %}, never a bare {% if settings.X %}. For checkbox, range, number, select and radio, a bare check is correct. 4. Inline output needs a fallback: {{ settings.X | default: 'Something' }}. 5. Never emit an empty value where JS expects an expression: var list = {{ data.items | json | default: '[]' }}; 6. Use {% form "name" %} for anything that collects visitor data. Never write a raw
with your own fetch, submit handler, or CAPTCHA. Declare a matching "storage" collection whose id equals the form name and whose field ids equal the input name attributes. 7. Use {% payment "id" %} for money. Never include Stripe.js or a checkout link. Declare a matching "payments" config. 8. Use {% video "setting_id" %} for video, never a hand-written iframe or video element. Use {% render 'icon', icon: settings.x %} for icons, never a hand-written iconify-icon. 9. For date and time settings, print {{ settings.x }} but do all scripting and math with {{ settings.x_iso }}. Never pass a formatted date to new Date(). 10. Gradient settings are images: apply with background or background-image, never background-color. 11. Do NOT put viewport units on body (no min-height: 100vh). Style an inner wrapper instead, or the embed reports the wrong height. 12. No horizontal overflow at any width. Use flexible wrapping layouts and clamp() for fluid sizing. 13. If the widget uses blocks, include "presets" with 2 or 3 starter blocks so the first preview is not empty. 14. data.* and sources.* are always EMPTY in the editor preview. Always render sensible placeholder content for the empty state. 15. Put no Liquid inside the schema block. Labels, defaults, and info text are plain literal strings. Return all four files, complete, with no commentary between them. ``` ## 1. The four files Every widget lives in a virtual file system. The editor recognizes four well-known paths. | File | Purpose | | --- | --- | | `index.html` | Markup fragment (Liquid + HTML). No ``, ``, ``, `