Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,48 @@ reinforce the afrofuturist identity without overwhelming the layout:
- Cards animate in on scroll-reveal (fade-in-up) and on hover (gold border +
glow), respecting `prefers-reduced-motion`.

### Loop states

The boucle label state machine rendered as a progression between "How boucle
works" and "Why boucle" (background `--surface-base`). It makes the
deterministic loop's states β€” the product's most concrete differentiator β€”
visible instead of stated as prose.

- **Content** β€” driven by the `loopStates` content collection (one entry per
state: `order`, `label`, `description`, `type`, `typeLabel`) plus a
`loopStatesHeader` single-file collection for the title/subtitle/aria-label.
All copy is editable from the Sveltia CMS, like every other section.
- **Nine states, in order** β€” `boucle:triage`, `boucle:spec-review`,
`boucle:todo`, `boucle:working`, `boucle:review`, `boucle:approval`,
`boucle:merging`, `boucle:done`, `boucle:human`.
- **Colour coding** (existing tokens only β€” no new colours): autonomous states
use a cyan chip on `--surface-raised` (`--accent-cyan`), human-decision states
use a gold chip (`--accent`), terminal states are muted (`--text-secondary`
chip, struck-through label, dashed border) so they read as exits from the
loop rather than steps in it. A legend with `aria-hidden` swatches reinforces
the colour-meaning mapping; the colour is never the only signal because each
chip also carries a visible `typeLabel` text ("Autonomous" / "Human decides" /
"Terminal" / "Escalation").
- **Each state** renders as a raised `--surface-raised` node with a 6px radius,
a number badge (mono font, type-coloured), a mono label chip, the visible
type label, and a one-line `--text-secondary` description.
- **Layout** β€” mobile-first single column. Below 768px the states stack
vertically with a neutral connector rail running down the left edge through
the number badges; the escalation state (`boucle:human`) is pulled out of
the numbered sequence into its own branch block beneath the list, with a
visible join notch and an "Escalation branch" tag connecting it back to the
main flow. At β‰₯768px the sequence becomes a 2-column grid; at β‰₯1024px a
4-column grid, reading left-to-right, top-to-bottom, with the escalation
branch centred beneath the sequence. The branch is conveyed purely by
layout (join notch + tag), not by a new colour. No horizontal page scroll
at 390px or 1440px.
- **Motion** β€” none. No animation or scroll-triggered reveal on the states
(non-goal); `prefers-reduced-motion` is naturally satisfied.
- **Accessibility** β€” a semantic section element with an aria-label, an
ordered list for the sequence, each chip's label + `typeLabel` as readable
text, and the legend `aria-hidden` so screen readers get the sequence from
the ordered list rather than duplicated swatch text.

### Quick start

- Minimal: a single `curl -fsSL https://boucle.dev/install.sh | bash` oneliner.
Expand Down
39 changes: 39 additions & 0 deletions public/admin/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,45 @@ collections:
widget: image
hint: Pick the card icon SVG from the Assets library, e.g. /icons/card-1.svg.

# ---------- Loop states header (single file) ----------
- name: loopStatesHeader
label: Loop states β€” header
label_singular: Loop states
description: '"Loop states" section title, subtitle, and aria-label.'
files:
- name: loop-states-header
label: Loop states header
file: src/content/loop-states-header/loop-states-header.md
fields:
- { name: title, label: Title, widget: string }
- { name: sub, label: Subtitle, widget: text }
- { name: ariaLabel, label: Section aria-label, widget: string }

# ---------- Loop states (label state machine) ----------
- name: loopStates
label: Loop states
label_singular: Loop state
description: The boucle label state machine. Each state has a label chip,
a one-line description, and a type that drives its colour treatment
(autonomous = cyan, human = gold, terminal = muted exit).
folder: src/content/loop-states
extension: md
format: frontmatter
create: true
slug: "{{slug}}"
fields:
- { name: order, label: Order, widget: number, value_type: int }
- { name: label, label: Label chip, widget: string }
- { name: description, label: Description, widget: text }
- name: type
label: Type
widget: select
options:
- { label: Autonomous, value: autonomous }
- { label: Human decides, value: human }
- { label: Terminal, value: terminal }
- { name: typeLabel, label: Type label (visible text), widget: string }

# ---------- Quick start (single file) ----------
- name: quickStart
label: Quick start
Expand Down
25 changes: 25 additions & 0 deletions src/content.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,29 @@ const cards = defineCollection({
}),
});

// Loop states section header: title, subtitle, and aria-label.
const loopStatesHeader = defineCollection({
loader: glob({ pattern: '**/*.md', base: './src/content/loop-states-header' }),
schema: z.object({
title: z.string(),
sub: z.string(),
ariaLabel: z.string(),
}),
});

// The label state machine: one entry per state. `type` drives the visual
// treatment (autonomous = cyan, human = gold, terminal = muted exit).
const loopStates = defineCollection({
loader: glob({ pattern: '**/*.md', base: './src/content/loop-states' }),
schema: z.object({
order: z.number().int().positive(),
label: z.string(),
description: z.string(),
type: z.enum(['autonomous', 'human', 'terminal']),
typeLabel: z.string(),
}),
});

// Quick start section: toggle, install/prompt code, transition, docs link.
const quickStart = defineCollection({
loader: glob({ pattern: '**/*.md', base: './src/content/quick-start' }),
Expand Down Expand Up @@ -157,6 +180,8 @@ export const collections = {
steps,
whyBoucle,
cards,
loopStatesHeader,
loopStates,
quickStart,
footer,
};
5 changes: 5 additions & 0 deletions src/content/loop-states-header/loop-states-header.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
title: The loop, state by state
sub: A label on your issue tells you exactly where the loop is β€” and when it's your turn to decide.
ariaLabel: The boucle label state machine β€” autonomous states in cyan, human-decision states in gold, terminal states marked as exits.
---
7 changes: 7 additions & 0 deletions src/content/loop-states/state-1-triage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
order: 1
label: boucle:triage
description: boucle reads your issue and classifies it before starting any work.
type: autonomous
typeLabel: Autonomous
---
7 changes: 7 additions & 0 deletions src/content/loop-states/state-2-spec-review.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
order: 2
label: boucle:spec-review
description: boucle drafts a spec and preview. You decide β€” approve or amend.
type: human
typeLabel: Human decides
---
7 changes: 7 additions & 0 deletions src/content/loop-states/state-3-todo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
order: 3
label: boucle:todo
description: The approved spec is queued and ready for the worker to pick up.
type: autonomous
typeLabel: Autonomous
---
7 changes: 7 additions & 0 deletions src/content/loop-states/state-4-working.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
order: 4
label: boucle:working
description: The worker implements the issue, committing as it goes.
type: autonomous
typeLabel: Autonomous
---
7 changes: 7 additions & 0 deletions src/content/loop-states/state-5-review.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
order: 5
label: boucle:review
description: The reviewer checks the change against the spec and your amendments.
type: autonomous
typeLabel: Autonomous
---
7 changes: 7 additions & 0 deletions src/content/loop-states/state-6-approval.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
order: 6
label: boucle:approval
description: boucle opens a PR for you to review. You decide β€” approve or send it back.
type: human
typeLabel: Human decides
---
7 changes: 7 additions & 0 deletions src/content/loop-states/state-7-merging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
order: 7
label: boucle:merging
description: On approval, boucle rebases and merges your feature into main.
type: autonomous
typeLabel: Autonomous
---
7 changes: 7 additions & 0 deletions src/content/loop-states/state-8-done.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
order: 8
label: boucle:done
description: Shipped. Your feature is live and the loop moves on.
type: terminal
typeLabel: Terminal
---
7 changes: 7 additions & 0 deletions src/content/loop-states/state-9-human.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
order: 9
label: boucle:human
description: An escalation hands the issue back to you. The loop stops here.
type: terminal
typeLabel: Escalation
---
Loading