@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.
- package/dist/components/OnboardingChecklist.svelte +2 -2
- package/dist/components/WispButton.svelte +83 -0
- package/dist/components/WispButton.svelte.d.ts +49 -0
- package/dist/components/WispPanel.svelte +1093 -0
- package/dist/components/WispPanel.svelte.d.ts +49 -0
- package/dist/components/custom/TableOfContents.svelte +12 -1
- package/dist/components/quota/UpgradePrompt.svelte +1 -0
- package/dist/config/wisp.d.ts +145 -0
- package/dist/config/wisp.js +175 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/server/inference-client.d.ts +139 -0
- package/dist/server/inference-client.js +294 -0
- package/dist/ui/components/content/RoadmapPreview.svelte +91 -0
- package/dist/ui/components/content/RoadmapPreview.svelte.d.ts +36 -0
- package/dist/ui/components/content/index.d.ts +1 -0
- package/dist/ui/components/content/index.js +1 -0
- package/dist/ui/components/nature/Logo.svelte +260 -0
- package/dist/ui/components/nature/Logo.svelte.d.ts +14 -0
- package/dist/ui/components/nature/botanical/Acorn.svelte +48 -0
- package/dist/ui/components/nature/botanical/Acorn.svelte.d.ts +8 -0
- package/dist/ui/components/nature/botanical/Berry.svelte +67 -0
- package/dist/ui/components/nature/botanical/Berry.svelte.d.ts +8 -0
- package/dist/ui/components/nature/botanical/DandelionPuff.svelte +98 -0
- package/dist/ui/components/nature/botanical/DandelionPuff.svelte.d.ts +8 -0
- package/dist/ui/components/nature/botanical/FallingLeavesLayer.svelte +170 -0
- package/dist/ui/components/nature/botanical/FallingLeavesLayer.svelte.d.ts +35 -0
- package/dist/ui/components/nature/botanical/FallingPetalsLayer.svelte +174 -0
- package/dist/ui/components/nature/botanical/FallingPetalsLayer.svelte.d.ts +25 -0
- package/dist/ui/components/nature/botanical/Leaf.svelte +77 -0
- package/dist/ui/components/nature/botanical/Leaf.svelte.d.ts +10 -0
- package/dist/ui/components/nature/botanical/LeafFalling.svelte +186 -0
- package/dist/ui/components/nature/botanical/LeafFalling.svelte.d.ts +22 -0
- package/dist/ui/components/nature/botanical/PetalFalling.svelte +266 -0
- package/dist/ui/components/nature/botanical/PetalFalling.svelte.d.ts +25 -0
- package/dist/ui/components/nature/botanical/PineCone.svelte +61 -0
- package/dist/ui/components/nature/botanical/PineCone.svelte.d.ts +7 -0
- package/dist/ui/components/nature/botanical/Vine.svelte +102 -0
- package/dist/ui/components/nature/botanical/Vine.svelte.d.ts +11 -0
- package/dist/ui/components/nature/botanical/index.d.ts +10 -0
- package/dist/ui/components/nature/botanical/index.js +11 -0
- package/dist/ui/components/nature/creatures/Bee.svelte +78 -0
- package/dist/ui/components/nature/creatures/Bee.svelte.d.ts +9 -0
- package/dist/ui/components/nature/creatures/Bird.svelte +94 -0
- package/dist/ui/components/nature/creatures/Bird.svelte.d.ts +11 -0
- package/dist/ui/components/nature/creatures/BirdFlying.svelte +83 -0
- package/dist/ui/components/nature/creatures/BirdFlying.svelte.d.ts +9 -0
- package/dist/ui/components/nature/creatures/Bluebird.svelte +95 -0
- package/dist/ui/components/nature/creatures/Bluebird.svelte.d.ts +12 -0
- package/dist/ui/components/nature/creatures/Butterfly.svelte +87 -0
- package/dist/ui/components/nature/creatures/Butterfly.svelte.d.ts +9 -0
- package/dist/ui/components/nature/creatures/Cardinal.svelte +95 -0
- package/dist/ui/components/nature/creatures/Cardinal.svelte.d.ts +12 -0
- package/dist/ui/components/nature/creatures/Chickadee.svelte +97 -0
- package/dist/ui/components/nature/creatures/Chickadee.svelte.d.ts +12 -0
- package/dist/ui/components/nature/creatures/Deer.svelte +95 -0
- package/dist/ui/components/nature/creatures/Deer.svelte.d.ts +9 -0
- package/dist/ui/components/nature/creatures/Firefly.svelte +111 -0
- package/dist/ui/components/nature/creatures/Firefly.svelte.d.ts +10 -0
- package/dist/ui/components/nature/creatures/Owl.svelte +91 -0
- package/dist/ui/components/nature/creatures/Owl.svelte.d.ts +9 -0
- package/dist/ui/components/nature/creatures/Rabbit.svelte +90 -0
- package/dist/ui/components/nature/creatures/Rabbit.svelte.d.ts +9 -0
- package/dist/ui/components/nature/creatures/Robin.svelte +98 -0
- package/dist/ui/components/nature/creatures/Robin.svelte.d.ts +12 -0
- package/dist/ui/components/nature/creatures/Squirrel.svelte +97 -0
- package/dist/ui/components/nature/creatures/Squirrel.svelte.d.ts +9 -0
- package/dist/ui/components/nature/creatures/index.d.ts +13 -0
- package/dist/ui/components/nature/creatures/index.js +14 -0
- package/dist/ui/components/nature/ground/Bush.svelte +57 -0
- package/dist/ui/components/nature/ground/Bush.svelte.d.ts +10 -0
- package/dist/ui/components/nature/ground/Crocus.svelte +83 -0
- package/dist/ui/components/nature/ground/Crocus.svelte.d.ts +12 -0
- package/dist/ui/components/nature/ground/Daffodil.svelte +75 -0
- package/dist/ui/components/nature/ground/Daffodil.svelte.d.ts +11 -0
- package/dist/ui/components/nature/ground/Fern.svelte +72 -0
- package/dist/ui/components/nature/ground/Fern.svelte.d.ts +10 -0
- package/dist/ui/components/nature/ground/FlowerWild.svelte +60 -0
- package/dist/ui/components/nature/ground/FlowerWild.svelte.d.ts +10 -0
- package/dist/ui/components/nature/ground/GrassTuft.svelte +49 -0
- package/dist/ui/components/nature/ground/GrassTuft.svelte.d.ts +10 -0
- package/dist/ui/components/nature/ground/Log.svelte +42 -0
- package/dist/ui/components/nature/ground/Log.svelte.d.ts +7 -0
- package/dist/ui/components/nature/ground/Mushroom.svelte +48 -0
- package/dist/ui/components/nature/ground/Mushroom.svelte.d.ts +9 -0
- package/dist/ui/components/nature/ground/MushroomCluster.svelte +41 -0
- package/dist/ui/components/nature/ground/MushroomCluster.svelte.d.ts +8 -0
- package/dist/ui/components/nature/ground/Rock.svelte +59 -0
- package/dist/ui/components/nature/ground/Rock.svelte.d.ts +8 -0
- package/dist/ui/components/nature/ground/Stump.svelte +44 -0
- package/dist/ui/components/nature/ground/Stump.svelte.d.ts +8 -0
- package/dist/ui/components/nature/ground/Tulip.svelte +79 -0
- package/dist/ui/components/nature/ground/Tulip.svelte.d.ts +11 -0
- package/dist/ui/components/nature/ground/index.d.ts +12 -0
- package/dist/ui/components/nature/ground/index.js +13 -0
- package/dist/ui/components/nature/index.d.ts +28 -0
- package/dist/ui/components/nature/index.js +38 -0
- package/dist/ui/components/nature/palette.d.ts +602 -0
- package/dist/ui/components/nature/palette.js +472 -0
- package/dist/ui/components/nature/sky/Cloud.svelte +122 -0
- package/dist/ui/components/nature/sky/Cloud.svelte.d.ts +11 -0
- package/dist/ui/components/nature/sky/CloudWispy.svelte +79 -0
- package/dist/ui/components/nature/sky/CloudWispy.svelte.d.ts +9 -0
- package/dist/ui/components/nature/sky/Moon.svelte +60 -0
- package/dist/ui/components/nature/sky/Moon.svelte.d.ts +9 -0
- package/dist/ui/components/nature/sky/Rainbow.svelte +101 -0
- package/dist/ui/components/nature/sky/Rainbow.svelte.d.ts +8 -0
- package/dist/ui/components/nature/sky/Star.svelte +84 -0
- package/dist/ui/components/nature/sky/Star.svelte.d.ts +10 -0
- package/dist/ui/components/nature/sky/StarCluster.svelte +85 -0
- package/dist/ui/components/nature/sky/StarCluster.svelte.d.ts +9 -0
- package/dist/ui/components/nature/sky/StarShooting.svelte +90 -0
- package/dist/ui/components/nature/sky/StarShooting.svelte.d.ts +9 -0
- package/dist/ui/components/nature/sky/Sun.svelte +70 -0
- package/dist/ui/components/nature/sky/Sun.svelte.d.ts +9 -0
- package/dist/ui/components/nature/sky/index.d.ts +8 -0
- package/dist/ui/components/nature/sky/index.js +9 -0
- package/dist/ui/components/nature/structural/Birdhouse.svelte +53 -0
- package/dist/ui/components/nature/structural/Birdhouse.svelte.d.ts +8 -0
- package/dist/ui/components/nature/structural/Bridge.svelte +65 -0
- package/dist/ui/components/nature/structural/Bridge.svelte.d.ts +7 -0
- package/dist/ui/components/nature/structural/FencePost.svelte +54 -0
- package/dist/ui/components/nature/structural/FencePost.svelte.d.ts +8 -0
- package/dist/ui/components/nature/structural/GardenGate.svelte +70 -0
- package/dist/ui/components/nature/structural/GardenGate.svelte.d.ts +8 -0
- package/dist/ui/components/nature/structural/Lantern.svelte +113 -0
- package/dist/ui/components/nature/structural/Lantern.svelte.d.ts +10 -0
- package/dist/ui/components/nature/structural/Lattice.svelte +89 -0
- package/dist/ui/components/nature/structural/Lattice.svelte.d.ts +8 -0
- package/dist/ui/components/nature/structural/LatticeWithVine.svelte +89 -0
- package/dist/ui/components/nature/structural/LatticeWithVine.svelte.d.ts +11 -0
- package/dist/ui/components/nature/structural/StonePath.svelte +48 -0
- package/dist/ui/components/nature/structural/StonePath.svelte.d.ts +7 -0
- package/dist/ui/components/nature/structural/index.d.ts +8 -0
- package/dist/ui/components/nature/structural/index.js +9 -0
- package/dist/ui/components/nature/trees/TreeAspen.svelte +163 -0
- package/dist/ui/components/nature/trees/TreeAspen.svelte.d.ts +11 -0
- package/dist/ui/components/nature/trees/TreeBirch.svelte +186 -0
- package/dist/ui/components/nature/trees/TreeBirch.svelte.d.ts +11 -0
- package/dist/ui/components/nature/trees/TreeCherry.svelte +108 -0
- package/dist/ui/components/nature/trees/TreeCherry.svelte.d.ts +11 -0
- package/dist/ui/components/nature/trees/TreePine.svelte +79 -0
- package/dist/ui/components/nature/trees/TreePine.svelte.d.ts +11 -0
- package/dist/ui/components/nature/trees/index.d.ts +4 -0
- package/dist/ui/components/nature/trees/index.js +5 -0
- package/dist/ui/components/nature/water/LilyPad.svelte +99 -0
- package/dist/ui/components/nature/water/LilyPad.svelte.d.ts +10 -0
- package/dist/ui/components/nature/water/Pond.svelte +104 -0
- package/dist/ui/components/nature/water/Pond.svelte.d.ts +8 -0
- package/dist/ui/components/nature/water/Reeds.svelte +85 -0
- package/dist/ui/components/nature/water/Reeds.svelte.d.ts +11 -0
- package/dist/ui/components/nature/water/Stream.svelte +98 -0
- package/dist/ui/components/nature/water/Stream.svelte.d.ts +8 -0
- package/dist/ui/components/nature/water/index.d.ts +4 -0
- package/dist/ui/components/nature/water/index.js +5 -0
- package/dist/ui/components/nature/weather/SnowfallLayer.svelte +175 -0
- package/dist/ui/components/nature/weather/SnowfallLayer.svelte.d.ts +25 -0
- package/dist/ui/components/nature/weather/Snowflake.svelte +99 -0
- package/dist/ui/components/nature/weather/Snowflake.svelte.d.ts +11 -0
- package/dist/ui/components/nature/weather/SnowflakeFalling.svelte +162 -0
- package/dist/ui/components/nature/weather/SnowflakeFalling.svelte.d.ts +23 -0
- package/dist/ui/components/nature/weather/index.d.ts +3 -0
- package/dist/ui/components/nature/weather/index.js +4 -0
- package/dist/ui/components/primitives/textarea/textarea.svelte +1 -1
- package/dist/ui/components/typography/Alagard.svelte +17 -0
- package/dist/ui/components/typography/Alagard.svelte.d.ts +10 -0
- package/dist/ui/components/typography/Atkinson.svelte +17 -0
- package/dist/ui/components/typography/Atkinson.svelte.d.ts +10 -0
- package/dist/ui/components/typography/BodoniModa.svelte +17 -0
- package/dist/ui/components/typography/BodoniModa.svelte.d.ts +10 -0
- package/dist/ui/components/typography/Calistoga.svelte +17 -0
- package/dist/ui/components/typography/Calistoga.svelte.d.ts +10 -0
- package/dist/ui/components/typography/Caveat.svelte +17 -0
- package/dist/ui/components/typography/Caveat.svelte.d.ts +10 -0
- package/dist/ui/components/typography/Cormorant.svelte +17 -0
- package/dist/ui/components/typography/Cormorant.svelte.d.ts +10 -0
- package/dist/ui/components/typography/Cozette.svelte +17 -0
- package/dist/ui/components/typography/Cozette.svelte.d.ts +10 -0
- package/dist/ui/components/typography/EBGaramond.svelte +17 -0
- package/dist/ui/components/typography/EBGaramond.svelte.d.ts +10 -0
- package/dist/ui/components/typography/FontProvider.svelte +98 -0
- package/dist/ui/components/typography/FontProvider.svelte.d.ts +17 -0
- package/dist/ui/components/typography/Fraunces.svelte +17 -0
- package/dist/ui/components/typography/Fraunces.svelte.d.ts +10 -0
- package/dist/ui/components/typography/IBMPlexMono.svelte +17 -0
- package/dist/ui/components/typography/IBMPlexMono.svelte.d.ts +10 -0
- package/dist/ui/components/typography/InstrumentSans.svelte +17 -0
- package/dist/ui/components/typography/InstrumentSans.svelte.d.ts +10 -0
- package/dist/ui/components/typography/Lexend.svelte +17 -0
- package/dist/ui/components/typography/Lexend.svelte.d.ts +10 -0
- package/dist/ui/components/typography/Lora.svelte +17 -0
- package/dist/ui/components/typography/Lora.svelte.d.ts +10 -0
- package/dist/ui/components/typography/Luciole.svelte +17 -0
- package/dist/ui/components/typography/Luciole.svelte.d.ts +10 -0
- package/dist/ui/components/typography/Manrope.svelte +17 -0
- package/dist/ui/components/typography/Manrope.svelte.d.ts +10 -0
- package/dist/ui/components/typography/Merriweather.svelte +17 -0
- package/dist/ui/components/typography/Merriweather.svelte.d.ts +10 -0
- package/dist/ui/components/typography/Nunito.svelte +17 -0
- package/dist/ui/components/typography/Nunito.svelte.d.ts +10 -0
- package/dist/ui/components/typography/OpenDyslexic.svelte +17 -0
- package/dist/ui/components/typography/OpenDyslexic.svelte.d.ts +10 -0
- package/dist/ui/components/typography/PlusJakartaSans.svelte +17 -0
- package/dist/ui/components/typography/PlusJakartaSans.svelte.d.ts +10 -0
- package/dist/ui/components/typography/Quicksand.svelte +17 -0
- package/dist/ui/components/typography/Quicksand.svelte.d.ts +10 -0
- package/dist/ui/components/typography/README.md +153 -0
- package/dist/ui/components/typography/index.d.ts +23 -0
- package/dist/ui/components/typography/index.js +42 -0
- package/dist/ui/components/ui/GlassCarousel.svelte +446 -0
- package/dist/ui/components/ui/GlassCarousel.svelte.d.ts +57 -0
- package/dist/ui/components/ui/GlassConfirmDialog.svelte +2 -1
- package/dist/ui/components/ui/GlassLogo.svelte +423 -0
- package/dist/ui/components/ui/GlassLogo.svelte.d.ts +23 -0
- package/dist/ui/components/ui/GlassNavbar.svelte +120 -0
- package/dist/ui/components/ui/GlassNavbar.svelte.d.ts +42 -0
- package/dist/ui/components/ui/GlassOverlay.svelte +1 -1
- package/dist/ui/components/ui/Logo.svelte +47 -52
- package/dist/ui/components/ui/Logo.svelte.d.ts +4 -3
- package/dist/ui/components/ui/index.d.ts +3 -0
- package/dist/ui/components/ui/index.js +3 -0
- package/dist/ui/index.d.ts +1 -0
- package/dist/ui/index.js +2 -0
- package/dist/ui/styles/grove.css +15 -1
- package/dist/ui/vineyard/index.d.ts +9 -0
- package/dist/ui/vineyard/index.js +8 -0
- package/dist/utils/csrf.js +5 -2
- package/dist/utils/readability.d.ts +89 -0
- package/dist/utils/readability.js +204 -0
- package/package.json +27 -1
|
@@ -0,0 +1,95 @@
|
|
|
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 { bark, accents } from '../palette';
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
class?: string;
|
|
11
|
+
style?: string;
|
|
12
|
+
bodyColor?: string;
|
|
13
|
+
maskColor?: string;
|
|
14
|
+
beakColor?: string;
|
|
15
|
+
animate?: boolean;
|
|
16
|
+
facing?: 'left' | 'right';
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let {
|
|
20
|
+
class: className = 'w-6 h-6',
|
|
21
|
+
style,
|
|
22
|
+
bodyColor,
|
|
23
|
+
maskColor,
|
|
24
|
+
beakColor,
|
|
25
|
+
animate = true,
|
|
26
|
+
facing = 'right'
|
|
27
|
+
}: Props = $props();
|
|
28
|
+
|
|
29
|
+
// Northern Cardinal colors (male) - from palette
|
|
30
|
+
const body = $derived(bodyColor ?? accents.bird.cardinalRed);
|
|
31
|
+
const mask = $derived(maskColor ?? accents.bird.cardinalMask);
|
|
32
|
+
const beak = $derived(beakColor ?? accents.bird.cardinalBeak);
|
|
33
|
+
const legColor = $derived(bark.darkBark);
|
|
34
|
+
|
|
35
|
+
const scaleX = $derived(facing === 'left' ? -1 : 1);
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<!-- Northern Cardinal - perched, with distinctive crest -->
|
|
39
|
+
<svg
|
|
40
|
+
class="{className} {animate ? 'bob' : ''}"
|
|
41
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
42
|
+
viewBox="0 0 50 60"
|
|
43
|
+
style="transform: scaleX({scaleX}); {style ?? ''}"
|
|
44
|
+
>
|
|
45
|
+
<!-- Tail feathers - long and red -->
|
|
46
|
+
<path fill={body} d="M5 35 Q0 40 2 50 Q8 48 12 42 Q14 38 10 34 Q7 33 5 35" />
|
|
47
|
+
<path fill="#b91c1c" d="M6 36 Q3 42 4 48 Q8 46 10 42" opacity="0.6" />
|
|
48
|
+
|
|
49
|
+
<!-- Body - bright red -->
|
|
50
|
+
<ellipse fill={body} cx="22" cy="32" rx="14" ry="12" />
|
|
51
|
+
|
|
52
|
+
<!-- Wing - slightly darker red with feather details -->
|
|
53
|
+
<path fill="#b91c1c" d="M10 28 Q6 34 9 42 Q16 40 20 34 Q18 27 10 28" />
|
|
54
|
+
<path fill="#991b1b" d="M12 32 Q10 36 12 40 Q15 38 16 35 Q14 32 12 32" opacity="0.5" />
|
|
55
|
+
|
|
56
|
+
<!-- Breast - lighter red highlight -->
|
|
57
|
+
<ellipse fill="#ef4444" cx="30" cy="35" rx="8" ry="9" opacity="0.7" />
|
|
58
|
+
|
|
59
|
+
<!-- Head - red with crest -->
|
|
60
|
+
<circle fill={body} cx="36" cy="20" r="10" />
|
|
61
|
+
|
|
62
|
+
<!-- Distinctive crest (pointed tuft) -->
|
|
63
|
+
<path fill={body} d="M32 12 Q36 5 38 8 Q40 10 38 14 Q35 13 32 12" />
|
|
64
|
+
<path fill="#ef4444" d="M34 10 Q36 6 37 9" opacity="0.5" />
|
|
65
|
+
|
|
66
|
+
<!-- Black mask - surrounds eye and covers throat -->
|
|
67
|
+
<path fill={mask} d="M38 16 Q44 14 46 18 Q46 22 44 24 Q40 26 36 26 Q32 24 32 20 Q34 16 38 16" />
|
|
68
|
+
|
|
69
|
+
<!-- Eye - visible within mask -->
|
|
70
|
+
<circle fill="#1a1a1a" cx="40" cy="19" r="2.5" />
|
|
71
|
+
<!-- Eye highlight -->
|
|
72
|
+
<circle fill="white" cx="41" cy="18" r="0.8" />
|
|
73
|
+
|
|
74
|
+
<!-- Beak - thick orange-red cone shape (cardinal signature) -->
|
|
75
|
+
<path fill={beak} d="M44 20 L52 21 L44 24 Q43 22 44 20" />
|
|
76
|
+
<!-- Beak curve detail -->
|
|
77
|
+
<path fill="#ea580c" d="M45 21 Q48 21 50 21.5" stroke="#c2410c" stroke-width="0.3" />
|
|
78
|
+
|
|
79
|
+
<!-- Legs - dark -->
|
|
80
|
+
<g fill="none" stroke={legColor} stroke-width="1.5">
|
|
81
|
+
<path d="M20 44 L20 54 M18 52 L22 52" />
|
|
82
|
+
<path d="M26 44 L26 54 M24 52 L28 52" />
|
|
83
|
+
</g>
|
|
84
|
+
</svg>
|
|
85
|
+
|
|
86
|
+
<style>
|
|
87
|
+
@keyframes bob {
|
|
88
|
+
0%, 100% { transform: translateY(0); }
|
|
89
|
+
50% { transform: translateY(-1.5px); }
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.bob {
|
|
93
|
+
animation: bob 2.5s ease-in-out infinite;
|
|
94
|
+
}
|
|
95
|
+
</style>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
class?: string;
|
|
3
|
+
style?: string;
|
|
4
|
+
bodyColor?: string;
|
|
5
|
+
maskColor?: string;
|
|
6
|
+
beakColor?: string;
|
|
7
|
+
animate?: boolean;
|
|
8
|
+
facing?: 'left' | 'right';
|
|
9
|
+
}
|
|
10
|
+
declare const Cardinal: import("svelte").Component<Props, {}, "">;
|
|
11
|
+
type Cardinal = ReturnType<typeof Cardinal>;
|
|
12
|
+
export default Cardinal;
|
|
@@ -0,0 +1,97 @@
|
|
|
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 { bark, accents } from '../palette';
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
class?: string;
|
|
11
|
+
style?: string;
|
|
12
|
+
capColor?: string;
|
|
13
|
+
cheekColor?: string;
|
|
14
|
+
bodyColor?: string;
|
|
15
|
+
animate?: boolean;
|
|
16
|
+
facing?: 'left' | 'right';
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let {
|
|
20
|
+
class: className = 'w-6 h-6',
|
|
21
|
+
style,
|
|
22
|
+
capColor,
|
|
23
|
+
cheekColor,
|
|
24
|
+
bodyColor,
|
|
25
|
+
animate = true,
|
|
26
|
+
facing = 'right'
|
|
27
|
+
}: Props = $props();
|
|
28
|
+
|
|
29
|
+
// Black-capped Chickadee colors - from palette
|
|
30
|
+
const cap = $derived(capColor ?? accents.bird.chickadeeCap);
|
|
31
|
+
const cheek = $derived(cheekColor ?? accents.bird.chickadeeCheek);
|
|
32
|
+
const body = $derived(bodyColor ?? accents.bird.chickadeeBody);
|
|
33
|
+
const belly = $derived(accents.bird.chickadeeBelly);
|
|
34
|
+
const beak = $derived(accents.bird.chickadeeCap); // Same black as cap
|
|
35
|
+
const legColor = $derived(bark.darkBark);
|
|
36
|
+
|
|
37
|
+
const scaleX = $derived(facing === 'left' ? -1 : 1);
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<!-- Black-capped Chickadee - small, round, perched -->
|
|
41
|
+
<svg
|
|
42
|
+
class="{className} {animate ? 'bob' : ''}"
|
|
43
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
44
|
+
viewBox="0 0 45 50"
|
|
45
|
+
style="transform: scaleX({scaleX}); {style ?? ''}"
|
|
46
|
+
>
|
|
47
|
+
<!-- Tail - short gray -->
|
|
48
|
+
<path fill={body} d="M5 28 Q2 32 4 38 Q10 36 12 30 Q9 27 5 28" />
|
|
49
|
+
|
|
50
|
+
<!-- Body - round gray back -->
|
|
51
|
+
<ellipse fill={body} cx="20" cy="28" rx="12" ry="10" />
|
|
52
|
+
|
|
53
|
+
<!-- Wing detail -->
|
|
54
|
+
<path fill="#4b5563" d="M10 25 Q7 30 10 35 Q15 33 17 28 Q14 24 10 25" opacity="0.8" />
|
|
55
|
+
<!-- Wing bars (subtle white edges) -->
|
|
56
|
+
<path fill="white" d="M9 30 Q12 29 14 30" opacity="0.4" stroke="white" stroke-width="0.5" />
|
|
57
|
+
|
|
58
|
+
<!-- Buff belly -->
|
|
59
|
+
<ellipse fill={belly} cx="26" cy="32" rx="7" ry="8" />
|
|
60
|
+
|
|
61
|
+
<!-- Head - round -->
|
|
62
|
+
<circle fill={body} cx="30" cy="18" r="9" />
|
|
63
|
+
|
|
64
|
+
<!-- Black cap (covers top of head) -->
|
|
65
|
+
<path fill={cap} d="M22 14 Q26 8 34 10 Q38 12 38 16 Q36 14 30 14 Q24 14 22 14" />
|
|
66
|
+
|
|
67
|
+
<!-- White cheek patch (signature chickadee feature) -->
|
|
68
|
+
<ellipse fill={cheek} cx="32" cy="18" rx="5" ry="4" />
|
|
69
|
+
|
|
70
|
+
<!-- Black bib under beak -->
|
|
71
|
+
<path fill={cap} d="M28 22 Q32 21 35 22 Q34 26 31 27 Q28 26 28 22" />
|
|
72
|
+
|
|
73
|
+
<!-- Eye - small and dark -->
|
|
74
|
+
<circle fill="#1a1a1a" cx="33" cy="16" r="1.5" />
|
|
75
|
+
<!-- Eye highlight -->
|
|
76
|
+
<circle fill="white" cx="33.5" cy="15.5" r="0.5" />
|
|
77
|
+
|
|
78
|
+
<!-- Beak - tiny and black -->
|
|
79
|
+
<path fill={beak} d="M38 17 L42 18 L38 19 Z" />
|
|
80
|
+
|
|
81
|
+
<!-- Legs - thin and dark -->
|
|
82
|
+
<g fill="none" stroke={legColor} stroke-width="1.2">
|
|
83
|
+
<path d="M17 38 L17 46 M15 44 L19 44" />
|
|
84
|
+
<path d="M23 38 L23 46 M21 44 L25 44" />
|
|
85
|
+
</g>
|
|
86
|
+
</svg>
|
|
87
|
+
|
|
88
|
+
<style>
|
|
89
|
+
@keyframes bob {
|
|
90
|
+
0%, 100% { transform: translateY(0); }
|
|
91
|
+
50% { transform: translateY(-1px); }
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.bob {
|
|
95
|
+
animation: bob 1.8s ease-in-out infinite;
|
|
96
|
+
}
|
|
97
|
+
</style>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
class?: string;
|
|
3
|
+
style?: string;
|
|
4
|
+
capColor?: string;
|
|
5
|
+
cheekColor?: string;
|
|
6
|
+
bodyColor?: string;
|
|
7
|
+
animate?: boolean;
|
|
8
|
+
facing?: 'left' | 'right';
|
|
9
|
+
}
|
|
10
|
+
declare const Chickadee: import("svelte").Component<Props, {}, "">;
|
|
11
|
+
type Chickadee = ReturnType<typeof Chickadee>;
|
|
12
|
+
export default Chickadee;
|
|
@@ -0,0 +1,95 @@
|
|
|
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 { earth, bark, natural } from '../palette';
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
class?: string;
|
|
11
|
+
furColor?: string;
|
|
12
|
+
animate?: boolean;
|
|
13
|
+
facing?: 'left' | 'right';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let {
|
|
17
|
+
class: className = 'w-12 h-12',
|
|
18
|
+
furColor,
|
|
19
|
+
animate = true,
|
|
20
|
+
facing = 'right'
|
|
21
|
+
}: Props = $props();
|
|
22
|
+
|
|
23
|
+
const fur = $derived(furColor ?? earth.clay);
|
|
24
|
+
const darkFur = $derived(bark.bark);
|
|
25
|
+
const lightFur = $derived(natural.cream);
|
|
26
|
+
const scaleX = $derived(facing === 'left' ? -1 : 1);
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<!-- Standing deer -->
|
|
30
|
+
<svg
|
|
31
|
+
class={className}
|
|
32
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
33
|
+
viewBox="0 0 80 100"
|
|
34
|
+
style="transform: scaleX({scaleX})"
|
|
35
|
+
>
|
|
36
|
+
<!-- Back legs -->
|
|
37
|
+
<path fill={fur} d="M20 65 L18 95 L24 95 L26 70 Q23 67 20 65" />
|
|
38
|
+
<path fill={fur} d="M30 68 L28 95 L34 95 L36 72 Q33 69 30 68" />
|
|
39
|
+
|
|
40
|
+
<!-- Body -->
|
|
41
|
+
<ellipse fill={fur} cx="35" cy="55" rx="22" ry="16" />
|
|
42
|
+
|
|
43
|
+
<!-- Front legs -->
|
|
44
|
+
<path fill={fur} d="M48 65 L46 95 L52 95 L54 68 Q51 65 48 65" />
|
|
45
|
+
<path fill={fur} d="M55 62 L55 95 L61 95 L61 65 Q58 62 55 62" />
|
|
46
|
+
|
|
47
|
+
<!-- Chest -->
|
|
48
|
+
<ellipse fill={lightFur} cx="52" cy="58" rx="8" ry="10" opacity="0.6" />
|
|
49
|
+
|
|
50
|
+
<!-- Neck -->
|
|
51
|
+
<path fill={fur} d="M50 50 Q55 35 52 25 Q60 30 65 45 Q58 52 50 50" />
|
|
52
|
+
|
|
53
|
+
<!-- Head -->
|
|
54
|
+
<ellipse fill={fur} cx="52" cy="22" rx="12" ry="10" />
|
|
55
|
+
|
|
56
|
+
<!-- Snout -->
|
|
57
|
+
<ellipse fill={darkFur} cx="62" cy="25" rx="6" ry="5" />
|
|
58
|
+
<ellipse fill="#1a1a1a" cx="66" cy="24" rx="1.5" ry="1" />
|
|
59
|
+
|
|
60
|
+
<!-- Ears -->
|
|
61
|
+
<g class={animate ? 'ear-flick' : ''}>
|
|
62
|
+
<ellipse fill={fur} cx="45" cy="12" rx="5" ry="8" transform="rotate(-30 45 12)" />
|
|
63
|
+
<ellipse fill={lightFur} cx="45" cy="12" rx="2.5" ry="5" transform="rotate(-30 45 12)" />
|
|
64
|
+
</g>
|
|
65
|
+
<ellipse fill={fur} cx="55" cy="10" rx="5" ry="8" transform="rotate(10 55 10)" />
|
|
66
|
+
<ellipse fill={lightFur} cx="55" cy="10" rx="2.5" ry="5" transform="rotate(10 55 10)" />
|
|
67
|
+
|
|
68
|
+
<!-- Eye -->
|
|
69
|
+
<circle fill="#1a1a1a" cx="55" cy="20" r="2" />
|
|
70
|
+
<circle fill="white" cx="55.5" cy="19.5" r="0.8" />
|
|
71
|
+
|
|
72
|
+
<!-- Spots (fawn pattern) -->
|
|
73
|
+
<circle fill={lightFur} cx="25" cy="52" r="2" opacity="0.4" />
|
|
74
|
+
<circle fill={lightFur} cx="32" cy="48" r="1.5" opacity="0.4" />
|
|
75
|
+
<circle fill={lightFur} cx="40" cy="55" r="2" opacity="0.4" />
|
|
76
|
+
<circle fill={lightFur} cx="35" cy="60" r="1.5" opacity="0.4" />
|
|
77
|
+
|
|
78
|
+
<!-- Tail -->
|
|
79
|
+
<ellipse fill={fur} cx="13" cy="52" rx="4" ry="6" />
|
|
80
|
+
<ellipse fill={lightFur} cx="12" cy="53" rx="2" ry="4" />
|
|
81
|
+
</svg>
|
|
82
|
+
|
|
83
|
+
<style>
|
|
84
|
+
@keyframes ear-flick {
|
|
85
|
+
0%, 85%, 100% { transform: rotate(-30deg); }
|
|
86
|
+
88% { transform: rotate(-20deg); }
|
|
87
|
+
91% { transform: rotate(-35deg); }
|
|
88
|
+
94% { transform: rotate(-28deg); }
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.ear-flick {
|
|
92
|
+
transform-origin: center bottom;
|
|
93
|
+
animation: ear-flick 5s ease-in-out infinite;
|
|
94
|
+
}
|
|
95
|
+
</style>
|
|
@@ -0,0 +1,111 @@
|
|
|
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 { accents, greens } from '../palette';
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
class?: string;
|
|
11
|
+
glowColor?: string;
|
|
12
|
+
bodyColor?: string;
|
|
13
|
+
animate?: boolean;
|
|
14
|
+
intensity?: 'subtle' | 'normal' | 'bright';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let {
|
|
18
|
+
class: className = 'w-3 h-3',
|
|
19
|
+
glowColor,
|
|
20
|
+
bodyColor,
|
|
21
|
+
animate = true,
|
|
22
|
+
intensity = 'normal'
|
|
23
|
+
}: Props = $props();
|
|
24
|
+
|
|
25
|
+
const glow = $derived(glowColor ?? accents.firefly.glow);
|
|
26
|
+
const body = $derived(bodyColor ?? accents.firefly.body);
|
|
27
|
+
|
|
28
|
+
const glowOpacity = $derived({
|
|
29
|
+
subtle: 0.4,
|
|
30
|
+
normal: 0.6,
|
|
31
|
+
bright: 0.8
|
|
32
|
+
}[intensity]);
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<!-- Firefly with glowing abdomen -->
|
|
36
|
+
<svg class="{className} {animate ? 'float' : ''}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30">
|
|
37
|
+
<!-- Outer glow -->
|
|
38
|
+
<circle
|
|
39
|
+
fill={glow}
|
|
40
|
+
cx="15"
|
|
41
|
+
cy="18"
|
|
42
|
+
r="12"
|
|
43
|
+
opacity={glowOpacity}
|
|
44
|
+
class={animate ? 'pulse' : ''}
|
|
45
|
+
/>
|
|
46
|
+
|
|
47
|
+
<!-- Inner glow -->
|
|
48
|
+
<circle
|
|
49
|
+
fill={glow}
|
|
50
|
+
cx="15"
|
|
51
|
+
cy="18"
|
|
52
|
+
r="7"
|
|
53
|
+
opacity={glowOpacity + 0.2}
|
|
54
|
+
class={animate ? 'pulse-inner' : ''}
|
|
55
|
+
/>
|
|
56
|
+
|
|
57
|
+
<!-- Body -->
|
|
58
|
+
<ellipse fill={body} cx="15" cy="12" rx="3" ry="4" />
|
|
59
|
+
|
|
60
|
+
<!-- Glowing abdomen -->
|
|
61
|
+
<ellipse fill={glow} cx="15" cy="18" rx="4" ry="5" class={animate ? 'glow' : ''} />
|
|
62
|
+
|
|
63
|
+
<!-- Wings (subtle) -->
|
|
64
|
+
<ellipse fill={greens.pale} cx="11" cy="10" rx="4" ry="2" opacity="0.3" transform="rotate(-20 11 10)" />
|
|
65
|
+
<ellipse fill={greens.pale} cx="19" cy="10" rx="4" ry="2" opacity="0.3" transform="rotate(20 19 10)" />
|
|
66
|
+
|
|
67
|
+
<!-- Antennae -->
|
|
68
|
+
<path fill="none" stroke={body} stroke-width="0.5" d="M13 8 Q11 4 10 3" />
|
|
69
|
+
<path fill="none" stroke={body} stroke-width="0.5" d="M17 8 Q19 4 20 3" />
|
|
70
|
+
</svg>
|
|
71
|
+
|
|
72
|
+
<style>
|
|
73
|
+
@keyframes float {
|
|
74
|
+
0%, 100% { transform: translateY(0) translateX(0); }
|
|
75
|
+
25% { transform: translateY(-3px) translateX(2px); }
|
|
76
|
+
50% { transform: translateY(-1px) translateX(-1px); }
|
|
77
|
+
75% { transform: translateY(-4px) translateX(1px); }
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@keyframes pulse {
|
|
81
|
+
0%, 100% { opacity: 0.4; }
|
|
82
|
+
50% { opacity: 0.7; }
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@keyframes pulse-inner {
|
|
86
|
+
0%, 100% { opacity: 0.6; }
|
|
87
|
+
50% { opacity: 0.9; }
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@keyframes glow {
|
|
91
|
+
0%, 100% { filter: brightness(1); }
|
|
92
|
+
50% { filter: brightness(1.3); }
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.float {
|
|
96
|
+
animation: float 4s ease-in-out infinite;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.pulse {
|
|
100
|
+
animation: pulse 2s ease-in-out infinite;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.pulse-inner {
|
|
104
|
+
animation: pulse-inner 2s ease-in-out infinite;
|
|
105
|
+
animation-delay: 0.2s;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.glow {
|
|
109
|
+
animation: glow 2s ease-in-out infinite;
|
|
110
|
+
}
|
|
111
|
+
</style>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
class?: string;
|
|
3
|
+
glowColor?: string;
|
|
4
|
+
bodyColor?: string;
|
|
5
|
+
animate?: boolean;
|
|
6
|
+
intensity?: 'subtle' | 'normal' | 'bright';
|
|
7
|
+
}
|
|
8
|
+
declare const Firefly: import("svelte").Component<Props, {}, "">;
|
|
9
|
+
type Firefly = ReturnType<typeof Firefly>;
|
|
10
|
+
export default Firefly;
|
|
@@ -0,0 +1,91 @@
|
|
|
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 { bark, earth, accents } from '../palette';
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
class?: string;
|
|
11
|
+
featherColor?: string;
|
|
12
|
+
animate?: boolean;
|
|
13
|
+
facing?: 'left' | 'right';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let {
|
|
17
|
+
class: className = 'w-8 h-10',
|
|
18
|
+
featherColor,
|
|
19
|
+
animate = true,
|
|
20
|
+
facing = 'right'
|
|
21
|
+
}: Props = $props();
|
|
22
|
+
|
|
23
|
+
const feathers = $derived(featherColor ?? bark.bark);
|
|
24
|
+
const lightFeathers = $derived(earth.clay);
|
|
25
|
+
const eyeColor = $derived(accents.flower.yellow);
|
|
26
|
+
const scaleX = $derived(facing === 'left' ? -1 : 1);
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<!-- Perched owl -->
|
|
30
|
+
<svg
|
|
31
|
+
class={className}
|
|
32
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
33
|
+
viewBox="0 0 50 70"
|
|
34
|
+
style="transform: scaleX({scaleX})"
|
|
35
|
+
>
|
|
36
|
+
<!-- Body -->
|
|
37
|
+
<ellipse fill={feathers} cx="25" cy="45" rx="18" ry="20" />
|
|
38
|
+
|
|
39
|
+
<!-- Chest pattern -->
|
|
40
|
+
<ellipse fill={lightFeathers} cx="25" cy="48" rx="12" ry="15" />
|
|
41
|
+
<!-- Chest feather lines -->
|
|
42
|
+
<path fill="none" stroke={feathers} stroke-width="0.5" d="M18 40 Q25 42 32 40" opacity="0.5" />
|
|
43
|
+
<path fill="none" stroke={feathers} stroke-width="0.5" d="M16 46 Q25 48 34 46" opacity="0.5" />
|
|
44
|
+
<path fill="none" stroke={feathers} stroke-width="0.5" d="M17 52 Q25 54 33 52" opacity="0.5" />
|
|
45
|
+
<path fill="none" stroke={feathers} stroke-width="0.5" d="M18 58 Q25 60 32 58" opacity="0.5" />
|
|
46
|
+
|
|
47
|
+
<!-- Head -->
|
|
48
|
+
<circle fill={feathers} cx="25" cy="20" r="16" />
|
|
49
|
+
|
|
50
|
+
<!-- Ear tufts -->
|
|
51
|
+
<path fill={feathers} d="M12 10 Q8 2 12 0 Q14 5 16 10" />
|
|
52
|
+
<path fill={feathers} d="M38 10 Q42 2 38 0 Q36 5 34 10" />
|
|
53
|
+
|
|
54
|
+
<!-- Facial disc -->
|
|
55
|
+
<circle fill={lightFeathers} cx="25" cy="22" r="12" />
|
|
56
|
+
|
|
57
|
+
<!-- Eyes -->
|
|
58
|
+
<g class={animate ? 'blink' : ''}>
|
|
59
|
+
<circle fill={eyeColor} cx="18" cy="20" r="5" />
|
|
60
|
+
<circle fill="#1a1a1a" cx="18" cy="20" r="3" />
|
|
61
|
+
<circle fill="white" cx="19" cy="19" r="1" />
|
|
62
|
+
|
|
63
|
+
<circle fill={eyeColor} cx="32" cy="20" r="5" />
|
|
64
|
+
<circle fill="#1a1a1a" cx="32" cy="20" r="3" />
|
|
65
|
+
<circle fill="white" cx="33" cy="19" r="1" />
|
|
66
|
+
</g>
|
|
67
|
+
|
|
68
|
+
<!-- Beak -->
|
|
69
|
+
<path fill={bark.warmBark} d="M25 24 L22 28 L25 32 L28 28 Z" />
|
|
70
|
+
|
|
71
|
+
<!-- Feet -->
|
|
72
|
+
<path fill={bark.warmBark} d="M18 64 L15 70 M18 64 L18 70 M18 64 L21 70" stroke={bark.warmBark} stroke-width="1.5" />
|
|
73
|
+
<path fill={bark.warmBark} d="M32 64 L29 70 M32 64 L32 70 M32 64 L35 70" stroke={bark.warmBark} stroke-width="1.5" />
|
|
74
|
+
|
|
75
|
+
<!-- Wing hints -->
|
|
76
|
+
<path fill={feathers} d="M8 35 Q5 45 8 55 Q12 50 12 40 Q10 35 8 35" opacity="0.7" />
|
|
77
|
+
<path fill={feathers} d="M42 35 Q45 45 42 55 Q38 50 38 40 Q40 35 42 35" opacity="0.7" />
|
|
78
|
+
</svg>
|
|
79
|
+
|
|
80
|
+
<style>
|
|
81
|
+
@keyframes blink {
|
|
82
|
+
0%, 94%, 100% { transform: scaleY(1); }
|
|
83
|
+
96% { transform: scaleY(0.1); }
|
|
84
|
+
98% { transform: scaleY(1); }
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.blink {
|
|
88
|
+
transform-origin: center center;
|
|
89
|
+
animation: blink 4s ease-in-out infinite;
|
|
90
|
+
}
|
|
91
|
+
</style>
|
|
@@ -0,0 +1,90 @@
|
|
|
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 { earth, natural } from '../palette';
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
class?: string;
|
|
11
|
+
furColor?: string;
|
|
12
|
+
animate?: boolean;
|
|
13
|
+
facing?: 'left' | 'right';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let {
|
|
17
|
+
class: className = 'w-8 h-8',
|
|
18
|
+
furColor,
|
|
19
|
+
animate = true,
|
|
20
|
+
facing = 'right'
|
|
21
|
+
}: Props = $props();
|
|
22
|
+
|
|
23
|
+
const fur = $derived(furColor ?? earth.clay);
|
|
24
|
+
const innerEar = $derived(natural.cream);
|
|
25
|
+
const scaleX = $derived(facing === 'left' ? -1 : 1);
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<!-- Sitting rabbit -->
|
|
29
|
+
<svg
|
|
30
|
+
class={className}
|
|
31
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
32
|
+
viewBox="0 0 50 60"
|
|
33
|
+
style="transform: scaleX({scaleX})"
|
|
34
|
+
>
|
|
35
|
+
<!-- Back leg -->
|
|
36
|
+
<ellipse fill={fur} cx="15" cy="50" rx="10" ry="8" />
|
|
37
|
+
|
|
38
|
+
<!-- Body -->
|
|
39
|
+
<ellipse fill={fur} cx="22" cy="42" rx="14" ry="12" />
|
|
40
|
+
|
|
41
|
+
<!-- Front leg -->
|
|
42
|
+
<ellipse fill={fur} cx="32" cy="52" rx="5" ry="7" />
|
|
43
|
+
|
|
44
|
+
<!-- Head -->
|
|
45
|
+
<circle fill={fur} cx="35" cy="28" r="12" />
|
|
46
|
+
|
|
47
|
+
<!-- Ears -->
|
|
48
|
+
<g class={animate ? 'ear-twitch' : ''}>
|
|
49
|
+
<ellipse fill={fur} cx="30" cy="10" rx="4" ry="12" />
|
|
50
|
+
<ellipse fill={innerEar} cx="30" cy="10" rx="2" ry="8" />
|
|
51
|
+
</g>
|
|
52
|
+
<g class={animate ? 'ear-twitch-delay' : ''}>
|
|
53
|
+
<ellipse fill={fur} cx="40" cy="8" rx="4" ry="12" transform="rotate(15 40 8)" />
|
|
54
|
+
<ellipse fill={innerEar} cx="40" cy="8" rx="2" ry="8" transform="rotate(15 40 8)" />
|
|
55
|
+
</g>
|
|
56
|
+
|
|
57
|
+
<!-- Eye -->
|
|
58
|
+
<circle fill="#1a1a1a" cx="40" cy="26" r="2.5" />
|
|
59
|
+
<circle fill="white" cx="41" cy="25" r="1" />
|
|
60
|
+
|
|
61
|
+
<!-- Nose -->
|
|
62
|
+
<ellipse fill={innerEar} cx="46" cy="30" rx="2" ry="1.5" />
|
|
63
|
+
|
|
64
|
+
<!-- Whiskers -->
|
|
65
|
+
<path fill="none" stroke={earth.stone} stroke-width="0.5" d="M46 30 L54 28" opacity="0.5" />
|
|
66
|
+
<path fill="none" stroke={earth.stone} stroke-width="0.5" d="M46 31 L54 31" opacity="0.5" />
|
|
67
|
+
<path fill="none" stroke={earth.stone} stroke-width="0.5" d="M46 32 L54 34" opacity="0.5" />
|
|
68
|
+
|
|
69
|
+
<!-- Tail -->
|
|
70
|
+
<circle fill={natural.cream} cx="8" cy="40" r="5" />
|
|
71
|
+
</svg>
|
|
72
|
+
|
|
73
|
+
<style>
|
|
74
|
+
@keyframes ear-twitch {
|
|
75
|
+
0%, 90%, 100% { transform: rotate(0deg); }
|
|
76
|
+
93% { transform: rotate(-5deg); }
|
|
77
|
+
96% { transform: rotate(3deg); }
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.ear-twitch {
|
|
81
|
+
transform-origin: center bottom;
|
|
82
|
+
animation: ear-twitch 4s ease-in-out infinite;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.ear-twitch-delay {
|
|
86
|
+
transform-origin: center bottom;
|
|
87
|
+
animation: ear-twitch 4s ease-in-out infinite;
|
|
88
|
+
animation-delay: 0.1s;
|
|
89
|
+
}
|
|
90
|
+
</style>
|