58 lines
2.9 KiB
TypeScript
58 lines
2.9 KiB
TypeScript
import { BaseNode, nodeType, objectId } from '@pascal-app/core'
|
|
import { z } from 'zod'
|
|
|
|
/** Tree species the plugin can place, each backed by an ez-tree preset family.
|
|
* The string persists in scene JSON. */
|
|
export const TreePreset = z.enum(['oak', 'pine', 'aspen', 'ash', 'bush', 'trellis'])
|
|
export type TreePreset = z.infer<typeof TreePreset>
|
|
|
|
/** Preset size variant. Maps to ez-tree's Small/Medium/Large presets (and
|
|
* Bush 1/2/3); ignored for `trellis`, which has a single preset. */
|
|
export const TreeSize = z.enum(['small', 'medium', 'large'])
|
|
export type TreeSize = z.infer<typeof TreeSize>
|
|
|
|
/** ez-tree's two growth models — deciduous (spreading) vs evergreen (conical). */
|
|
export const TreeType = z.enum(['deciduous', 'evergreen'])
|
|
export type TreeType = z.infer<typeof TreeType>
|
|
|
|
/**
|
|
* Schema for a placed tree. Composed from the public `BaseNode` exactly the way
|
|
* built-in node kinds are — `objectId`/`nodeType` come from `@pascal-app/core`,
|
|
* so a plugin needs no private host internals to mint a persistable node.
|
|
*
|
|
* `type` is the namespaced kind `trees:tree`. Every geometry-relevant field
|
|
* (preset/size/treeType/seed/foliage/trunk/leafless/leafColor/branchColor) is
|
|
* folded into the instancing variant key; `height`/`position`/`rotation` are
|
|
* cheap per-instance transforms.
|
|
*/
|
|
export const TreeNode = BaseNode.extend({
|
|
id: objectId('tree'),
|
|
type: nodeType('trees:tree'),
|
|
position: z.tuple([z.number(), z.number(), z.number()]).default([0, 0, 0]),
|
|
rotation: z.tuple([z.number(), z.number(), z.number()]).default([0, 0, 0]),
|
|
preset: TreePreset.default('oak'),
|
|
size: TreeSize.default('medium'),
|
|
// Overrides — all optional so an unset field inherits the ez-tree preset (its
|
|
// own seed/type/tints), exactly like flower `petalColor`. Placing a tree stores
|
|
// none of these, so a fresh tree is the pure preset; the inspector sets them.
|
|
/** Growth-model override. Unset ⇒ inherit the preset (oak → deciduous, pine → evergreen). */
|
|
treeType: TreeType.optional(),
|
|
height: z.number().positive().default(7),
|
|
/** Geometry-seed override. Unset ⇒ the preset's own seed (its canonical silhouette);
|
|
* set (e.g. via Randomize) to vary the tree. */
|
|
seed: z.number().int().optional(),
|
|
// Curated geometry params (folded into the instancing variant key):
|
|
/** Leaf-count multiplier vs the preset (1 = preset default). */
|
|
foliageDensity: z.number().min(0).max(1.5).default(1),
|
|
/** Branch-radius multiplier (1 = preset default). */
|
|
trunkThickness: z.number().min(0.3).max(2.5).default(1),
|
|
/** Strip all leaves — a bare winter silhouette. */
|
|
leafless: z.boolean().default(false),
|
|
/** Leaf tint override (hex). Unset ⇒ the preset's leaf tint. */
|
|
leafColor: z.string().optional(),
|
|
/** Bark/branch tint override (hex). Unset ⇒ the preset's bark tint. */
|
|
branchColor: z.string().optional(),
|
|
})
|
|
|
|
export type TreeNode = z.infer<typeof TreeNode>
|