@autumnsgrove/groveengine 0.7.0 → 0.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (230) hide show
  1. package/dist/components/OnboardingChecklist.svelte +2 -2
  2. package/dist/components/WispButton.svelte +83 -0
  3. package/dist/components/WispButton.svelte.d.ts +49 -0
  4. package/dist/components/WispPanel.svelte +1093 -0
  5. package/dist/components/WispPanel.svelte.d.ts +49 -0
  6. package/dist/components/custom/TableOfContents.svelte +12 -1
  7. package/dist/components/quota/UpgradePrompt.svelte +1 -0
  8. package/dist/config/wisp.d.ts +145 -0
  9. package/dist/config/wisp.js +175 -0
  10. package/dist/index.d.ts +2 -0
  11. package/dist/index.js +3 -0
  12. package/dist/server/inference-client.d.ts +139 -0
  13. package/dist/server/inference-client.js +294 -0
  14. package/dist/ui/components/content/RoadmapPreview.svelte +91 -0
  15. package/dist/ui/components/content/RoadmapPreview.svelte.d.ts +36 -0
  16. package/dist/ui/components/content/index.d.ts +1 -0
  17. package/dist/ui/components/content/index.js +1 -0
  18. package/dist/ui/components/nature/Logo.svelte +260 -0
  19. package/dist/ui/components/nature/Logo.svelte.d.ts +14 -0
  20. package/dist/ui/components/nature/botanical/Acorn.svelte +48 -0
  21. package/dist/ui/components/nature/botanical/Acorn.svelte.d.ts +8 -0
  22. package/dist/ui/components/nature/botanical/Berry.svelte +67 -0
  23. package/dist/ui/components/nature/botanical/Berry.svelte.d.ts +8 -0
  24. package/dist/ui/components/nature/botanical/DandelionPuff.svelte +98 -0
  25. package/dist/ui/components/nature/botanical/DandelionPuff.svelte.d.ts +8 -0
  26. package/dist/ui/components/nature/botanical/FallingLeavesLayer.svelte +170 -0
  27. package/dist/ui/components/nature/botanical/FallingLeavesLayer.svelte.d.ts +35 -0
  28. package/dist/ui/components/nature/botanical/FallingPetalsLayer.svelte +174 -0
  29. package/dist/ui/components/nature/botanical/FallingPetalsLayer.svelte.d.ts +25 -0
  30. package/dist/ui/components/nature/botanical/Leaf.svelte +77 -0
  31. package/dist/ui/components/nature/botanical/Leaf.svelte.d.ts +10 -0
  32. package/dist/ui/components/nature/botanical/LeafFalling.svelte +186 -0
  33. package/dist/ui/components/nature/botanical/LeafFalling.svelte.d.ts +22 -0
  34. package/dist/ui/components/nature/botanical/PetalFalling.svelte +266 -0
  35. package/dist/ui/components/nature/botanical/PetalFalling.svelte.d.ts +25 -0
  36. package/dist/ui/components/nature/botanical/PineCone.svelte +61 -0
  37. package/dist/ui/components/nature/botanical/PineCone.svelte.d.ts +7 -0
  38. package/dist/ui/components/nature/botanical/Vine.svelte +102 -0
  39. package/dist/ui/components/nature/botanical/Vine.svelte.d.ts +11 -0
  40. package/dist/ui/components/nature/botanical/index.d.ts +10 -0
  41. package/dist/ui/components/nature/botanical/index.js +11 -0
  42. package/dist/ui/components/nature/creatures/Bee.svelte +78 -0
  43. package/dist/ui/components/nature/creatures/Bee.svelte.d.ts +9 -0
  44. package/dist/ui/components/nature/creatures/Bird.svelte +94 -0
  45. package/dist/ui/components/nature/creatures/Bird.svelte.d.ts +11 -0
  46. package/dist/ui/components/nature/creatures/BirdFlying.svelte +83 -0
  47. package/dist/ui/components/nature/creatures/BirdFlying.svelte.d.ts +9 -0
  48. package/dist/ui/components/nature/creatures/Bluebird.svelte +95 -0
  49. package/dist/ui/components/nature/creatures/Bluebird.svelte.d.ts +12 -0
  50. package/dist/ui/components/nature/creatures/Butterfly.svelte +87 -0
  51. package/dist/ui/components/nature/creatures/Butterfly.svelte.d.ts +9 -0
  52. package/dist/ui/components/nature/creatures/Cardinal.svelte +95 -0
  53. package/dist/ui/components/nature/creatures/Cardinal.svelte.d.ts +12 -0
  54. package/dist/ui/components/nature/creatures/Chickadee.svelte +97 -0
  55. package/dist/ui/components/nature/creatures/Chickadee.svelte.d.ts +12 -0
  56. package/dist/ui/components/nature/creatures/Deer.svelte +95 -0
  57. package/dist/ui/components/nature/creatures/Deer.svelte.d.ts +9 -0
  58. package/dist/ui/components/nature/creatures/Firefly.svelte +111 -0
  59. package/dist/ui/components/nature/creatures/Firefly.svelte.d.ts +10 -0
  60. package/dist/ui/components/nature/creatures/Owl.svelte +91 -0
  61. package/dist/ui/components/nature/creatures/Owl.svelte.d.ts +9 -0
  62. package/dist/ui/components/nature/creatures/Rabbit.svelte +90 -0
  63. package/dist/ui/components/nature/creatures/Rabbit.svelte.d.ts +9 -0
  64. package/dist/ui/components/nature/creatures/Robin.svelte +98 -0
  65. package/dist/ui/components/nature/creatures/Robin.svelte.d.ts +12 -0
  66. package/dist/ui/components/nature/creatures/Squirrel.svelte +97 -0
  67. package/dist/ui/components/nature/creatures/Squirrel.svelte.d.ts +9 -0
  68. package/dist/ui/components/nature/creatures/index.d.ts +13 -0
  69. package/dist/ui/components/nature/creatures/index.js +14 -0
  70. package/dist/ui/components/nature/ground/Bush.svelte +57 -0
  71. package/dist/ui/components/nature/ground/Bush.svelte.d.ts +10 -0
  72. package/dist/ui/components/nature/ground/Crocus.svelte +83 -0
  73. package/dist/ui/components/nature/ground/Crocus.svelte.d.ts +12 -0
  74. package/dist/ui/components/nature/ground/Daffodil.svelte +75 -0
  75. package/dist/ui/components/nature/ground/Daffodil.svelte.d.ts +11 -0
  76. package/dist/ui/components/nature/ground/Fern.svelte +72 -0
  77. package/dist/ui/components/nature/ground/Fern.svelte.d.ts +10 -0
  78. package/dist/ui/components/nature/ground/FlowerWild.svelte +60 -0
  79. package/dist/ui/components/nature/ground/FlowerWild.svelte.d.ts +10 -0
  80. package/dist/ui/components/nature/ground/GrassTuft.svelte +49 -0
  81. package/dist/ui/components/nature/ground/GrassTuft.svelte.d.ts +10 -0
  82. package/dist/ui/components/nature/ground/Log.svelte +42 -0
  83. package/dist/ui/components/nature/ground/Log.svelte.d.ts +7 -0
  84. package/dist/ui/components/nature/ground/Mushroom.svelte +48 -0
  85. package/dist/ui/components/nature/ground/Mushroom.svelte.d.ts +9 -0
  86. package/dist/ui/components/nature/ground/MushroomCluster.svelte +41 -0
  87. package/dist/ui/components/nature/ground/MushroomCluster.svelte.d.ts +8 -0
  88. package/dist/ui/components/nature/ground/Rock.svelte +59 -0
  89. package/dist/ui/components/nature/ground/Rock.svelte.d.ts +8 -0
  90. package/dist/ui/components/nature/ground/Stump.svelte +44 -0
  91. package/dist/ui/components/nature/ground/Stump.svelte.d.ts +8 -0
  92. package/dist/ui/components/nature/ground/Tulip.svelte +79 -0
  93. package/dist/ui/components/nature/ground/Tulip.svelte.d.ts +11 -0
  94. package/dist/ui/components/nature/ground/index.d.ts +12 -0
  95. package/dist/ui/components/nature/ground/index.js +13 -0
  96. package/dist/ui/components/nature/index.d.ts +28 -0
  97. package/dist/ui/components/nature/index.js +38 -0
  98. package/dist/ui/components/nature/palette.d.ts +602 -0
  99. package/dist/ui/components/nature/palette.js +472 -0
  100. package/dist/ui/components/nature/sky/Cloud.svelte +122 -0
  101. package/dist/ui/components/nature/sky/Cloud.svelte.d.ts +11 -0
  102. package/dist/ui/components/nature/sky/CloudWispy.svelte +79 -0
  103. package/dist/ui/components/nature/sky/CloudWispy.svelte.d.ts +9 -0
  104. package/dist/ui/components/nature/sky/Moon.svelte +60 -0
  105. package/dist/ui/components/nature/sky/Moon.svelte.d.ts +9 -0
  106. package/dist/ui/components/nature/sky/Rainbow.svelte +101 -0
  107. package/dist/ui/components/nature/sky/Rainbow.svelte.d.ts +8 -0
  108. package/dist/ui/components/nature/sky/Star.svelte +84 -0
  109. package/dist/ui/components/nature/sky/Star.svelte.d.ts +10 -0
  110. package/dist/ui/components/nature/sky/StarCluster.svelte +85 -0
  111. package/dist/ui/components/nature/sky/StarCluster.svelte.d.ts +9 -0
  112. package/dist/ui/components/nature/sky/StarShooting.svelte +90 -0
  113. package/dist/ui/components/nature/sky/StarShooting.svelte.d.ts +9 -0
  114. package/dist/ui/components/nature/sky/Sun.svelte +70 -0
  115. package/dist/ui/components/nature/sky/Sun.svelte.d.ts +9 -0
  116. package/dist/ui/components/nature/sky/index.d.ts +8 -0
  117. package/dist/ui/components/nature/sky/index.js +9 -0
  118. package/dist/ui/components/nature/structural/Birdhouse.svelte +53 -0
  119. package/dist/ui/components/nature/structural/Birdhouse.svelte.d.ts +8 -0
  120. package/dist/ui/components/nature/structural/Bridge.svelte +65 -0
  121. package/dist/ui/components/nature/structural/Bridge.svelte.d.ts +7 -0
  122. package/dist/ui/components/nature/structural/FencePost.svelte +54 -0
  123. package/dist/ui/components/nature/structural/FencePost.svelte.d.ts +8 -0
  124. package/dist/ui/components/nature/structural/GardenGate.svelte +70 -0
  125. package/dist/ui/components/nature/structural/GardenGate.svelte.d.ts +8 -0
  126. package/dist/ui/components/nature/structural/Lantern.svelte +113 -0
  127. package/dist/ui/components/nature/structural/Lantern.svelte.d.ts +10 -0
  128. package/dist/ui/components/nature/structural/Lattice.svelte +89 -0
  129. package/dist/ui/components/nature/structural/Lattice.svelte.d.ts +8 -0
  130. package/dist/ui/components/nature/structural/LatticeWithVine.svelte +89 -0
  131. package/dist/ui/components/nature/structural/LatticeWithVine.svelte.d.ts +11 -0
  132. package/dist/ui/components/nature/structural/StonePath.svelte +48 -0
  133. package/dist/ui/components/nature/structural/StonePath.svelte.d.ts +7 -0
  134. package/dist/ui/components/nature/structural/index.d.ts +8 -0
  135. package/dist/ui/components/nature/structural/index.js +9 -0
  136. package/dist/ui/components/nature/trees/TreeAspen.svelte +163 -0
  137. package/dist/ui/components/nature/trees/TreeAspen.svelte.d.ts +11 -0
  138. package/dist/ui/components/nature/trees/TreeBirch.svelte +186 -0
  139. package/dist/ui/components/nature/trees/TreeBirch.svelte.d.ts +11 -0
  140. package/dist/ui/components/nature/trees/TreeCherry.svelte +108 -0
  141. package/dist/ui/components/nature/trees/TreeCherry.svelte.d.ts +11 -0
  142. package/dist/ui/components/nature/trees/TreePine.svelte +79 -0
  143. package/dist/ui/components/nature/trees/TreePine.svelte.d.ts +11 -0
  144. package/dist/ui/components/nature/trees/index.d.ts +4 -0
  145. package/dist/ui/components/nature/trees/index.js +5 -0
  146. package/dist/ui/components/nature/water/LilyPad.svelte +99 -0
  147. package/dist/ui/components/nature/water/LilyPad.svelte.d.ts +10 -0
  148. package/dist/ui/components/nature/water/Pond.svelte +104 -0
  149. package/dist/ui/components/nature/water/Pond.svelte.d.ts +8 -0
  150. package/dist/ui/components/nature/water/Reeds.svelte +85 -0
  151. package/dist/ui/components/nature/water/Reeds.svelte.d.ts +11 -0
  152. package/dist/ui/components/nature/water/Stream.svelte +98 -0
  153. package/dist/ui/components/nature/water/Stream.svelte.d.ts +8 -0
  154. package/dist/ui/components/nature/water/index.d.ts +4 -0
  155. package/dist/ui/components/nature/water/index.js +5 -0
  156. package/dist/ui/components/nature/weather/SnowfallLayer.svelte +175 -0
  157. package/dist/ui/components/nature/weather/SnowfallLayer.svelte.d.ts +25 -0
  158. package/dist/ui/components/nature/weather/Snowflake.svelte +99 -0
  159. package/dist/ui/components/nature/weather/Snowflake.svelte.d.ts +11 -0
  160. package/dist/ui/components/nature/weather/SnowflakeFalling.svelte +162 -0
  161. package/dist/ui/components/nature/weather/SnowflakeFalling.svelte.d.ts +23 -0
  162. package/dist/ui/components/nature/weather/index.d.ts +3 -0
  163. package/dist/ui/components/nature/weather/index.js +4 -0
  164. package/dist/ui/components/primitives/textarea/textarea.svelte +1 -1
  165. package/dist/ui/components/typography/Alagard.svelte +17 -0
  166. package/dist/ui/components/typography/Alagard.svelte.d.ts +10 -0
  167. package/dist/ui/components/typography/Atkinson.svelte +17 -0
  168. package/dist/ui/components/typography/Atkinson.svelte.d.ts +10 -0
  169. package/dist/ui/components/typography/BodoniModa.svelte +17 -0
  170. package/dist/ui/components/typography/BodoniModa.svelte.d.ts +10 -0
  171. package/dist/ui/components/typography/Calistoga.svelte +17 -0
  172. package/dist/ui/components/typography/Calistoga.svelte.d.ts +10 -0
  173. package/dist/ui/components/typography/Caveat.svelte +17 -0
  174. package/dist/ui/components/typography/Caveat.svelte.d.ts +10 -0
  175. package/dist/ui/components/typography/Cormorant.svelte +17 -0
  176. package/dist/ui/components/typography/Cormorant.svelte.d.ts +10 -0
  177. package/dist/ui/components/typography/Cozette.svelte +17 -0
  178. package/dist/ui/components/typography/Cozette.svelte.d.ts +10 -0
  179. package/dist/ui/components/typography/EBGaramond.svelte +17 -0
  180. package/dist/ui/components/typography/EBGaramond.svelte.d.ts +10 -0
  181. package/dist/ui/components/typography/FontProvider.svelte +98 -0
  182. package/dist/ui/components/typography/FontProvider.svelte.d.ts +17 -0
  183. package/dist/ui/components/typography/Fraunces.svelte +17 -0
  184. package/dist/ui/components/typography/Fraunces.svelte.d.ts +10 -0
  185. package/dist/ui/components/typography/IBMPlexMono.svelte +17 -0
  186. package/dist/ui/components/typography/IBMPlexMono.svelte.d.ts +10 -0
  187. package/dist/ui/components/typography/InstrumentSans.svelte +17 -0
  188. package/dist/ui/components/typography/InstrumentSans.svelte.d.ts +10 -0
  189. package/dist/ui/components/typography/Lexend.svelte +17 -0
  190. package/dist/ui/components/typography/Lexend.svelte.d.ts +10 -0
  191. package/dist/ui/components/typography/Lora.svelte +17 -0
  192. package/dist/ui/components/typography/Lora.svelte.d.ts +10 -0
  193. package/dist/ui/components/typography/Luciole.svelte +17 -0
  194. package/dist/ui/components/typography/Luciole.svelte.d.ts +10 -0
  195. package/dist/ui/components/typography/Manrope.svelte +17 -0
  196. package/dist/ui/components/typography/Manrope.svelte.d.ts +10 -0
  197. package/dist/ui/components/typography/Merriweather.svelte +17 -0
  198. package/dist/ui/components/typography/Merriweather.svelte.d.ts +10 -0
  199. package/dist/ui/components/typography/Nunito.svelte +17 -0
  200. package/dist/ui/components/typography/Nunito.svelte.d.ts +10 -0
  201. package/dist/ui/components/typography/OpenDyslexic.svelte +17 -0
  202. package/dist/ui/components/typography/OpenDyslexic.svelte.d.ts +10 -0
  203. package/dist/ui/components/typography/PlusJakartaSans.svelte +17 -0
  204. package/dist/ui/components/typography/PlusJakartaSans.svelte.d.ts +10 -0
  205. package/dist/ui/components/typography/Quicksand.svelte +17 -0
  206. package/dist/ui/components/typography/Quicksand.svelte.d.ts +10 -0
  207. package/dist/ui/components/typography/README.md +153 -0
  208. package/dist/ui/components/typography/index.d.ts +23 -0
  209. package/dist/ui/components/typography/index.js +42 -0
  210. package/dist/ui/components/ui/GlassCarousel.svelte +446 -0
  211. package/dist/ui/components/ui/GlassCarousel.svelte.d.ts +57 -0
  212. package/dist/ui/components/ui/GlassConfirmDialog.svelte +2 -1
  213. package/dist/ui/components/ui/GlassLogo.svelte +423 -0
  214. package/dist/ui/components/ui/GlassLogo.svelte.d.ts +23 -0
  215. package/dist/ui/components/ui/GlassNavbar.svelte +120 -0
  216. package/dist/ui/components/ui/GlassNavbar.svelte.d.ts +42 -0
  217. package/dist/ui/components/ui/GlassOverlay.svelte +1 -1
  218. package/dist/ui/components/ui/Logo.svelte +47 -52
  219. package/dist/ui/components/ui/Logo.svelte.d.ts +4 -3
  220. package/dist/ui/components/ui/index.d.ts +3 -0
  221. package/dist/ui/components/ui/index.js +3 -0
  222. package/dist/ui/index.d.ts +1 -0
  223. package/dist/ui/index.js +2 -0
  224. package/dist/ui/styles/grove.css +15 -1
  225. package/dist/ui/vineyard/index.d.ts +9 -0
  226. package/dist/ui/vineyard/index.js +8 -0
  227. package/dist/utils/csrf.js +5 -2
  228. package/dist/utils/readability.d.ts +89 -0
  229. package/dist/utils/readability.js +204 -0
  230. package/package.json +27 -1
@@ -0,0 +1,163 @@
1
+ <!--
2
+ Grove — A place to Be
3
+ Copyright (c) 2025 Autumn Brown
4
+ Licensed under AGPL-3.0
5
+ -->
6
+ <script lang="ts">
7
+ import type { Season } from '../palette';
8
+ import { autumn, greens, winter } from '../palette';
9
+
10
+ interface Props {
11
+ class?: string;
12
+ color?: string;
13
+ trunkColor?: string;
14
+ season?: Season;
15
+ animate?: boolean;
16
+ }
17
+
18
+ let {
19
+ class: className = 'w-6 h-6',
20
+ color,
21
+ trunkColor,
22
+ season = 'summer',
23
+ animate = true
24
+ }: Props = $props();
25
+
26
+ // Check if tree should be bare (winter)
27
+ const isBare = $derived(season === 'winter');
28
+
29
+ // Aspen turns brilliant gold/yellow in autumn
30
+ // Use $derived to react to season/color prop changes
31
+ const defaultColor = $derived(season === 'autumn' ? autumn.gold : 'currentColor');
32
+ const foliageColor = $derived(color ?? defaultColor);
33
+
34
+ // Aspen bark is pale cream/greenish-white with dark marks
35
+ // In winter, bark takes on a slightly frosted appearance
36
+ const actualTrunkColor = $derived(
37
+ trunkColor ?? (season === 'winter' ? winter.frost : '#e8e4d9')
38
+ );
39
+ const barkMarkColor = $derived(season === 'winter' ? '#5a5a5a' : '#4a4a4a');
40
+
41
+ // Slightly darker shade for leaf depth
42
+ const leafShadow = $derived(season === 'autumn' ? autumn.amber : greens.grove);
43
+ </script>
44
+
45
+ <!-- Aspen tree - slender trunk with quivering round/heart-shaped leaves -->
46
+ <svg class={className} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 140">
47
+ <!-- Trunk - slender with characteristic bark marks -->
48
+ <rect fill={actualTrunkColor} x="46" y="60" width="8" height="80" rx="2" />
49
+
50
+ <!-- Bark marks (aspen "eyes") -->
51
+ <ellipse fill={barkMarkColor} cx="49" cy="78" rx="2" ry="1" opacity="0.6" />
52
+ <ellipse fill={barkMarkColor} cx="51" cy="98" rx="2.5" ry="1" opacity="0.5" />
53
+ <ellipse fill={barkMarkColor} cx="48" cy="118" rx="2" ry="1" opacity="0.6" />
54
+
55
+ <!-- Upper branches hint - visible year-round -->
56
+ <path fill={actualTrunkColor} d="M50 60 Q44 55 38 58 L42 52 Q47 54 50 55 Z" />
57
+ <path fill={actualTrunkColor} d="M50 60 Q56 55 62 58 L58 52 Q53 54 50 55 Z" />
58
+
59
+ <!-- Extended bare branches visible in winter -->
60
+ {#if isBare}
61
+ <path fill="none" stroke={actualTrunkColor} stroke-width="2" d="M42 52 Q32 42 22 38" />
62
+ <path fill="none" stroke={actualTrunkColor} stroke-width="2" d="M58 52 Q68 42 78 38" />
63
+ <path fill="none" stroke={actualTrunkColor} stroke-width="1.5" d="M22 38 Q18 32 20 25" />
64
+ <path fill="none" stroke={actualTrunkColor} stroke-width="1.5" d="M22 38 Q28 30 32 22" />
65
+ <path fill="none" stroke={actualTrunkColor} stroke-width="1.5" d="M78 38 Q82 32 80 25" />
66
+ <path fill="none" stroke={actualTrunkColor} stroke-width="1.5" d="M78 38 Q72 30 68 22" />
67
+ <path fill="none" stroke={actualTrunkColor} stroke-width="1" d="M50 55 Q50 35 50 18" />
68
+ <path fill="none" stroke={actualTrunkColor} stroke-width="1" d="M50 28 Q44 20 38 15" />
69
+ <path fill="none" stroke={actualTrunkColor} stroke-width="1" d="M50 28 Q56 20 62 15" />
70
+ <!-- Snow accents on branches -->
71
+ <ellipse fill={winter.snow} cx="22" cy="37" rx="4" ry="1.5" opacity="0.8" />
72
+ <ellipse fill={winter.snow} cx="78" cy="37" rx="4" ry="1.5" opacity="0.8" />
73
+ <ellipse fill={winter.snow} cx="50" cy="17" rx="3" ry="1" opacity="0.7" />
74
+ {/if}
75
+
76
+ <!-- Individual aspen leaves - round/heart shaped with pointed tips -->
77
+ <!-- Each group quivers independently like real aspen leaves -->
78
+ <!-- Hidden in winter when tree is bare -->
79
+
80
+ {#if !isBare}
81
+ <!-- Left branch cluster -->
82
+ <g class={animate ? 'quiver quiver-1' : ''}>
83
+ <!-- Round leaves with pointed tips - characteristic aspen shape -->
84
+ <path fill={foliageColor} d="M22 40 Q16 36 16 32 Q16 28 22 28 Q28 28 28 32 Q28 36 22 40 Z" />
85
+ <path fill={foliageColor} d="M28 32 Q23 29 23 26 Q23 22 28 22 Q33 22 33 26 Q33 29 28 32 Z" />
86
+ <path fill={foliageColor} d="M18 32 Q13 29 13 26 Q13 22 18 22 Q23 22 23 26 Q23 29 18 32 Z" />
87
+ <path fill={foliageColor} d="M25 45 Q20 42 20 39 Q20 35 25 35 Q30 35 30 39 Q30 42 25 45 Z" />
88
+ <path fill={foliageColor} d="M16 42 Q11 39 11 36 Q11 32 16 32 Q21 32 21 36 Q21 39 16 42 Z" />
89
+ </g>
90
+
91
+ <g class={animate ? 'quiver quiver-2' : ''}>
92
+ <path fill={foliageColor} d="M32 28 Q27 25 27 21 Q27 17 32 17 Q37 17 37 21 Q37 25 32 28 Z" />
93
+ <path fill={foliageColor} d="M26 18 Q22 16 22 13 Q22 10 26 10 Q30 10 30 13 Q30 16 26 18 Z" />
94
+ <path fill={foliageColor} d="M35 38 Q30 35 30 32 Q30 28 35 28 Q40 28 40 32 Q40 35 35 38 Z" />
95
+ <path fill={foliageColor} d="M22 12 Q18 10 18 7 Q18 4 22 4 Q26 4 26 7 Q26 10 22 12 Z" />
96
+ </g>
97
+
98
+ <!-- Center top cluster -->
99
+ <g class={animate ? 'quiver quiver-3' : ''}>
100
+ <path fill={foliageColor} d="M50 18 Q45 14 45 10 Q45 6 50 6 Q55 6 55 10 Q55 14 50 18 Z" />
101
+ <path fill={foliageColor} d="M44 22 Q39 19 39 15 Q39 11 44 11 Q49 11 49 15 Q49 19 44 22 Z" />
102
+ <path fill={foliageColor} d="M56 22 Q51 19 51 15 Q51 11 56 11 Q61 11 61 15 Q61 19 56 22 Z" />
103
+ <path fill={foliageColor} d="M50 28 Q45 25 45 21 Q45 17 50 17 Q55 17 55 21 Q55 25 50 28 Z" />
104
+ <path fill={foliageColor} d="M42 32 Q37 29 37 25 Q37 21 42 21 Q47 21 47 25 Q47 29 42 32 Z" />
105
+ <path fill={foliageColor} d="M58 32 Q53 29 53 25 Q53 21 58 21 Q63 21 63 25 Q63 29 58 32 Z" />
106
+ </g>
107
+
108
+ <!-- Center middle cluster -->
109
+ <g class={animate ? 'quiver quiver-1' : ''}>
110
+ <path fill={foliageColor} d="M50 38 Q45 35 45 31 Q45 27 50 27 Q55 27 55 31 Q55 35 50 38 Z" />
111
+ <path fill={foliageColor} d="M44 45 Q39 42 39 38 Q39 34 44 34 Q49 34 49 38 Q49 42 44 45 Z" />
112
+ <path fill={foliageColor} d="M56 45 Q51 42 51 38 Q51 34 56 34 Q61 34 61 38 Q61 42 56 45 Z" />
113
+ <path fill={foliageColor} d="M48 52 Q43 49 43 45 Q43 41 48 41 Q53 41 53 45 Q53 49 48 52 Z" />
114
+ <path fill={foliageColor} d="M52 52 Q47 49 47 45 Q47 41 52 41 Q57 41 57 45 Q57 49 52 52 Z" />
115
+ </g>
116
+
117
+ <!-- Right branch cluster -->
118
+ <g class={animate ? 'quiver quiver-2' : ''}>
119
+ <path fill={foliageColor} d="M78 40 Q72 36 72 32 Q72 28 78 28 Q84 28 84 32 Q84 36 78 40 Z" />
120
+ <path fill={foliageColor} d="M72 32 Q67 29 67 26 Q67 22 72 22 Q77 22 77 26 Q77 29 72 32 Z" />
121
+ <path fill={foliageColor} d="M82 32 Q77 29 77 26 Q77 22 82 22 Q87 22 87 26 Q87 29 82 32 Z" />
122
+ <path fill={foliageColor} d="M75 45 Q70 42 70 39 Q70 35 75 35 Q80 35 80 39 Q80 42 75 45 Z" />
123
+ <path fill={foliageColor} d="M84 42 Q79 39 79 36 Q79 32 84 32 Q89 32 89 36 Q89 39 84 42 Z" />
124
+ </g>
125
+
126
+ <g class={animate ? 'quiver quiver-3' : ''}>
127
+ <path fill={foliageColor} d="M68 28 Q63 25 63 21 Q63 17 68 17 Q73 17 73 21 Q73 25 68 28 Z" />
128
+ <path fill={foliageColor} d="M74 18 Q70 16 70 13 Q70 10 74 10 Q78 10 78 13 Q78 16 74 18 Z" />
129
+ <path fill={foliageColor} d="M65 38 Q60 35 60 32 Q60 28 65 28 Q70 28 70 32 Q70 35 65 38 Z" />
130
+ <path fill={foliageColor} d="M78 12 Q74 10 74 7 Q74 4 78 4 Q82 4 82 7 Q82 10 78 12 Z" />
131
+ </g>
132
+ {/if}
133
+ </svg>
134
+
135
+ <style>
136
+ /* Aspen leaves famously "quiver" in the slightest breeze */
137
+ @keyframes quiver {
138
+ 0%, 100% {
139
+ transform: rotate(0deg) translateX(0);
140
+ }
141
+ 20% {
142
+ transform: rotate(0.8deg) translateX(0.4px);
143
+ }
144
+ 40% {
145
+ transform: rotate(-0.6deg) translateX(-0.3px);
146
+ }
147
+ 60% {
148
+ transform: rotate(0.5deg) translateX(0.2px);
149
+ }
150
+ 80% {
151
+ transform: rotate(-0.4deg) translateX(-0.2px);
152
+ }
153
+ }
154
+
155
+ .quiver {
156
+ transform-origin: center bottom;
157
+ animation: quiver 2.5s ease-in-out infinite;
158
+ }
159
+
160
+ .quiver-1 { animation-delay: 0s; }
161
+ .quiver-2 { animation-delay: 0.4s; }
162
+ .quiver-3 { animation-delay: 0.8s; }
163
+ </style>
@@ -0,0 +1,11 @@
1
+ import type { Season } from '../palette';
2
+ interface Props {
3
+ class?: string;
4
+ color?: string;
5
+ trunkColor?: string;
6
+ season?: Season;
7
+ animate?: boolean;
8
+ }
9
+ declare const TreeAspen: import("svelte").Component<Props, {}, "">;
10
+ type TreeAspen = ReturnType<typeof TreeAspen>;
11
+ export default TreeAspen;
@@ -0,0 +1,186 @@
1
+ <!--
2
+ Grove — A place to Be
3
+ Copyright (c) 2025 Autumn Brown
4
+ Licensed under AGPL-3.0
5
+ -->
6
+ <script lang="ts">
7
+ import type { Season } from '../palette';
8
+ import { autumn, greens, natural, winter } from '../palette';
9
+
10
+ interface Props {
11
+ class?: string;
12
+ color?: string;
13
+ trunkColor?: string;
14
+ season?: Season;
15
+ animate?: boolean;
16
+ }
17
+
18
+ let {
19
+ class: className = 'w-6 h-6',
20
+ color,
21
+ trunkColor,
22
+ season = 'summer',
23
+ animate = true
24
+ }: Props = $props();
25
+
26
+ // Check if tree should be bare (winter)
27
+ const isBare = $derived(season === 'winter');
28
+
29
+ // Birch turns brilliant golden yellow in autumn
30
+ // Use $derived to react to season/color prop changes
31
+ const defaultColor = $derived(season === 'autumn' ? autumn.gold : 'currentColor');
32
+ const foliageColor = $derived(color ?? defaultColor);
33
+
34
+ // Birch bark is white/cream with dark horizontal marks
35
+ // In winter, the white bark stands out even more against snow
36
+ const actualTrunkColor = $derived(trunkColor ?? natural.birchWhite);
37
+ const barkMarkColor = '#2d2d2d';
38
+ </script>
39
+
40
+ <!-- Birch tree - white bark with horizontal marks, small triangular leaves -->
41
+ <svg class={className} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 140">
42
+ <!-- Main trunk - characteristic white birch bark -->
43
+ <rect fill={actualTrunkColor} x="45" y="55" width="10" height="85" rx="2" />
44
+
45
+ <!-- Bark marks (horizontal lenticels - birch signature) -->
46
+ <line x1="46" y1="65" x2="54" y2="65" stroke={barkMarkColor} stroke-width="1.5" opacity="0.5" />
47
+ <line x1="47" y1="78" x2="53" y2="78" stroke={barkMarkColor} stroke-width="1" opacity="0.4" />
48
+ <line x1="46" y1="92" x2="54" y2="92" stroke={barkMarkColor} stroke-width="1.5" opacity="0.5" />
49
+ <line x1="47" y1="105" x2="53" y2="105" stroke={barkMarkColor} stroke-width="1" opacity="0.4" />
50
+ <line x1="46" y1="118" x2="54" y2="118" stroke={barkMarkColor} stroke-width="1.5" opacity="0.5" />
51
+ <line x1="47" y1="130" x2="53" y2="130" stroke={barkMarkColor} stroke-width="1" opacity="0.4" />
52
+
53
+ <!-- Peeling bark texture hints -->
54
+ <path fill="none" stroke={barkMarkColor} stroke-width="0.5" d="M45 83 Q43 87 45 91" opacity="0.25" />
55
+ <path fill="none" stroke={barkMarkColor} stroke-width="0.5" d="M55 108 Q57 112 55 116" opacity="0.25" />
56
+
57
+ <!-- Delicate branch structure - always visible -->
58
+ <path fill="none" stroke={actualTrunkColor} stroke-width="3" d="M50 55 Q42 48 32 42" />
59
+ <path fill="none" stroke={actualTrunkColor} stroke-width="3" d="M50 55 Q58 48 68 42" />
60
+ <path fill="none" stroke={actualTrunkColor} stroke-width="2" d="M50 50 Q44 38 38 28" />
61
+ <path fill="none" stroke={actualTrunkColor} stroke-width="2" d="M50 50 Q56 38 62 28" />
62
+ <path fill="none" stroke={actualTrunkColor} stroke-width="1.5" d="M46 42 Q40 32 35 22" />
63
+ <path fill="none" stroke={actualTrunkColor} stroke-width="1.5" d="M54 42 Q60 32 65 22" />
64
+
65
+ <!-- Extended bare branches and snow accents in winter -->
66
+ {#if isBare}
67
+ <path fill="none" stroke={actualTrunkColor} stroke-width="1" d="M32 42 Q26 35 22 28" />
68
+ <path fill="none" stroke={actualTrunkColor} stroke-width="1" d="M32 42 Q35 35 38 30" />
69
+ <path fill="none" stroke={actualTrunkColor} stroke-width="1" d="M68 42 Q74 35 78 28" />
70
+ <path fill="none" stroke={actualTrunkColor} stroke-width="1" d="M68 42 Q65 35 62 30" />
71
+ <path fill="none" stroke={actualTrunkColor} stroke-width="0.8" d="M35 22 Q32 15 30 8" />
72
+ <path fill="none" stroke={actualTrunkColor} stroke-width="0.8" d="M65 22 Q68 15 70 8" />
73
+ <path fill="none" stroke={actualTrunkColor} stroke-width="0.8" d="M38 28 Q36 22 34 16" />
74
+ <path fill="none" stroke={actualTrunkColor} stroke-width="0.8" d="M62 28 Q64 22 66 16" />
75
+ <!-- Snow accents on branches -->
76
+ <ellipse fill={winter.snow} cx="32" cy="41" rx="4" ry="1.5" opacity="0.8" />
77
+ <ellipse fill={winter.snow} cx="68" cy="41" rx="4" ry="1.5" opacity="0.8" />
78
+ <ellipse fill={winter.snow} cx="38" cy="27" rx="3" ry="1" opacity="0.7" />
79
+ <ellipse fill={winter.snow} cx="62" cy="27" rx="3" ry="1" opacity="0.7" />
80
+ <ellipse fill={winter.snow} cx="50" cy="49" rx="3" ry="1" opacity="0.6" />
81
+ {/if}
82
+
83
+ <!-- Birch leaves - small serrated ovate leaves (doubled for fullness) -->
84
+ <!-- Hidden in winter when tree is bare -->
85
+ {#if !isBare}
86
+ <!-- Left side clusters -->
87
+ <g class={animate ? 'sway sway-1' : ''}>
88
+ <!-- Organic leaf shapes with gentle serration -->
89
+ <path fill={foliageColor} d="M30 50 Q25 45 27 40 L30 38 L33 40 Q35 45 30 50 Z" />
90
+ <path fill={foliageColor} d="M22 43 Q18 39 20 35 L22 33 L24 35 Q26 39 22 43 Z" />
91
+ <path fill={foliageColor} d="M32 40 Q28 36 30 31 L32 29 L34 31 Q36 36 32 40 Z" />
92
+ <path fill={foliageColor} d="M19 51 Q15 47 17 43 L19 41 L21 43 Q23 47 19 51 Z" />
93
+ <path fill={foliageColor} d="M36 53 Q32 49 34 44 L36 42 L38 44 Q40 49 36 53 Z" />
94
+ <!-- Additional leaves for fullness -->
95
+ <path fill={foliageColor} d="M25 46 Q21 42 23 38 L25 36 L27 38 Q29 42 25 46 Z" />
96
+ <path fill={foliageColor} d="M16 47 Q12 43 14 39 L16 37 L18 39 Q20 43 16 47 Z" />
97
+ <path fill={foliageColor} d="M28 54 Q24 50 26 45 L28 43 L30 45 Q32 50 28 54 Z" />
98
+ <path fill={foliageColor} d="M34 47 Q30 43 32 38 L34 36 L36 38 Q38 43 34 47 Z" />
99
+ </g>
100
+
101
+ <g class={animate ? 'sway sway-2' : ''}>
102
+ <path fill={foliageColor} d="M34 33 Q30 29 32 24 L34 22 L36 24 Q38 29 34 33 Z" />
103
+ <path fill={foliageColor} d="M26 30 Q22 26 24 21 L26 19 L28 21 Q30 26 26 30 Z" />
104
+ <path fill={foliageColor} d="M29 19 Q26 16 27 12 L29 10 L31 12 Q32 16 29 19 Z" />
105
+ <path fill={foliageColor} d="M38 24 Q35 21 36 17 L38 15 L40 17 Q41 21 38 24 Z" />
106
+ <!-- Additional leaves for fullness -->
107
+ <path fill={foliageColor} d="M22 36 Q18 32 20 27 L22 25 L24 27 Q26 32 22 36 Z" />
108
+ <path fill={foliageColor} d="M30 26 Q27 23 28 19 L30 17 L32 19 Q33 23 30 26 Z" />
109
+ <path fill={foliageColor} d="M35 28 Q32 25 33 21 L35 19 L37 21 Q38 25 35 28 Z" />
110
+ <path fill={foliageColor} d="M24 24 Q21 21 22 17 L24 15 L26 17 Q27 21 24 24 Z" />
111
+ </g>
112
+
113
+ <!-- Center top cluster -->
114
+ <g class={animate ? 'sway sway-3' : ''}>
115
+ <path fill={foliageColor} d="M50 23 Q46 18 48 13 L50 11 L52 13 Q54 18 50 23 Z" />
116
+ <path fill={foliageColor} d="M45 27 Q41 23 43 18 L45 16 L47 18 Q49 23 45 27 Z" />
117
+ <path fill={foliageColor} d="M55 27 Q51 23 53 18 L55 16 L57 18 Q59 23 55 27 Z" />
118
+ <path fill={foliageColor} d="M52 11 Q49 8 50 5 L52 3 L54 5 Q55 8 52 11 Z" />
119
+ <path fill={foliageColor} d="M47 16 Q44 13 45 9 L47 7 L49 9 Q50 13 47 16 Z" />
120
+ <path fill={foliageColor} d="M53 16 Q50 13 51 9 L53 7 L55 9 Q56 13 53 16 Z" />
121
+ <!-- Additional leaves for fullness -->
122
+ <path fill={foliageColor} d="M48 19 Q45 16 46 12 L48 10 L50 12 Q51 16 48 19 Z" />
123
+ <path fill={foliageColor} d="M56 19 Q53 16 54 12 L56 10 L58 12 Q59 16 56 19 Z" />
124
+ <path fill={foliageColor} d="M50 15 Q47 12 48 8 L50 6 L52 8 Q53 12 50 15 Z" />
125
+ <path fill={foliageColor} d="M42 23 Q39 20 40 16 L42 14 L44 16 Q45 20 42 23 Z" />
126
+ <path fill={foliageColor} d="M58 23 Q55 20 56 16 L58 14 L60 16 Q61 20 58 23 Z" />
127
+ </g>
128
+
129
+ <!-- Center middle -->
130
+ <g class={animate ? 'sway sway-1' : ''}>
131
+ <path fill={foliageColor} d="M50 37 Q46 32 48 27 L50 25 L52 27 Q54 32 50 37 Z" />
132
+ <path fill={foliageColor} d="M43 40 Q39 36 41 31 L43 29 L45 31 Q47 36 43 40 Z" />
133
+ <path fill={foliageColor} d="M57 40 Q53 36 55 31 L57 29 L59 31 Q61 36 57 40 Z" />
134
+ <path fill={foliageColor} d="M48 49 Q45 46 46 42 L48 40 L50 42 Q51 46 48 49 Z" />
135
+ <path fill={foliageColor} d="M52 49 Q49 46 50 42 L52 40 L54 42 Q55 46 52 49 Z" />
136
+ <!-- Additional leaves for fullness -->
137
+ <path fill={foliageColor} d="M46 33 Q43 30 44 26 L46 24 L48 26 Q49 30 46 33 Z" />
138
+ <path fill={foliageColor} d="M54 33 Q51 30 52 26 L54 24 L56 26 Q57 30 54 33 Z" />
139
+ <path fill={foliageColor} d="M40 44 Q37 41 38 37 L40 35 L42 37 Q43 41 40 44 Z" />
140
+ <path fill={foliageColor} d="M60 44 Q57 41 58 37 L60 35 L62 37 Q63 41 60 44 Z" />
141
+ <path fill={foliageColor} d="M50 44 Q47 41 48 37 L50 35 L52 37 Q53 41 50 44 Z" />
142
+ </g>
143
+
144
+ <!-- Right side clusters -->
145
+ <g class={animate ? 'sway sway-2' : ''}>
146
+ <path fill={foliageColor} d="M70 50 Q65 45 67 40 L70 38 L73 40 Q75 45 70 50 Z" />
147
+ <path fill={foliageColor} d="M78 43 Q74 39 76 35 L78 33 L80 35 Q82 39 78 43 Z" />
148
+ <path fill={foliageColor} d="M68 40 Q64 36 66 31 L68 29 L70 31 Q72 36 68 40 Z" />
149
+ <path fill={foliageColor} d="M81 51 Q77 47 79 43 L81 41 L83 43 Q85 47 81 51 Z" />
150
+ <path fill={foliageColor} d="M64 53 Q60 49 62 44 L64 42 L66 44 Q68 49 64 53 Z" />
151
+ <!-- Additional leaves for fullness -->
152
+ <path fill={foliageColor} d="M75 46 Q71 42 73 38 L75 36 L77 38 Q79 42 75 46 Z" />
153
+ <path fill={foliageColor} d="M84 47 Q80 43 82 39 L84 37 L86 39 Q88 43 84 47 Z" />
154
+ <path fill={foliageColor} d="M72 54 Q68 50 70 45 L72 43 L74 45 Q76 50 72 54 Z" />
155
+ <path fill={foliageColor} d="M66 47 Q62 43 64 38 L66 36 L68 38 Q70 43 66 47 Z" />
156
+ </g>
157
+
158
+ <g class={animate ? 'sway sway-3' : ''}>
159
+ <path fill={foliageColor} d="M66 33 Q62 29 64 24 L66 22 L68 24 Q70 29 66 33 Z" />
160
+ <path fill={foliageColor} d="M74 30 Q70 26 72 21 L74 19 L76 21 Q78 26 74 30 Z" />
161
+ <path fill={foliageColor} d="M71 19 Q68 16 69 12 L71 10 L73 12 Q74 16 71 19 Z" />
162
+ <path fill={foliageColor} d="M62 24 Q59 21 60 17 L62 15 L64 17 Q65 21 62 24 Z" />
163
+ <!-- Additional leaves for fullness -->
164
+ <path fill={foliageColor} d="M78 36 Q74 32 76 27 L78 25 L80 27 Q82 32 78 36 Z" />
165
+ <path fill={foliageColor} d="M70 26 Q67 23 68 19 L70 17 L72 19 Q73 23 70 26 Z" />
166
+ <path fill={foliageColor} d="M65 28 Q62 25 63 21 L65 19 L67 21 Q68 25 65 28 Z" />
167
+ <path fill={foliageColor} d="M76 24 Q73 21 74 17 L76 15 L78 17 Q79 21 76 24 Z" />
168
+ </g>
169
+ {/if}
170
+ </svg>
171
+
172
+ <style>
173
+ @keyframes sway {
174
+ 0%, 100% { transform: translateX(0) rotate(0deg); }
175
+ 50% { transform: translateX(0.8px) rotate(0.3deg); }
176
+ }
177
+
178
+ .sway {
179
+ transform-origin: center bottom;
180
+ animation: sway 3.5s ease-in-out infinite;
181
+ }
182
+
183
+ .sway-1 { animation-delay: 0s; }
184
+ .sway-2 { animation-delay: 0.4s; }
185
+ .sway-3 { animation-delay: 0.8s; }
186
+ </style>
@@ -0,0 +1,11 @@
1
+ import type { Season } from '../palette';
2
+ interface Props {
3
+ class?: string;
4
+ color?: string;
5
+ trunkColor?: string;
6
+ season?: Season;
7
+ animate?: boolean;
8
+ }
9
+ declare const TreeBirch: import("svelte").Component<Props, {}, "">;
10
+ type TreeBirch = ReturnType<typeof TreeBirch>;
11
+ export default TreeBirch;
@@ -0,0 +1,108 @@
1
+ <!--
2
+ Grove — A place to Be
3
+ Copyright (c) 2025 Autumn Brown
4
+ Licensed under AGPL-3.0
5
+ -->
6
+ <script lang="ts">
7
+ import type { Season } from '../palette';
8
+ import { autumnReds, cherryBlossoms, winter } from '../palette';
9
+
10
+ interface Props {
11
+ class?: string;
12
+ color?: string;
13
+ trunkColor?: string;
14
+ season?: Season;
15
+ animate?: boolean;
16
+ }
17
+
18
+ let {
19
+ class: className = 'w-6 h-6',
20
+ color,
21
+ trunkColor,
22
+ season = 'spring',
23
+ animate = false
24
+ }: Props = $props();
25
+
26
+ // Check if tree should be bare (winter)
27
+ const isBare = $derived(season === 'winter');
28
+
29
+ // Cherry trees: pink blossoms in spring, red/crimson foliage in autumn
30
+ // Use $derived to react to season/color prop changes
31
+ const defaultColor = $derived(season === 'autumn' ? autumnReds.scarlet : cherryBlossoms.pale);
32
+ const blossomColor = $derived(color ?? defaultColor);
33
+ const actualTrunkColor = $derived(
34
+ trunkColor ?? (season === 'winter' ? winter.bareBranch : '#6B4423')
35
+ );
36
+ </script>
37
+
38
+ <!-- Cherry blossom tree - delicate branching with clustered flowers -->
39
+ <svg
40
+ class="{className} {animate ? 'sway' : ''}"
41
+ xmlns="http://www.w3.org/2000/svg"
42
+ viewBox="0 0 100 120"
43
+ >
44
+ <!-- Main trunk -->
45
+ <path fill={actualTrunkColor} d="M45 65 Q43 85 42 120 L58 120 Q57 85 55 65 Q50 60 45 65"/>
46
+
47
+ <!-- Branches - always visible -->
48
+ <path fill={actualTrunkColor} d="M50 60 Q35 50 20 55 Q25 52 30 45 Q40 48 50 55" stroke={actualTrunkColor} stroke-width="2"/>
49
+ <path fill={actualTrunkColor} d="M50 60 Q65 50 80 55 Q75 52 70 45 Q60 48 50 55" stroke={actualTrunkColor} stroke-width="2"/>
50
+ <path d="M50 50 Q45 35 35 30" stroke={actualTrunkColor} stroke-width="2" fill="none"/>
51
+ <path d="M50 50 Q55 35 65 30" stroke={actualTrunkColor} stroke-width="2" fill="none"/>
52
+
53
+ <!-- Extended bare branches in winter -->
54
+ {#if isBare}
55
+ <path d="M20 55 Q12 50 8 42" stroke={actualTrunkColor} stroke-width="1.5" fill="none"/>
56
+ <path d="M20 55 Q18 48 15 38" stroke={actualTrunkColor} stroke-width="1" fill="none"/>
57
+ <path d="M80 55 Q88 50 92 42" stroke={actualTrunkColor} stroke-width="1.5" fill="none"/>
58
+ <path d="M80 55 Q82 48 85 38" stroke={actualTrunkColor} stroke-width="1" fill="none"/>
59
+ <path d="M35 30 Q28 22 22 15" stroke={actualTrunkColor} stroke-width="1" fill="none"/>
60
+ <path d="M35 30 Q38 22 42 12" stroke={actualTrunkColor} stroke-width="1" fill="none"/>
61
+ <path d="M65 30 Q72 22 78 15" stroke={actualTrunkColor} stroke-width="1" fill="none"/>
62
+ <path d="M65 30 Q62 22 58 12" stroke={actualTrunkColor} stroke-width="1" fill="none"/>
63
+ <path d="M50 50 Q50 35 50 18" stroke={actualTrunkColor} stroke-width="1.5" fill="none"/>
64
+ <!-- Snow accents on branches -->
65
+ <ellipse fill={winter.snow} cx="20" cy="54" rx="5" ry="1.5" opacity="0.8" />
66
+ <ellipse fill={winter.snow} cx="80" cy="54" rx="5" ry="1.5" opacity="0.8" />
67
+ <ellipse fill={winter.snow} cx="35" cy="29" rx="4" ry="1" opacity="0.7" />
68
+ <ellipse fill={winter.snow} cx="65" cy="29" rx="4" ry="1" opacity="0.7" />
69
+ <ellipse fill={winter.snow} cx="50" cy="18" rx="3" ry="1" opacity="0.7" />
70
+ {/if}
71
+
72
+ <!-- Blossom clusters - hidden in winter -->
73
+ {#if !isBare}
74
+ <!-- Blossom clusters - left side -->
75
+ <circle fill={blossomColor} cx="20" cy="52" r="12"/>
76
+ <circle fill={blossomColor} cx="28" cy="42" r="10"/>
77
+ <circle fill={blossomColor} cx="15" cy="40" r="8"/>
78
+
79
+ <!-- Blossom clusters - right side -->
80
+ <circle fill={blossomColor} cx="80" cy="52" r="12"/>
81
+ <circle fill={blossomColor} cx="72" cy="42" r="10"/>
82
+ <circle fill={blossomColor} cx="85" cy="40" r="8"/>
83
+
84
+ <!-- Blossom clusters - top -->
85
+ <circle fill={blossomColor} cx="35" cy="28" r="11"/>
86
+ <circle fill={blossomColor} cx="50" cy="20" r="14"/>
87
+ <circle fill={blossomColor} cx="65" cy="28" r="11"/>
88
+ <circle fill={blossomColor} cx="42" cy="12" r="9"/>
89
+ <circle fill={blossomColor} cx="58" cy="12" r="9"/>
90
+
91
+ <!-- Center clusters -->
92
+ <circle fill={blossomColor} cx="40" cy="50" r="10"/>
93
+ <circle fill={blossomColor} cx="60" cy="50" r="10"/>
94
+ <circle fill={blossomColor} cx="50" cy="38" r="12"/>
95
+ {/if}
96
+ </svg>
97
+
98
+ <style>
99
+ @keyframes sway {
100
+ 0%, 100% { transform: rotate(0deg); }
101
+ 50% { transform: rotate(1.2deg); }
102
+ }
103
+
104
+ .sway {
105
+ transform-origin: center bottom;
106
+ animation: sway 3.5s ease-in-out infinite;
107
+ }
108
+ </style>
@@ -0,0 +1,11 @@
1
+ import type { Season } from '../palette';
2
+ interface Props {
3
+ class?: string;
4
+ color?: string;
5
+ trunkColor?: string;
6
+ season?: Season;
7
+ animate?: boolean;
8
+ }
9
+ declare const TreeCherry: import("svelte").Component<Props, {}, "">;
10
+ type TreeCherry = ReturnType<typeof TreeCherry>;
11
+ export default TreeCherry;
@@ -0,0 +1,79 @@
1
+ <!--
2
+ Grove — A place to Be
3
+ Copyright (c) 2025 Autumn Brown
4
+ Licensed under AGPL-3.0
5
+ -->
6
+ <script lang="ts">
7
+ import type { Season } from '../palette';
8
+ import { winter } from '../palette';
9
+
10
+ interface Props {
11
+ class?: string;
12
+ color?: string;
13
+ trunkColor?: string;
14
+ season?: Season;
15
+ animate?: boolean;
16
+ }
17
+
18
+ let {
19
+ class: className = 'w-6 h-6',
20
+ color,
21
+ trunkColor,
22
+ season = 'summer',
23
+ animate = false
24
+ }: Props = $props();
25
+
26
+ // Check if winter for snow accents
27
+ const isWinter = $derived(season === 'winter');
28
+
29
+ // Pine trees are evergreen - they stay green year-round!
30
+ // In winter, they take on a frosted appearance from the color prop
31
+ const foliageColor = $derived(color ?? 'currentColor');
32
+ const actualTrunkColor = $derived(trunkColor ?? '#6B4423');
33
+ </script>
34
+
35
+ <!-- Pine/Conifer tree - triangular layered design -->
36
+ <svg
37
+ class="{className} {animate ? 'sway' : ''}"
38
+ xmlns="http://www.w3.org/2000/svg"
39
+ viewBox="0 0 100 140"
40
+ >
41
+ <!-- Trunk -->
42
+ <rect fill={actualTrunkColor} x="42" y="100" width="16" height="40" rx="2"/>
43
+
44
+ <!-- Bottom layer (widest) -->
45
+ <polygon fill={foliageColor} points="50,55 10,105 90,105"/>
46
+
47
+ <!-- Middle layer -->
48
+ <polygon fill={foliageColor} points="50,30 18,75 82,75"/>
49
+
50
+ <!-- Top layer (smallest) -->
51
+ <polygon fill={foliageColor} points="50,5 28,50 72,50"/>
52
+
53
+ <!-- Snow accents in winter -->
54
+ {#if isWinter}
55
+ <!-- Snow on branch edges -->
56
+ <path fill={winter.snow} d="M50 5 Q55 12 60 18 L40 18 Q45 12 50 5" opacity="0.85" />
57
+ <path fill={winter.snow} d="M28 50 Q38 52 50 50 Q62 52 72 50 L65 55 L35 55 Z" opacity="0.7" />
58
+ <path fill={winter.snow} d="M18 75 Q35 77 50 75 Q65 77 82 75 L72 82 L28 82 Z" opacity="0.6" />
59
+ <path fill={winter.snow} d="M10 105 Q30 107 50 105 Q70 107 90 105 L80 110 L20 110 Z" opacity="0.5" />
60
+ <!-- Scattered snow spots -->
61
+ <ellipse fill={winter.snow} cx="35" cy="65" rx="4" ry="2" opacity="0.5" />
62
+ <ellipse fill={winter.snow} cx="65" cy="68" rx="3" ry="1.5" opacity="0.4" />
63
+ <ellipse fill={winter.snow} cx="30" cy="90" rx="5" ry="2" opacity="0.4" />
64
+ <ellipse fill={winter.snow} cx="70" cy="92" rx="4" ry="2" opacity="0.45" />
65
+ <ellipse fill={winter.snow} cx="50" cy="40" rx="3" ry="1.5" opacity="0.5" />
66
+ {/if}
67
+ </svg>
68
+
69
+ <style>
70
+ @keyframes sway {
71
+ 0%, 100% { transform: rotate(0deg); }
72
+ 50% { transform: rotate(0.8deg); }
73
+ }
74
+
75
+ .sway {
76
+ transform-origin: center bottom;
77
+ animation: sway 5s ease-in-out infinite;
78
+ }
79
+ </style>
@@ -0,0 +1,11 @@
1
+ import type { Season } from '../palette';
2
+ interface Props {
3
+ class?: string;
4
+ color?: string;
5
+ trunkColor?: string;
6
+ season?: Season;
7
+ animate?: boolean;
8
+ }
9
+ declare const TreePine: import("svelte").Component<Props, {}, "">;
10
+ type TreePine = ReturnType<typeof TreePine>;
11
+ export default TreePine;
@@ -0,0 +1,4 @@
1
+ export { default as TreeAspen } from './TreeAspen.svelte';
2
+ export { default as TreeBirch } from './TreeBirch.svelte';
3
+ export { default as TreeCherry } from './TreeCherry.svelte';
4
+ export { default as TreePine } from './TreePine.svelte';
@@ -0,0 +1,5 @@
1
+ // Tree components - various tree types for forest scenes
2
+ export { default as TreeAspen } from './TreeAspen.svelte';
3
+ export { default as TreeBirch } from './TreeBirch.svelte';
4
+ export { default as TreeCherry } from './TreeCherry.svelte';
5
+ export { default as TreePine } from './TreePine.svelte';