KQ-1697 · GOAL/WEAVE

Goal Weave

A goal-selection step whose plan assembles itself: choosing a goal draws a thread out of its card to each of its tasks — the curve split at a growing t on an enter tween, every point rounded — while the tasks arrive from 8px left on springs.glide in a cascade(), and removing a goal retracts its threads and pulls out only the tasks no other goal holds while shared ones stay. The goal cards are checkboxes that lift on springs.snap and follow the arrow keys; plan rows rove with Up and Down, Alt with Up or Down (or a drag of the grip, 1:1 with the release velocity handed to springs.glide) reorders them, and the threads follow every glide from a geometry loop that runs only while something moves.

KQ-1697 · GOAL/WEAVE

Set up your workspace

Pick your goals; the plan assembles itself

2goals

Up and Down move between tasks; Alt with Up or Down moves a task.

What should Fernworks help with?

6 tasks from 2 goals

2 goals · 6 tasks · 1 shared

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/goal-weave

Props

goals
GoalWeaveGoal[]
default defaultGoalWeaveGoals
The goals to choose from, { id, title, detail?, icon?, tint? }.
tasks
GoalWeaveTask[]
default defaultGoalWeaveTasks
Every task a goal can bring, { id, title, minutes?, goals, starter? }; a task in several goals is shared, and starter tasks form the plan while nothing is chosen.
value / defaultValue
string[]
default — / []
The chosen goal ids, controlled or initial. A host change weaves like a press.
onGoalsChange
(ids: string[]) => void
default —
Fires from the card, key or click that changed the goals.
onPlanChange
(taskIds: string[]) => void
default —
Fires with the plan in order whenever goals or a reorder change it.
onAccept
(taskIds: string[], goalIds: string[]) => void
default —
Use this plan was pressed.
cardStyle
"tile" | "chip" | "row"
default "tile"
Two-column tiles with icon, title and detail; compact wrapping chips; or a list of rows with task counts.
threadStyle
"thread" | "stitch" | "ribbon"
default "thread"
A fine 1.5px curve, a dashed stitch, or a soft 6px ribbon.
accent
string
default "var(--accent-bright)"
The first goal's tint (later goals turn its hue 48° each), the chosen cards and the primary button. Any CSS colour.
question
string
default "What should Fernworks help with?"
The question over the goal cards; it also names the checkbox group.
planTitle
string
default "Your first week"
The plan's heading (and the drawer's label on narrow widths).
acceptLabel
string
default "Use this plan"
The primary button's label.
maxGoals
number
default —
The most goals that can be chosen at once; the rest turn aria-disabled with the reason.
status
"ready" | "loading" | "error"
default "ready"
Whether the goals have arrived: loading draws skeleton cards, error a message with Try again.
onRetry
() => void
default —
Try again was pressed after the goals failed to load.
maxHeight
number
default 560
The tallest the step grows before its body scrolls, px.
disabled
boolean
default false
Nothing can be chosen, moved or accepted; the step dims.
className
string
default —
Classes for the outer section.