81 lines
3.4 KiB
TypeScript

import { create } from 'zustand'
import { FLOWER_PRESETS } from './flower-presets'
import type { FlowerPreset } from './flower-schema'
import { GRASS_PRESETS } from './grass-presets'
import type { GrassPreset } from './grass-schema'
import { defaultHeightOf, TREE_PRESETS } from './presets'
import type { TreePreset, TreeSize } from './schema'
/**
* The plugin's own module-level state — the example of "plugins self-manage
* runtime state with module-level stores" from the plugin-authoring contract.
* It holds the placement "brush": what the next planted tree/flower looks like.
* The presets panel writes it; the placement tool reads it. No host lifecycle
* slot. Colours are intentionally absent — they're edit-only (inspector).
*/
/** Which section of the Nature panel is showing. */
export type TreesPanelMode = 'trees' | 'flowers' | 'grass'
type TreesStore = {
/** Active panel section — in the store (not panel-local state) so the host's
* "find in catalog" can land on the right section (see `find-sync.ts`). */
mode: TreesPanelMode
setMode: (mode: TreesPanelMode) => void
preset: TreePreset
size: TreeSize
/** Height (m) of the next tree — a per-instance scale, never affects placed trees. */
height: number
/** Leaf-count multiplier vs the preset (folded into the instancing variant). */
foliageDensity: number
/** Branch-radius multiplier (folded into the instancing variant). */
trunkThickness: number
/** Plant bare (leafless) trees. */
leafless: boolean
setPreset: (preset: TreePreset) => void
setSize: (size: TreeSize) => void
setHeight: (height: number) => void
setFoliageDensity: (value: number) => void
setTrunkThickness: (value: number) => void
setLeafless: (value: boolean) => void
// Flower brush (sibling kind).
flowerPreset: FlowerPreset
flowerHeight: number
setFlowerPreset: (preset: FlowerPreset) => void
setFlowerHeight: (height: number) => void
// Grass brush (sibling kind).
grassPreset: GrassPreset
grassHeight: number
setGrassPreset: (preset: GrassPreset) => void
setGrassHeight: (height: number) => void
}
export const useTreesStore = create<TreesStore>((set, get) => ({
mode: 'trees',
setMode: (mode) => set({ mode }),
preset: 'oak',
size: 'medium',
height: TREE_PRESETS.oak.height.medium,
foliageDensity: 1,
trunkThickness: 1,
leafless: false,
// Switching preset/size re-seeds the height to that combo's natural default;
// the foliage/trunk brush settings carry over. Growth model comes from the
// preset (oak → deciduous, pine → evergreen); override per-tree in the inspector.
setPreset: (preset) => set({ preset, height: defaultHeightOf(preset, get().size) }),
setSize: (size) => set({ size, height: defaultHeightOf(get().preset, size) }),
setHeight: (height) => set({ height }),
setFoliageDensity: (foliageDensity) => set({ foliageDensity }),
setTrunkThickness: (trunkThickness) => set({ trunkThickness }),
setLeafless: (leafless) => set({ leafless }),
flowerPreset: 'daisy',
flowerHeight: FLOWER_PRESETS.daisy.defaultHeight,
setFlowerPreset: (flowerPreset) =>
set({ flowerPreset, flowerHeight: FLOWER_PRESETS[flowerPreset].defaultHeight }),
setFlowerHeight: (flowerHeight) => set({ flowerHeight }),
grassPreset: 'meadow',
grassHeight: GRASS_PRESETS.meadow.defaultHeight,
setGrassPreset: (grassPreset) =>
set({ grassPreset, grassHeight: GRASS_PRESETS[grassPreset].defaultHeight }),
setGrassHeight: (grassHeight) => set({ grassHeight }),
}))