sprout-garden-plot-types
Sprout Garden: Plot Types
The vocabulary of transformation. Each plot does ONE thing.
Core Concept
Every plot follows the same pattern:
SEED → GROW → FRUIT- Seed: What arrives (the input)
- Grow: The transformation (what this plot does)
- Fruit: What emerges (the output)
Plots differ only in:
- Which directions they accept seeds from
- What transformation they apply
- Which directions they emit fruit to
Phase 1: Foundation Plots
Available from the start. Teach flow and basic transformation.
Vine (→ ↓ ← ↑)
Purpose: Carries sprout without changing it. Defines the path.
| Property | Value |
|---|---|
| Symbol | ➡️ ⬇️ ⬅️ ⬆️ |
| Seeds from | Opposite of pointing direction + perpendiculars |
| Fruits to | Pointing direction |
| Grows | Pass-through (no change) |
| Interaction | Tap to rotate 90° clockwise |
{
type: 'vine-right',
seeds: ['left', 'up', 'down'],
fruits: ['right'],
grow: (sprout) => sprout,
next: 'vine-down' // rotation cycle
}Teaching: Flow, direction, path planning
Form Grower (⚙️)
Purpose: Ripens the shape by one step in the cycle.
| Property | Value |
|---|---|
| Symbol | ⚙️ |
| Seeds from | All four directions |
| Fruits to | Pass-through (same direction it came from) |
| Grows | shape = next in cycle |
Cycle: ● circle → ■ square → ▲ triangle → ★ star → ● circle
{
type: 'form-grower',
seeds: ['left', 'right', 'up', 'down'],
fruits: ['pass-through'],
grow: (sprout) => ({
...sprout,
shape: SHAPE_CYCLE[(SHAPE_CYCLE.indexOf(sprout.shape) + 1) % 4]
})
}Teaching: Sequential transformation, cycles, modular arithmetic
Color Bloomer (🎨)
Purpose: Blooms the color by one step in the cycle.
| Property | Value |
|---|---|
| Symbol | 🎨 |
| Seeds from | All four directions |
| Fruits to | Pass-through |
| Grows | color = next in cycle |
Cycle: 🔴 red → 🟢 green → 🔵 blue → 🟡 yellow → 🔴 red
{
type: 'color-bloomer',
seeds: ['left', 'right', 'up', 'down'],
fruits: ['pass-through'],
grow: (sprout) => ({
...sprout,
color: COLOR_CYCLE[(COLOR_CYCLE.indexOf(sprout.color) + 1) % 4]
})
}Teaching: Independent transformations, multiple properties
Spring (🌱)
Purpose: Source. Emits new sprouts into the garden.
| Property | Value |
|---|---|
| Symbol | 🌱 |
| Seeds from | None (pure source) |
| Fruits to | All four directions (connects to adjacent vines/plots) |
| Grows | Creates sprout from config |
{
type: 'spring',
seeds: [],
fruits: ['right', 'left', 'up', 'down'],
config: {
emits: { shape: 'circle', color: 'red' },
mode: 'single', // single | burst | timed | continuous
count: 1
}
}Teaching: Sources, initial state
Harvest (🎯)
Purpose: Sink. Collects sprouts that arrive.
| Property | Value |
|---|---|
| Symbol | 🎯 |
| Seeds from | All four directions |
| Fruits to | None (terminal) |
| Grows | Collects and validates |
{
type: 'harvest',
seeds: ['left', 'right', 'up', 'down'],
fruits: [],
config: {
expects: { shape: 'star', color: 'green' }, // null = accepts anything
count: 1 // how many needed to complete
}
}Teaching: Goals, success conditions
Weeder (❌)
Purpose: Meta-plot. Removes placed plots (edit tool).
| Property | Value |
|---|---|
| Symbol | ❌ |
| Not a real plot | Edit action |
Teaching: Iteration, experimentation
Phase 2: Imprinting Plots
Unlocked after mastering cycles. Teach direct assignment.
Form Imprinter (● ■ ▲ ★)
Purpose: Stamps a SPECIFIC shape, regardless of input.
| Property | Value |
|---|---|
| Symbols | ●, ■, ▲, ★ (one per shape) |
| Seeds from | All four directions |
| Fruits to | Pass-through |
| Grows | shape = fixed value |
{
type: 'form-imprinter-circle',
symbol: '●',
seeds: ['left', 'right', 'up', 'down'],
fruits: ['pass-through'],
grow: (sprout) => ({ ...sprout, shape: 'circle' })
}Teaching: Assignment vs transformation, constants
Color Imprinter (🔴 🟢 🔵 🟡)
Purpose: Stamps a SPECIFIC color, regardless of input.
| Property | Value |
|---|---|
| Symbols | 🔴, 🟢, 🔵, 🟡 (one per color) |
| Seeds from | All four directions |
| Fruits to | Pass-through |
| Grows | color = fixed value |
Teaching: Same as form imprinter
Phase 3: Gate Plots
Unlocked for conditional logic.
Gate (🚧)
Purpose: Only allows sprouts matching a condition to pass.
| Property | Value |
|---|---|
| Symbol | 🚧 |
| Seeds from | All four directions |
| Fruits to | Pass-through (if condition met) |
| Grows | Pass if condition, otherwise block |
| Blocked behavior | Sprout wilts (💀) or bounces back |
{
type: 'gate',
symbol: '🚧',
condition: { shape: 'star' }, // or { color: 'blue' } or compound
grow: (sprout) => {
if (matches(sprout, this.condition)) {
return sprout; // pass through
}
return null; // blocked - sprout wilts
}
}Gate Variants:
gate-shape-circle- only circles passgate-color-red- only red passesgate-fruit- only stars pass (shape = fruit stage)
Teaching: Conditionals, filtering, constraints
Phase 4: Forking Plots
Unlocked for branching logic.
Fork (⑂)
Purpose: Routes sprout to different outputs based on property.
| Property | Value |
|---|---|
| Symbol | ⑂ |
| Seeds from | One direction (configurable) |
| Fruits to | Two or more directions |
| Grows | Routes based on condition |
{
type: 'fork',
symbol: '⑂',
seeds: ['left'],
routing: {
'up': { color: 'red' }, // red goes up
'down': { color: 'blue' }, // blue goes down
'right': 'default' // everything else goes right
}
}Teaching: Pattern matching, branching, routing
Splitter (⚡)
Purpose: Duplicates sprout to ALL outputs (not conditional).
| Property | Value |
|---|---|
| Symbol | ⚡ |
| Seeds from | One direction |
| Fruits to | Multiple directions |
| Grows | Clones sprout to each output |
{
type: 'splitter',
seeds: ['left'],
fruits: ['up', 'right', 'down'],
grow: (sprout) => [
{ ...sprout, id: uuid() }, // clone 1
{ ...sprout, id: uuid() }, // clone 2
{ ...sprout, id: uuid() } // clone 3
]
}Teaching: One-to-many, parallel paths
Grafter (⊕)
Purpose: Combines multiple inputs into one output.
| Property | Value |
|---|---|
| Symbol | ⊕ |
| Seeds from | Multiple directions (multiple seed slots) |
| Fruits to | One direction |
| Grows | Waits for all seeds, then combines |
{
type: 'grafter',
seeds: ['left', 'up'], // two seed slots
fruits: ['right'],
grow: (seeds) => {
if (seeds.left && seeds.up) {
return combine(seeds.left, seeds.up);
}
return null; // wait for both
}
}Combine modes:
first- output first arrivedmerge- combine propertiesrecipe- specific combination produces specific output
Teaching: Joins, synchronization, AND logic
Phase 5: Logic Trellises
Unlocked for boolean algebra.
AND Trellis (∧)
Purpose: Outputs only if BOTH inputs present.
Same as Grafter with mode = 'both-required'.
OR Trellis (∨)
Purpose: Outputs if EITHER input present.
{
type: 'or-trellis',
seeds: ['left', 'up'],
fruits: ['right'],
grow: (seeds) => seeds.left || seeds.up // first available
}NOT Trellis (¬)
Purpose: Inverts property.
{
type: 'not-trellis',
grow: (sprout) => ({
...sprout,
color: OPPOSITE_COLOR[sprout.color], // red↔green, blue↔yellow
shape: OPPOSITE_SHAPE[sprout.shape] // circle↔star, square↔triangle
})
}XOR Trellis (⊕)
Purpose: Outputs if ONE but not BOTH inputs.
Phase 6: Timing Plots
For synchronization puzzles.
Delay (⏱️)
Purpose: Holds sprout for N ticks before releasing.
| Property | Value |
|---|---|
| Symbols | ⏱️¹, ⏱️², ⏱️³ |
| Seeds from | All directions |
| Fruits to | Pass-through (after delay) |
| Grows | Holds, then releases |
{
type: 'delay-2',
delay_ticks: 2,
held_sprout: null,
held_since: null,
grow: function(sprout, current_tick) {
if (this.held_sprout) {
if (current_tick - this.held_since >= this.delay_ticks) {
const result = this.held_sprout;
this.held_sprout = null;
return result; // release
}
return null; // still holding
}
this.held_sprout = sprout;
this.held_since = current_tick;
return null; // start holding
}
}Teaching: Timing, synchronization, path length compensation
Phase 7: Loop Constructs
For iteration.
Merge (⊕)
Purpose: Entry point for loops. Accepts from outside AND from loop-back.
Check (❓)
Purpose: Condition check. Routes to exit or back to loop.
Counter (+1)
Purpose: Increments a counter property on the sprout.
{
type: 'counter',
grow: (sprout) => ({
...sprout,
count: (sprout.count || 0) + 1
})
}Phase 8: Rabbit Holes
For abstraction/functions.
Rabbit Hole (🌀)
Purpose: Portal to sub-garden. Function call.
| Property | Value |
|---|---|
| Symbol | 🌀 |
| Seeds from | One direction |
| Fruits to | One direction |
| Contains | Full sub-garden |
{
type: 'rabbit-hole',
symbol: '🌀',
seeds: ['left'],
fruits: ['right'],
subgarden: 'triple-ripen', // reference to saved function
grow: (sprout) => executeSubgarden(this.subgarden, sprout)
}Interaction: Click to zoom into sub-garden. Edit it. Zoom back out.
Teaching: Abstraction, composition, functions, recursion
Wanderland Equivalents
| Sprout Garden Plot | Wanderland Fence |
|---|---|
| Vine | Reflex / Arrow |
| Form Grower | Transformer |
| Color Bloomer | Transformer |
| Spring | Source / Watcher |
| Harvest | Sink / Accumulator |
| Gate | Filter / Validator |
| Fork | Router / Pattern Match |
| Grafter | Join / Aggregator |
| Delay | Buffer / Queue |
| Rabbit Hole | Sub-graph / Function |
Same semantics. Different skin.
Implementation Notes
Plot Interface
class Plot {
constructor(type, config = {}) {
this.type = type;
this.config = config;
this.seeds = {}; // { direction: sprout }
this.fruit = null;
}
canReceiveSeed(fromDirection) {
return PLOT_TYPES[this.type].seeds.includes(fromDirection);
}
receiveSeed(sprout, fromDirection) {
this.seeds[fromDirection] = sprout;
}
hasSeed() {
return Object.values(this.seeds).some(s => s !== null);
}
grow() {
// Hot Potato: if we have seeds, process them
const growFn = PLOT_TYPES[this.type].grow;
this.fruit = growFn(this.seeds, this.config);
this.seeds = {}; // consumed
}
getFruitDirections() {
return PLOT_TYPES[this.type].fruits;
}
}Adding New Plot Types
Just add to the registry:
PLOT_TYPES['my-new-plot'] = {
symbol: '🆕',
seeds: ['left', 'right'],
fruits: ['up'],
grow: (seeds) => transform(seeds)
};The engine doesn't change. Just the vocabulary.
Tags
sprout-garden, plot-types, fences, transformations, game-mechanics
Slots
North
slots:
- sprout-gardenSouth
slots: []East
slots: []West
slots: []