Create your first slop
A slop is a focused app and its document in one portable .slop package. Start with a working Checklist, then make the interface and data your own.
Install the tools
Section titled “Install the tools”Use Bun 1.4.2 or newer, on macOS or Linux. Creating, previewing, checking and building an app, and creating or editing its documents, need only the CLI. To register templates, open windows, render Finder artwork and export PNG/PDF, install the matching hitSlop Mac app in /Applications or ~/Applications. You do not need Node, Swift, Xcode, or a hitSlop repository checkout.
The public CLI workflow is:
bunx hitslop init tiny-countercd tiny-counterbun installbun run devAlternatively, install the CLI with bun install -g hitslop and run slop init tiny-counter. The generated project pins its own hitslop version; prefer its bun run scripts after creation.
See CLI workflows for command entry points, document creation, editing, moving data between documents, export, and agent skill installation.
init asks you to describe your slop and who the author is. It starts from a working Checklist, saves your idea in BRIEF.md, and includes AGENTS.md and authoring/design skills in .agents/skills/.
The final question asks which agent CLI should build it for you. Choose an installed Codex, Claude Code, Gemini CLI, or OpenCode, or select Other CLI… to enter a tool such as Grok and its prompt option. The agent launches in your project with the brief and hitSlop guidance. Choose Finish without launching to follow the tutorial below yourself. Add --yes for a non-interactive starter; this never launches another agent.
Understand the source
Section titled “Understand the source”Read slop.ts first. It declares the app with defineSlop: its title, description, author, categories, initial window size, theme colors and a new document’s values. Its explicit slug identifies the app. The wizard records your author name, and the agent sets the title, description, and categories to match what it builds; you can edit these and the initial window size anytime.
schema.tsdefines document fields;slop.ts’sinitialprovides creation-only values.commands.tsexports named actions shared by the page and CLI; the starter includesaddTask.App.svelterenders and edits the document through typed handles.slop.ts’sthemedeclares the colors people can change.styles.cssowns layout and component styling; import it explicitly fromslop.ts.
Import the editor as view and optional capture components as export and icon. Filenames do not assign roles.
The browser preview edits a disposable copy of the document; refreshing starts a fresh one. Vite watches source changes. Component and CSS updates preserve accepted edits; a change to slop.ts or the modules it imports outside components (such as schema.ts) resets the copy. Test native persistence in a writable document copy.
Turn the starter into a counter
Section titled “Turn the starter into a counter”Replace the starter’s data definition:
import { defineDocument, s } from "hitslop";export default defineDocument({ title: s.text(), count: s.counter() });Then describe the counter in slop.ts. Its initial values must fit the new schema, and its theme declares the colors styles.css uses below:
import { defineSlop } from "hitslop";import schema from "./schema";import App from "./App.svelte";import { countOne } from "./commands";import "./styles.css";
export default defineSlop({ slug: "tiny-counter", view: App, commands: { countOne }, title: "Tiny Counter", description: "Count the small things worth counting.", author: { name: "Your Name" }, categories: ["utilities"], window: { kind: "standard", width: 360, height: 360 }, theme: { surface: "#fff7e6", ink: "#382d24", accent: "#28634b" }, document: schema, initial: { title: "Tiny Counter", count: 0 },});Replace the starter’s commands.ts with a counter action:
import doc from "./schema";
export const countOne = doc.command({ description: "Count one more.", args: {}, run({ tx }) { tx.fields.count.increment(); },});Replace App.svelte with:
<script lang="ts"> import { bindText } from "hitslop/svelte"; import doc from "./schema"; import { countOne } from "./commands";</script><main class="counter"> <input aria-label="Counter title" use:bindText={doc.fields.title} /> <p class="counter-value">{doc.current.count}</p> <button onclick={() => countOne()}> Count one </button></main>Export.svelte:
<script lang="ts"> import doc from "./schema";</script><article class="counter"><h1>{doc.current.title}</h1><p>{doc.current.count}</p></article>Icon.svelte:
<script lang="ts"> import doc from "./schema";</script><strong class="counter-icon">{doc.current.count}</strong>Give it ordinary CSS, using the starter’s declared tokens:
* { box-sizing: border-box; }body { background: var(--slop-surface); color: var(--slop-ink); font-family: system-ui; }.counter { padding: 2rem; text-align: center; }.counter input { width: 100%; font: inherit; }.counter-value { font-size: 4rem; font-variant-numeric: tabular-nums; }.counter button { padding: .8rem 1.2rem; background: var(--slop-accent); color: white; border: 0; border-radius: .5rem; }.counter button:focus-visible { outline: 3px solid var(--slop-ink); outline-offset: 3px; }.counter-icon { font-size: 180px; color: var(--slop-accent); }Build, register, and test persistence
Section titled “Build, register, and test persistence”bun run checkbun run buildbun run registerBuild emits dist/tiny-counter.slop. Register renders its Finder artwork with the Mac app and installs an immutable template in ~/.hitslop/templates. In the Mac app, choose Templates, select your app, and Create a writable copy.
Edit that copy, close immediately after typing, reopen, duplicate it, and export PNG/PDF. Check keyboard focus and a narrower window. Read styling, data and schemas, and icons and exports before expanding the app.