@mumulinya167/ccm-pet-assets 2.0.0
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/README.md +4 -0
- package/assets/calico/calico-collapsing.apng +0 -0
- package/assets/calico/calico-dozing.apng +0 -0
- package/assets/calico/calico-error.apng +0 -0
- package/assets/calico/calico-happy.apng +0 -0
- package/assets/calico/calico-idle-follow.svg +324 -0
- package/assets/calico/calico-idle.apng +0 -0
- package/assets/calico/calico-mini-alert.apng +0 -0
- package/assets/calico/calico-mini-crabwalk.apng +0 -0
- package/assets/calico/calico-mini-enter.apng +0 -0
- package/assets/calico/calico-mini-happy.apng +0 -0
- package/assets/calico/calico-mini-idle.apng +0 -0
- package/assets/calico/calico-mini-peek.apng +0 -0
- package/assets/calico/calico-mini-sleep.apng +0 -0
- package/assets/calico/calico-notification.apng +0 -0
- package/assets/calico/calico-react-drag.apng +0 -0
- package/assets/calico/calico-react-left.apng +0 -0
- package/assets/calico/calico-react-poke.apng +0 -0
- package/assets/calico/calico-sleeping.apng +0 -0
- package/assets/calico/calico-thinking.apng +0 -0
- package/assets/calico/calico-waking.apng +0 -0
- package/assets/calico/calico-working-building.apng +0 -0
- package/assets/calico/calico-working-carrying.apng +0 -0
- package/assets/calico/calico-working-conducting.apng +0 -0
- package/assets/calico/calico-working-juggling.apng +0 -0
- package/assets/calico/calico-working-sweeping.apng +0 -0
- package/assets/calico/calico-working-typing.apng +0 -0
- package/assets/calico/calico-yawning.apng +0 -0
- package/assets/calico.svg +324 -0
- package/assets/clawd/LICENSE +22 -0
- package/assets/clawd/clawd-about-hero.svg +202 -0
- package/assets/clawd/clawd-collapse-sleep.svg +247 -0
- package/assets/clawd/clawd-error.svg +94 -0
- package/assets/clawd/clawd-happy.svg +161 -0
- package/assets/clawd/clawd-headphones-groove.svg +194 -0
- package/assets/clawd/clawd-idle-bubble.svg +180 -0
- package/assets/clawd/clawd-idle-collapse.svg +101 -0
- package/assets/clawd/clawd-idle-doze.svg +72 -0
- package/assets/clawd/clawd-idle-follow.svg +64 -0
- package/assets/clawd/clawd-idle-living.svg +196 -0
- package/assets/clawd/clawd-idle-look.svg +115 -0
- package/assets/clawd/clawd-idle-reading.svg +252 -0
- package/assets/clawd/clawd-idle-yawn.svg +158 -0
- package/assets/clawd/clawd-mini-alert.svg +129 -0
- package/assets/clawd/clawd-mini-crabwalk.svg +76 -0
- package/assets/clawd/clawd-mini-enter-sleep.svg +64 -0
- package/assets/clawd/clawd-mini-enter.svg +114 -0
- package/assets/clawd/clawd-mini-happy.svg +124 -0
- package/assets/clawd/clawd-mini-idle.svg +83 -0
- package/assets/clawd/clawd-mini-peek.svg +82 -0
- package/assets/clawd/clawd-mini-sleep.svg +112 -0
- package/assets/clawd/clawd-mini-typing.svg +153 -0
- package/assets/clawd/clawd-notification.svg +438 -0
- package/assets/clawd/clawd-react-annoyed.svg +167 -0
- package/assets/clawd/clawd-react-double-jump.svg +229 -0
- package/assets/clawd/clawd-react-double.svg +108 -0
- package/assets/clawd/clawd-react-drag.svg +102 -0
- package/assets/clawd/clawd-react-left.svg +102 -0
- package/assets/clawd/clawd-react-right.svg +102 -0
- package/assets/clawd/clawd-sleeping.svg +118 -0
- package/assets/clawd/clawd-static-base.svg +21 -0
- package/assets/clawd/clawd-wake.svg +277 -0
- package/assets/clawd/clawd-working-building.svg +329 -0
- package/assets/clawd/clawd-working-carrying.svg +178 -0
- package/assets/clawd/clawd-working-debugger.svg +245 -0
- package/assets/clawd/clawd-working-juggling.svg +183 -0
- package/assets/clawd/clawd-working-sweeping.svg +248 -0
- package/assets/clawd/clawd-working-thinking.svg +501 -0
- package/assets/clawd/clawd-working-typing-boss.svg +307 -0
- package/assets/clawd/clawd-working-typing.svg +273 -0
- package/assets/clawd/clawd-working-ultrathink.svg +166 -0
- package/assets/clawd/clawd-working-wizard.svg +356 -0
- package/assets/clawd.svg +64 -0
- package/assets/cloudling/cloudling/cloudling-attention.svg +380 -0
- package/assets/cloudling/cloudling/cloudling-building.svg +667 -0
- package/assets/cloudling/cloudling/cloudling-carrying.svg +604 -0
- package/assets/cloudling/cloudling/cloudling-conducting.svg +616 -0
- package/assets/cloudling/cloudling/cloudling-dozing-to-sleeping.svg +578 -0
- package/assets/cloudling/cloudling/cloudling-dozing.svg +358 -0
- package/assets/cloudling/cloudling/cloudling-error.svg +428 -0
- package/assets/cloudling/cloudling/cloudling-idle-reading.svg +658 -0
- package/assets/cloudling/cloudling/cloudling-idle-to-dozing.svg +568 -0
- package/assets/cloudling/cloudling/cloudling-idle-to-sleeping.svg +811 -0
- package/assets/cloudling/cloudling/cloudling-idle.svg +255 -0
- package/assets/cloudling/cloudling/cloudling-juggling.svg +648 -0
- package/assets/cloudling/cloudling/cloudling-mini-alert.svg +390 -0
- package/assets/cloudling/cloudling/cloudling-mini-crabwalk.svg +335 -0
- package/assets/cloudling/cloudling/cloudling-mini-enter-roll-in.svg +226 -0
- package/assets/cloudling/cloudling/cloudling-mini-enter-sleep.svg +232 -0
- package/assets/cloudling/cloudling/cloudling-mini-happy.svg +371 -0
- package/assets/cloudling/cloudling/cloudling-mini-idle.svg +279 -0
- package/assets/cloudling/cloudling/cloudling-mini-peek.svg +328 -0
- package/assets/cloudling/cloudling/cloudling-mini-sleep.svg +260 -0
- package/assets/cloudling/cloudling/cloudling-mini-typing.svg +692 -0
- package/assets/cloudling/cloudling/cloudling-notification.svg +494 -0
- package/assets/cloudling/cloudling/cloudling-react-drag.svg +83 -0
- package/assets/cloudling/cloudling/cloudling-sleeping-to-idle.svg +555 -0
- package/assets/cloudling/cloudling/cloudling-sleeping.svg +500 -0
- package/assets/cloudling/cloudling/cloudling-sweeping.svg +292 -0
- package/assets/cloudling/cloudling/cloudling-thinking.svg +720 -0
- package/assets/cloudling/cloudling/cloudling-typing.svg +354 -0
- package/assets/cloudling/cloudling-attention.svg +380 -0
- package/assets/cloudling/cloudling-building.svg +667 -0
- package/assets/cloudling/cloudling-carrying.svg +604 -0
- package/assets/cloudling/cloudling-conducting.svg +616 -0
- package/assets/cloudling/cloudling-dozing-to-sleeping.svg +578 -0
- package/assets/cloudling/cloudling-dozing.svg +358 -0
- package/assets/cloudling/cloudling-error.svg +428 -0
- package/assets/cloudling/cloudling-idle-reading.svg +658 -0
- package/assets/cloudling/cloudling-idle-to-dozing.svg +568 -0
- package/assets/cloudling/cloudling-idle-to-sleeping.svg +811 -0
- package/assets/cloudling/cloudling-idle.svg +255 -0
- package/assets/cloudling/cloudling-juggling.svg +648 -0
- package/assets/cloudling/cloudling-mini-alert.svg +390 -0
- package/assets/cloudling/cloudling-mini-crabwalk.svg +335 -0
- package/assets/cloudling/cloudling-mini-enter-roll-in.svg +226 -0
- package/assets/cloudling/cloudling-mini-enter-sleep.svg +232 -0
- package/assets/cloudling/cloudling-mini-happy.svg +371 -0
- package/assets/cloudling/cloudling-mini-idle.svg +279 -0
- package/assets/cloudling/cloudling-mini-peek.svg +328 -0
- package/assets/cloudling/cloudling-mini-sleep.svg +260 -0
- package/assets/cloudling/cloudling-mini-typing.svg +692 -0
- package/assets/cloudling/cloudling-notification.svg +494 -0
- package/assets/cloudling/cloudling-react-drag.svg +83 -0
- package/assets/cloudling/cloudling-sleeping-to-idle.svg +555 -0
- package/assets/cloudling/cloudling-sleeping.svg +500 -0
- package/assets/cloudling/cloudling-sweeping.svg +292 -0
- package/assets/cloudling/cloudling-thinking.svg +720 -0
- package/assets/cloudling/cloudling-typing.svg +354 -0
- package/assets/cloudling.svg +255 -0
- package/assets/ghost-attention.svg +19 -0
- package/assets/ghost-carrying.svg +19 -0
- package/assets/ghost-collapsing.svg +19 -0
- package/assets/ghost-dozing.svg +23 -0
- package/assets/ghost-error.svg +19 -0
- package/assets/ghost-happy.svg +23 -0
- package/assets/ghost-idle-action1.svg +19 -0
- package/assets/ghost-idle-action2.svg +19 -0
- package/assets/ghost-idle-action3.svg +19 -0
- package/assets/ghost-idle.svg +11 -0
- package/assets/ghost-juggling.svg +19 -0
- package/assets/ghost-notification.svg +19 -0
- package/assets/ghost-react-double.svg +23 -0
- package/assets/ghost-react-drag.svg +23 -0
- package/assets/ghost-react-left.svg +19 -0
- package/assets/ghost-react-right.svg +19 -0
- package/assets/ghost-sleeping.svg +19 -0
- package/assets/ghost-sweeping.svg +19 -0
- package/assets/ghost-thinking.svg +19 -0
- package/assets/ghost-waking.svg +19 -0
- package/assets/ghost-working.svg +19 -0
- package/assets/ghost-yawning.svg +23 -0
- package/assets/ghost.svg +11 -0
- package/assets/robot-attention.svg +19 -0
- package/assets/robot-carrying.svg +19 -0
- package/assets/robot-collapsing.svg +19 -0
- package/assets/robot-dozing.svg +23 -0
- package/assets/robot-error.svg +19 -0
- package/assets/robot-happy.svg +23 -0
- package/assets/robot-idle-action1.svg +19 -0
- package/assets/robot-idle-action2.svg +19 -0
- package/assets/robot-idle-action3.svg +19 -0
- package/assets/robot-idle.svg +11 -0
- package/assets/robot-juggling.svg +19 -0
- package/assets/robot-notification.svg +19 -0
- package/assets/robot-react-double.svg +23 -0
- package/assets/robot-react-drag.svg +23 -0
- package/assets/robot-react-left.svg +19 -0
- package/assets/robot-react-right.svg +19 -0
- package/assets/robot-sleeping.svg +19 -0
- package/assets/robot-sweeping.svg +19 -0
- package/assets/robot-thinking.svg +19 -0
- package/assets/robot-waking.svg +19 -0
- package/assets/robot-working.svg +19 -0
- package/assets/robot-yawning.svg +23 -0
- package/assets/robot.svg +11 -0
- package/manifest.json +889 -0
- package/package.json +18 -0
|
@@ -0,0 +1,648 @@
|
|
|
1
|
+
<svg id="stageSvg" xmlns="http://www.w3.org/2000/svg" width="880" height="720" viewBox="-32 -24 88 72" preserveAspectRatio="xMidYMid meet">
|
|
2
|
+
<style><![CDATA[
|
|
3
|
+
#stageBg { fill: #0f0f14; }
|
|
4
|
+
.edge-rim-tight { stroke-opacity: .65; }
|
|
5
|
+
.edge-rim-soft { stroke-opacity: .50; }
|
|
6
|
+
.edge-contact { stroke-opacity: .65; }
|
|
7
|
+
@media (prefers-color-scheme: light) {
|
|
8
|
+
#stageBg { fill: #fff; }
|
|
9
|
+
.edge-rim-tight { stroke-opacity: .75; }
|
|
10
|
+
.edge-rim-soft { stroke-opacity: .60; }
|
|
11
|
+
.edge-contact { stroke-opacity: .75; }
|
|
12
|
+
.cloud-drop-shadow { flood-opacity: .13; }
|
|
13
|
+
.food-cloud-shadow { flood-opacity: .28; flood-color: #5060FF; }
|
|
14
|
+
.food-cloud > path {
|
|
15
|
+
stroke: #5870E8 !important;
|
|
16
|
+
stroke-width: 1.2 !important;
|
|
17
|
+
stroke-opacity: .9 !important;
|
|
18
|
+
vector-effect: non-scaling-stroke !important;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
]]></style>
|
|
22
|
+
<defs>
|
|
23
|
+
<linearGradient id="body-grad" x1="12" y1="2" x2="12" y2="22" gradientUnits="userSpaceOnUse">
|
|
24
|
+
<stop offset="0" stop-color="#f0f9ff"/>
|
|
25
|
+
<stop offset="0.5" stop-color="#e0f2fe"/>
|
|
26
|
+
<stop offset="1" stop-color="#bae6fd"/>
|
|
27
|
+
</linearGradient>
|
|
28
|
+
<linearGradient id="eye-grad" x1="12" y1="3" x2="12" y2="21" gradientUnits="userSpaceOnUse">
|
|
29
|
+
<stop offset="0" stop-color="#B1A7FF"/>
|
|
30
|
+
<stop offset="0.5" stop-color="#7A9DFF"/>
|
|
31
|
+
<stop offset="1" stop-color="#3941FF"/>
|
|
32
|
+
</linearGradient>
|
|
33
|
+
<radialGradient id="hi-grad" cx="0.45" cy="0.25" r="0.55">
|
|
34
|
+
<stop offset="0" stop-color="#f0f9ff" stop-opacity="0.9"/>
|
|
35
|
+
<stop offset="1" stop-color="#f0f9ff" stop-opacity="0"/>
|
|
36
|
+
</radialGradient>
|
|
37
|
+
<linearGradient id="plane-white" x1="5" y1="5" x2="31" y2="25" gradientUnits="userSpaceOnUse">
|
|
38
|
+
<stop id="planeWhite0" offset="0" stop-color="#fff7d6"/>
|
|
39
|
+
<stop id="planeWhite1" offset="0.46" stop-color="#FCE3B0"/>
|
|
40
|
+
<stop id="planeWhite2" offset="1" stop-color="#EFB85C"/>
|
|
41
|
+
</linearGradient>
|
|
42
|
+
<linearGradient id="plane-lavender" x1="4" y1="6" x2="21" y2="32" gradientUnits="userSpaceOnUse">
|
|
43
|
+
<stop id="planeLavender0" offset="0" stop-color="#ffeaf3"/>
|
|
44
|
+
<stop id="planeLavender1" offset="0.54" stop-color="#FCC9DD"/>
|
|
45
|
+
<stop id="planeLavender2" offset="1" stop-color="#D768A0"/>
|
|
46
|
+
</linearGradient>
|
|
47
|
+
<linearGradient id="plane-mid" x1="8" y1="10" x2="25" y2="29" gradientUnits="userSpaceOnUse">
|
|
48
|
+
<stop id="planeMid0" offset="0" stop-color="#dbfff8"/>
|
|
49
|
+
<stop id="planeMid1" offset="0.60" stop-color="#A0E5DD"/>
|
|
50
|
+
<stop id="planeMid2" offset="1" stop-color="#35AFA8"/>
|
|
51
|
+
</linearGradient>
|
|
52
|
+
<linearGradient id="plane-dark" x1="5" y1="8" x2="23" y2="29" gradientUnits="userSpaceOnUse">
|
|
53
|
+
<stop id="planeDark0" offset="0" stop-color="#dcd5ff"/>
|
|
54
|
+
<stop id="planeDark1" offset="0.55" stop-color="#B1A7FF"/>
|
|
55
|
+
<stop id="planeDark2" offset="1" stop-color="#5F52D9"/>
|
|
56
|
+
</linearGradient>
|
|
57
|
+
<filter id="cloud-drop" x="-45%" y="-45%" width="190%" height="190%">
|
|
58
|
+
<feDropShadow class="cloud-drop-shadow" dx="0" dy="0.6" stdDeviation="0.8" flood-color="#3941FF" flood-opacity="0.18"/>
|
|
59
|
+
</filter>
|
|
60
|
+
<filter id="edge-blur" x="-40%" y="-40%" width="180%" height="180%">
|
|
61
|
+
<feGaussianBlur stdDeviation="0.16"/>
|
|
62
|
+
</filter>
|
|
63
|
+
<filter id="plane-drop" x="-45%" y="-45%" width="190%" height="190%">
|
|
64
|
+
<feDropShadow id="planeShadow" dx="0" dy="0.45" stdDeviation="0.65" flood-color="#3941FF" flood-opacity="0.30"/>
|
|
65
|
+
</filter>
|
|
66
|
+
<filter id="trail-blur" x="-80%" y="-90%" width="260%" height="280%">
|
|
67
|
+
<feGaussianBlur stdDeviation="0.10"/>
|
|
68
|
+
</filter>
|
|
69
|
+
<clipPath id="cloud-clip">
|
|
70
|
+
<path id="cloud-clip-path"/>
|
|
71
|
+
</clipPath>
|
|
72
|
+
<g id="paper-plane-symbol">
|
|
73
|
+
<polygon points="3,6 24,23 20.6,29.5" fill="url(#plane-mid)"/>
|
|
74
|
+
<polygon points="3,6 20.1,25.6 20.6,29.5" fill="url(#plane-dark)"/>
|
|
75
|
+
<polygon points="3,6 20.1,25.6 6.7,32.2" fill="url(#plane-lavender)"/>
|
|
76
|
+
<polygon points="3,6 34,15.7 24,23" fill="url(#plane-white)"/>
|
|
77
|
+
<g id="planeFoldLines" stroke="rgba(57,65,255,.38)" stroke-width="0.34" stroke-linecap="round" fill="none">
|
|
78
|
+
<line x1="3" y1="6" x2="24" y2="23"/>
|
|
79
|
+
<line x1="3" y1="6" x2="20.6" y2="29.5"/>
|
|
80
|
+
<line x1="3" y1="6" x2="20.1" y2="25.6"/>
|
|
81
|
+
</g>
|
|
82
|
+
<path id="planeNoseHighlight" d="M 3 6 L 34 15.7" stroke="rgba(255,255,255,.74)" stroke-width="0.3" stroke-linecap="round" fill="none"/>
|
|
83
|
+
</g>
|
|
84
|
+
<g id="paper-plane-under-symbol">
|
|
85
|
+
<polygon id="planeUnderMid" points="3,6 24,23 20.6,29.5" fill="#327E86"/>
|
|
86
|
+
<polygon id="planeUnderDark" points="3,6 20.1,25.6 20.6,29.5" fill="#3F3595"/>
|
|
87
|
+
<polygon id="planeUnderLavender" points="3,6 20.1,25.6 6.7,32.2" fill="#A94B7E"/>
|
|
88
|
+
<polygon id="planeUnderWhite" points="3,6 34,15.7 24,23" fill="#B9863C"/>
|
|
89
|
+
<g id="planeUnderFoldLines" stroke="rgba(255,255,255,.28)" stroke-width="0.32" stroke-linecap="round" fill="none">
|
|
90
|
+
<line x1="3" y1="6" x2="24" y2="23"/>
|
|
91
|
+
<line x1="3" y1="6" x2="20.6" y2="29.5"/>
|
|
92
|
+
<line x1="3" y1="6" x2="20.1" y2="25.6"/>
|
|
93
|
+
</g>
|
|
94
|
+
<path id="planeUnderNoseHighlight" d="M 3 6 L 34 15.7" stroke="rgba(255,255,255,.34)" stroke-width="0.28" stroke-linecap="round" fill="none"/>
|
|
95
|
+
</g>
|
|
96
|
+
</defs>
|
|
97
|
+
<g id="trailBack" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
|
98
|
+
<path id="trailBackSoft" filter="url(#trail-blur)"/>
|
|
99
|
+
<path id="trailBackMain"/>
|
|
100
|
+
<path id="trailBackAccent"/>
|
|
101
|
+
</g>
|
|
102
|
+
<g id="planeBack" filter="url(#plane-drop)">
|
|
103
|
+
<g id="planeBackUnder"><use href="#paper-plane-under-symbol"/></g>
|
|
104
|
+
<g id="planeBackTop"><use href="#paper-plane-symbol"/></g>
|
|
105
|
+
</g>
|
|
106
|
+
|
|
107
|
+
<g id="cloudEdge">
|
|
108
|
+
<path id="edgeContact" class="edge-contact" fill="none" stroke="#7d8aa7" stroke-width="1.05" stroke-linejoin="round" transform="translate(0 0.18)" filter="url(#edge-blur)"/>
|
|
109
|
+
<path id="edgeRimSoft" class="edge-rim-soft" fill="none" stroke="#7A9DFF" stroke-width="0.90" stroke-linejoin="round" filter="url(#edge-blur)"/>
|
|
110
|
+
<path id="edgeRimTight" class="edge-rim-tight" fill="none" stroke="#aab3c6" stroke-width="0.42" stroke-linejoin="round"/>
|
|
111
|
+
</g>
|
|
112
|
+
<g id="cloudGroup" filter="url(#cloud-drop)">
|
|
113
|
+
<path id="cloudPath" fill="url(#body-grad)"/>
|
|
114
|
+
<rect x="1" y="2" width="22" height="11" fill="url(#hi-grad)" clip-path="url(#cloud-clip)"/>
|
|
115
|
+
</g>
|
|
116
|
+
<g id="eyeGroup">
|
|
117
|
+
<rect id="eyeL" x="7.7" y="9.5" width="2.6" height="5" rx="1.3" ry="1.3" fill="url(#eye-grad)" stroke="#ffffff" stroke-width="0.08" stroke-opacity="0.7"/>
|
|
118
|
+
<rect id="eyeR" x="13.7" y="9.5" width="2.6" height="5" rx="1.3" ry="1.3" fill="url(#eye-grad)" stroke="#ffffff" stroke-width="0.08" stroke-opacity="0.7"/>
|
|
119
|
+
</g>
|
|
120
|
+
|
|
121
|
+
<g id="trailFront" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
|
122
|
+
<path id="trailFrontSoft" filter="url(#trail-blur)"/>
|
|
123
|
+
<path id="trailFrontMain"/>
|
|
124
|
+
<path id="trailFrontAccent"/>
|
|
125
|
+
</g>
|
|
126
|
+
<g id="planeFront" filter="url(#plane-drop)">
|
|
127
|
+
<g id="planeFrontUnder"><use href="#paper-plane-under-symbol"/></g>
|
|
128
|
+
<g id="planeFrontTop"><use href="#paper-plane-symbol"/></g>
|
|
129
|
+
</g>
|
|
130
|
+
<g id="__cloudling-export-shims" opacity="0" pointer-events="none" style="display:none">
|
|
131
|
+
<g id="planePaletteV"></g>
|
|
132
|
+
<g id="readout"></g>
|
|
133
|
+
<g id="scrub"></g>
|
|
134
|
+
<g id="scrubV"></g>
|
|
135
|
+
</g>
|
|
136
|
+
|
|
137
|
+
<script type="application/ecmascript"><![CDATA[
|
|
138
|
+
const CLOUD_D = "M9.064 3.344a4.578 4.578 0 012.285-.312c1 .115 1.891.54 2.673 1.275.01.01.024.017.037.021a.09.09 0 00.043 0 4.55 4.55 0 013.046.275l.047.022.116.057a4.581 4.581 0 012.188 2.399c.209.51.313 1.041.315 1.595a4.24 4.24 0 01-.134 1.223.123.123 0 00.03.115c.594.607.988 1.33 1.183 2.17.289 1.425-.007 2.71-.887 3.854l-.136.166a4.548 4.548 0 01-2.201 1.388.123.123 0 00-.081.076c-.191.551-.383 1.023-.74 1.494-.9 1.187-2.222 1.846-3.711 1.838-1.187-.006-2.239-.44-3.157-1.302a.107.107 0 00-.105-.024c-.388.125-.78.143-1.204.138a4.441 4.441 0 01-1.945-.466 4.544 4.544 0 01-1.61-1.335c-.152-.202-.303-.392-.414-.617a5.81 5.81 0 01-.37-.961 4.582 4.582 0 01-.014-2.298.124.124 0 00.006-.056.085.085 0 00-.027-.048 4.467 4.467 0 01-1.034-1.651 3.896 3.896 0 01-.251-1.192 5.189 5.189 0 01.141-1.6c.337-1.112.982-1.985 1.933-2.618.212-.141.413-.251.601-.33.215-.089.43-.164.646-.227a.098.098 0 00.065-.066 4.51 4.51 0 01.829-1.615 4.535 4.535 0 011.837-1.388z";
|
|
139
|
+
|
|
140
|
+
const CENTER = { x: 12, y: 12 };
|
|
141
|
+
/* A 版配色下, 视觉机头会被读成右侧白色尖角 TR, 不是命名里的 N 点。 */
|
|
142
|
+
function visualForwardDeg() {
|
|
143
|
+
return Math.atan2(15.7 - P.pivotY, 34 - P.pivotX) * 180 / Math.PI;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const els = {
|
|
147
|
+
cloudPath: document.getElementById('cloudPath'),
|
|
148
|
+
cloudClipPath: document.getElementById('cloud-clip-path'),
|
|
149
|
+
edgeContact: document.getElementById('edgeContact'),
|
|
150
|
+
edgeRimSoft: document.getElementById('edgeRimSoft'),
|
|
151
|
+
edgeRimTight: document.getElementById('edgeRimTight'),
|
|
152
|
+
eyeGroup: document.getElementById('eyeGroup'),
|
|
153
|
+
eyeL: document.getElementById('eyeL'),
|
|
154
|
+
eyeR: document.getElementById('eyeR'),
|
|
155
|
+
eyeGrad: document.getElementById('eye-grad'),
|
|
156
|
+
planeBack: document.getElementById('planeBack'),
|
|
157
|
+
planeFront: document.getElementById('planeFront'),
|
|
158
|
+
planeBackTop: document.getElementById('planeBackTop'),
|
|
159
|
+
planeBackUnder: document.getElementById('planeBackUnder'),
|
|
160
|
+
planeFrontTop: document.getElementById('planeFrontTop'),
|
|
161
|
+
planeFrontUnder: document.getElementById('planeFrontUnder'),
|
|
162
|
+
trailBack: document.getElementById('trailBack'),
|
|
163
|
+
trailFront: document.getElementById('trailFront'),
|
|
164
|
+
trailBackSoft: document.getElementById('trailBackSoft'),
|
|
165
|
+
trailBackMain: document.getElementById('trailBackMain'),
|
|
166
|
+
trailBackAccent: document.getElementById('trailBackAccent'),
|
|
167
|
+
trailFrontSoft: document.getElementById('trailFrontSoft'),
|
|
168
|
+
trailFrontMain: document.getElementById('trailFrontMain'),
|
|
169
|
+
trailFrontAccent: document.getElementById('trailFrontAccent'),
|
|
170
|
+
readout: document.getElementById('readout'),
|
|
171
|
+
scrub: document.getElementById('scrub'),
|
|
172
|
+
scrubV: document.getElementById('scrubV')
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const P = {
|
|
176
|
+
duration: 5.2,
|
|
177
|
+
rx: 17.8,
|
|
178
|
+
ry: 4.9,
|
|
179
|
+
tilt: -13,
|
|
180
|
+
theta: 0,
|
|
181
|
+
planeScale: 0.20,
|
|
182
|
+
planePalette: 'bluePractical',
|
|
183
|
+
planeOffsetX: 0,
|
|
184
|
+
planeOffsetY: 0,
|
|
185
|
+
planeRotOffset: 123,
|
|
186
|
+
pivotX: 19,
|
|
187
|
+
pivotY: 19,
|
|
188
|
+
backScale: 0.71,
|
|
189
|
+
backOpacity: 0.65,
|
|
190
|
+
rightRush: 0.58,
|
|
191
|
+
rightRushTighten: 0.28,
|
|
192
|
+
trailStrength: 0.90,
|
|
193
|
+
rollMinScale: 0.85,
|
|
194
|
+
rollFade: 0.18,
|
|
195
|
+
manualRotOverride: false,
|
|
196
|
+
manualPlane: false,
|
|
197
|
+
manualX: 26,
|
|
198
|
+
manualY: 24,
|
|
199
|
+
manualRot: -35,
|
|
200
|
+
manualScale: 0.22,
|
|
201
|
+
morphMin: 0.08,
|
|
202
|
+
morphMax: 0.60,
|
|
203
|
+
cloudR: 7.0,
|
|
204
|
+
eyeShift: 1.20,
|
|
205
|
+
eyeFlowPeriod: 5.5,
|
|
206
|
+
eyeFlowAmp: 4,
|
|
207
|
+
blinkInterval: 6.0,
|
|
208
|
+
blinkDur: 0.16,
|
|
209
|
+
showTrail: true,
|
|
210
|
+
pause: false
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const PLANE_PALETTES = {
|
|
214
|
+
happyPop: {
|
|
215
|
+
label: 'Happy',
|
|
216
|
+
gradients: {
|
|
217
|
+
White: ['#fff7d6', '#FCE3B0', '#EFB85C'],
|
|
218
|
+
Lavender: ['#ffeaf3', '#FCC9DD', '#D768A0'],
|
|
219
|
+
Mid: ['#dbfff8', '#A0E5DD', '#35AFA8'],
|
|
220
|
+
Dark: ['#dcd5ff', '#B1A7FF', '#5F52D9']
|
|
221
|
+
},
|
|
222
|
+
under: {
|
|
223
|
+
Mid: '#327E86',
|
|
224
|
+
Dark: '#3F3595',
|
|
225
|
+
Lavender: '#A94B7E',
|
|
226
|
+
White: '#B9863C'
|
|
227
|
+
},
|
|
228
|
+
fold: 'rgba(57,65,255,.38)',
|
|
229
|
+
underFold: 'rgba(255,255,255,.28)',
|
|
230
|
+
highlight: 'rgba(255,255,255,.74)',
|
|
231
|
+
underHighlight: 'rgba(255,255,255,.34)',
|
|
232
|
+
trailBack: '#A0E5DD',
|
|
233
|
+
trailFront: '#FCE3B0',
|
|
234
|
+
shadow: '#3941FF',
|
|
235
|
+
shadowOpacity: '0.30'
|
|
236
|
+
},
|
|
237
|
+
happySoft: {
|
|
238
|
+
label: 'Soft',
|
|
239
|
+
gradients: {
|
|
240
|
+
White: ['#ffffff', '#FCE3B0', '#F4C76E'],
|
|
241
|
+
Lavender: ['#fff3f8', '#FCC9DD', '#E58AB7'],
|
|
242
|
+
Mid: ['#effffb', '#A0E5DD', '#68C9C1'],
|
|
243
|
+
Dark: ['#eeeaff', '#B1A7FF', '#7D71E8']
|
|
244
|
+
},
|
|
245
|
+
under: {
|
|
246
|
+
Mid: '#5AAEA8',
|
|
247
|
+
Dark: '#6558C4',
|
|
248
|
+
Lavender: '#C9789E',
|
|
249
|
+
White: '#D4A54E'
|
|
250
|
+
},
|
|
251
|
+
fold: 'rgba(57,65,255,.30)',
|
|
252
|
+
underFold: 'rgba(255,255,255,.24)',
|
|
253
|
+
highlight: 'rgba(255,255,255,.70)',
|
|
254
|
+
underHighlight: 'rgba(255,255,255,.30)',
|
|
255
|
+
trailBack: '#A0E5DD',
|
|
256
|
+
trailFront: '#B1A7FF',
|
|
257
|
+
shadow: '#7A9DFF',
|
|
258
|
+
shadowOpacity: '0.26'
|
|
259
|
+
},
|
|
260
|
+
ticketWarm: {
|
|
261
|
+
label: 'Warm',
|
|
262
|
+
gradients: {
|
|
263
|
+
White: ['#ffd28c', '#dc5a1c', '#a64214'],
|
|
264
|
+
Lavender: ['#ff9b45', '#dc5a1c', '#7b2f10'],
|
|
265
|
+
Mid: ['#d8722c', '#9d4315', '#5c260d'],
|
|
266
|
+
Dark: ['#743217', '#4a1f0d', '#271006']
|
|
267
|
+
},
|
|
268
|
+
under: {
|
|
269
|
+
Mid: '#5d260d',
|
|
270
|
+
Dark: '#1f0c04',
|
|
271
|
+
Lavender: '#713010',
|
|
272
|
+
White: '#8b3a13'
|
|
273
|
+
},
|
|
274
|
+
fold: 'rgba(42,18,8,.44)',
|
|
275
|
+
underFold: 'rgba(255,211,154,.20)',
|
|
276
|
+
highlight: 'rgba(255,225,190,.58)',
|
|
277
|
+
underHighlight: 'rgba(255,205,150,.24)',
|
|
278
|
+
trailBack: '#9d4315',
|
|
279
|
+
trailFront: '#dc5a1c',
|
|
280
|
+
shadow: '#dc5a1c',
|
|
281
|
+
shadowOpacity: '0.24'
|
|
282
|
+
},
|
|
283
|
+
bluePractical: {
|
|
284
|
+
label: 'Blue',
|
|
285
|
+
gradients: {
|
|
286
|
+
White: ['#ffffff', '#b8c8ff', '#6f86ff'],
|
|
287
|
+
Lavender: ['#e6e2ff', '#aeb8ff', '#6874f2'],
|
|
288
|
+
Mid: ['#9bb7ff', '#536dff', '#3941FF'],
|
|
289
|
+
Dark: ['#646bff', '#3037d4', '#171b82']
|
|
290
|
+
},
|
|
291
|
+
under: {
|
|
292
|
+
Mid: '#3037d4',
|
|
293
|
+
Dark: '#12165f',
|
|
294
|
+
Lavender: '#5664ff',
|
|
295
|
+
White: '#8ea1ff'
|
|
296
|
+
},
|
|
297
|
+
fold: 'rgba(17,27,140,.46)',
|
|
298
|
+
underFold: 'rgba(255,255,255,.24)',
|
|
299
|
+
highlight: 'rgba(255,255,255,.72)',
|
|
300
|
+
underHighlight: 'rgba(255,255,255,.36)',
|
|
301
|
+
trailBack: '#7A9DFF',
|
|
302
|
+
trailFront: '#B1A7FF',
|
|
303
|
+
shadow: '#3941FF',
|
|
304
|
+
shadowOpacity: '0.36'
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
const lerp = (a, b, t) => a + (b - a) * t;
|
|
309
|
+
const clamp = (v, a, b) => Math.max(a, Math.min(b, v));
|
|
310
|
+
const wrap01 = v => ((v % 1) + 1) % 1;
|
|
311
|
+
const smoothstep = t => t * t * (3 - 2 * t);
|
|
312
|
+
const smoothstepRange = (a, b, v) => smoothstep(clamp((v - a) / (b - a), 0, 1));
|
|
313
|
+
const TAU = Math.PI * 2;
|
|
314
|
+
|
|
315
|
+
function orbitProgressFor(timeProgress) {
|
|
316
|
+
const p = wrap01(timeProgress);
|
|
317
|
+
const a = TAU * p;
|
|
318
|
+
const warped = p
|
|
319
|
+
+ P.rightRush * Math.sin(a) / TAU
|
|
320
|
+
+ P.rightRushTighten * Math.sin(2 * a) / (2 * TAU);
|
|
321
|
+
return wrap01(warped);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function orbitSpeedFor(timeProgress) {
|
|
325
|
+
const p = wrap01(timeProgress);
|
|
326
|
+
const a = TAU * p;
|
|
327
|
+
return 1 + P.rightRush * Math.cos(a) + P.rightRushTighten * Math.cos(2 * a);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const EYE_BASE = {
|
|
331
|
+
l: { y: 9.5, h: 5, rx: 1.3 },
|
|
332
|
+
r: { y: 9.5, h: 5, rx: 1.3 }
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
let nextBlinkT = 2.4;
|
|
336
|
+
let blinkActive = false;
|
|
337
|
+
let blinkStartT = 0;
|
|
338
|
+
|
|
339
|
+
function getBlinkScale(t) {
|
|
340
|
+
if (!blinkActive && t > nextBlinkT) {
|
|
341
|
+
blinkActive = true;
|
|
342
|
+
blinkStartT = t;
|
|
343
|
+
}
|
|
344
|
+
if (blinkActive) {
|
|
345
|
+
const dt = t - blinkStartT;
|
|
346
|
+
const half = P.blinkDur / 2;
|
|
347
|
+
if (dt < half) return 1 - 0.94 * (dt / half);
|
|
348
|
+
if (dt < P.blinkDur) return 0.06 + 0.94 * ((dt - half) / half);
|
|
349
|
+
blinkActive = false;
|
|
350
|
+
nextBlinkT = t + P.blinkInterval * (0.82 + Math.random() * 0.36);
|
|
351
|
+
}
|
|
352
|
+
return 1;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function applyBlink(rect, base, scale) {
|
|
356
|
+
const h = Math.max(base.h * scale, 0.15);
|
|
357
|
+
const y = base.y + (base.h - h) / 2;
|
|
358
|
+
const rx = Math.min(base.rx, h / 2);
|
|
359
|
+
rect.setAttribute('height', h.toFixed(3));
|
|
360
|
+
rect.setAttribute('y', y.toFixed(3));
|
|
361
|
+
rect.setAttribute('rx', rx.toFixed(3));
|
|
362
|
+
rect.setAttribute('ry', rx.toFixed(3));
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function setStop(id, color) {
|
|
366
|
+
document.getElementById(id).setAttribute('stop-color', color);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function applyPlanePalette(key) {
|
|
370
|
+
const palette = PLANE_PALETTES[key] || PLANE_PALETTES.happyPop;
|
|
371
|
+
P.planePalette = key;
|
|
372
|
+
for (const [name, colors] of Object.entries(palette.gradients)) {
|
|
373
|
+
colors.forEach((color, i) => setStop(`plane${name}${i}`, color));
|
|
374
|
+
}
|
|
375
|
+
for (const [name, color] of Object.entries(palette.under)) {
|
|
376
|
+
document.getElementById(`planeUnder${name}`).setAttribute('fill', color);
|
|
377
|
+
}
|
|
378
|
+
document.getElementById('planeFoldLines').setAttribute('stroke', palette.fold);
|
|
379
|
+
document.getElementById('planeUnderFoldLines').setAttribute('stroke', palette.underFold);
|
|
380
|
+
document.getElementById('planeNoseHighlight').setAttribute('stroke', palette.highlight);
|
|
381
|
+
document.getElementById('planeUnderNoseHighlight').setAttribute('stroke', palette.underHighlight);
|
|
382
|
+
[els.trailBackSoft, els.trailBackMain, els.trailBackAccent].forEach(el => el.setAttribute('stroke', palette.trailBack));
|
|
383
|
+
[els.trailFrontSoft, els.trailFrontMain, els.trailFrontAccent].forEach(el => el.setAttribute('stroke', palette.trailFront));
|
|
384
|
+
document.getElementById('planeShadow').setAttribute('flood-color', palette.shadow);
|
|
385
|
+
document.getElementById('planeShadow').setAttribute('flood-opacity', palette.shadowOpacity);
|
|
386
|
+
document.getElementById('planePaletteV').textContent = palette.label;
|
|
387
|
+
renderAt(currentProgress);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function samplePath(d, N) {
|
|
391
|
+
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
392
|
+
path.setAttribute('d', d);
|
|
393
|
+
const len = path.getTotalLength();
|
|
394
|
+
const pts = [];
|
|
395
|
+
for (let i = 0; i < N; i++) {
|
|
396
|
+
const p = path.getPointAtLength(i / N * len);
|
|
397
|
+
pts.push({ x: p.x, y: p.y });
|
|
398
|
+
}
|
|
399
|
+
return pts;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
let basePoints = samplePath(CLOUD_D, 64);
|
|
403
|
+
|
|
404
|
+
function morphPoints(pts, R, t) {
|
|
405
|
+
return pts.map(p => {
|
|
406
|
+
const dx = p.x - CENTER.x;
|
|
407
|
+
const dy = p.y - CENTER.y;
|
|
408
|
+
const a = Math.atan2(dy, dx);
|
|
409
|
+
return {
|
|
410
|
+
x: lerp(p.x, CENTER.x + R * Math.cos(a), t),
|
|
411
|
+
y: lerp(p.y, CENTER.y + R * Math.sin(a), t)
|
|
412
|
+
};
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function pointsToSmoothPath(pts) {
|
|
417
|
+
const n = pts.length;
|
|
418
|
+
let d = `M ${pts[0].x.toFixed(3)} ${pts[0].y.toFixed(3)}`;
|
|
419
|
+
for (let i = 0; i < n; i++) {
|
|
420
|
+
const p0 = pts[(i - 1 + n) % n];
|
|
421
|
+
const p1 = pts[i];
|
|
422
|
+
const p2 = pts[(i + 1) % n];
|
|
423
|
+
const p3 = pts[(i + 2) % n];
|
|
424
|
+
const c1x = p1.x + (p2.x - p0.x) / 6;
|
|
425
|
+
const c1y = p1.y + (p2.y - p0.y) / 6;
|
|
426
|
+
const c2x = p2.x - (p3.x - p1.x) / 6;
|
|
427
|
+
const c2y = p2.y - (p3.y - p1.y) / 6;
|
|
428
|
+
d += ` C ${c1x.toFixed(3)} ${c1y.toFixed(3)} ${c2x.toFixed(3)} ${c2y.toFixed(3)} ${p2.x.toFixed(3)} ${p2.y.toFixed(3)}`;
|
|
429
|
+
}
|
|
430
|
+
return d + ' Z';
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function orbitPoint(thetaDeg) {
|
|
434
|
+
const t = thetaDeg * Math.PI / 180;
|
|
435
|
+
const r = P.tilt * Math.PI / 180;
|
|
436
|
+
const ct = Math.cos(t), st = Math.sin(t);
|
|
437
|
+
const cr = Math.cos(r), sr = Math.sin(r);
|
|
438
|
+
return {
|
|
439
|
+
x: CENTER.x + P.rx * ct * cr - P.ry * st * sr,
|
|
440
|
+
y: CENTER.y + P.rx * ct * sr + P.ry * st * cr
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
function orbitDerivative(thetaDeg) {
|
|
445
|
+
const t = thetaDeg * Math.PI / 180;
|
|
446
|
+
const r = P.tilt * Math.PI / 180;
|
|
447
|
+
const cr = Math.cos(r), sr = Math.sin(r);
|
|
448
|
+
const dx = -P.rx * Math.sin(t) * cr - P.ry * Math.cos(t) * sr;
|
|
449
|
+
const dy = -P.rx * Math.sin(t) * sr + P.ry * Math.cos(t) * cr;
|
|
450
|
+
return { x: dx, y: dy };
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function getPlaneState(progress) {
|
|
454
|
+
const orbitProgress = orbitProgressFor(progress);
|
|
455
|
+
const theta = P.theta + orbitProgress * 360;
|
|
456
|
+
const orbitDepth = Math.sin(theta * Math.PI / 180);
|
|
457
|
+
return {
|
|
458
|
+
phase: 'orbit',
|
|
459
|
+
theta,
|
|
460
|
+
orbitDepth,
|
|
461
|
+
orbitProximity: smoothstepRange(0.22, 0.90, Math.abs(orbitDepth)),
|
|
462
|
+
p: orbitPoint(theta),
|
|
463
|
+
d: orbitDerivative(theta),
|
|
464
|
+
orbitT: orbitProgress,
|
|
465
|
+
timeT: wrap01(progress),
|
|
466
|
+
orbitSpeed: orbitSpeedFor(progress),
|
|
467
|
+
frontOverride: false,
|
|
468
|
+
opacity: 1
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
function cloudMorphFor(orbitProximity) {
|
|
473
|
+
return lerp(P.morphMin, P.morphMax, orbitProximity);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
function trailPathD(timeProgress, fromLag, toLag, samples) {
|
|
477
|
+
let d = '';
|
|
478
|
+
for (let i = 0; i <= samples; i++) {
|
|
479
|
+
const lag = lerp(fromLag, toLag, i / samples);
|
|
480
|
+
const sample = getAutoPlaneVisual(getPlaneState(timeProgress - lag));
|
|
481
|
+
d += i === 0
|
|
482
|
+
? `M ${sample.p.x.toFixed(3)} ${sample.p.y.toFixed(3)}`
|
|
483
|
+
: ` L ${sample.p.x.toFixed(3)} ${sample.p.y.toFixed(3)}`;
|
|
484
|
+
}
|
|
485
|
+
return d;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
function setTrailLayer(el, d, opacity, width, dash = 'none', dashOffset = 0) {
|
|
489
|
+
el.setAttribute('d', d);
|
|
490
|
+
el.setAttribute('opacity', opacity.toFixed(3));
|
|
491
|
+
el.setAttribute('stroke-width', width.toFixed(3));
|
|
492
|
+
el.setAttribute('stroke-dasharray', dash);
|
|
493
|
+
el.setAttribute('stroke-dashoffset', dashOffset.toFixed(3));
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
function renderTrailLines(timeProgress, orbitSpeed, plane) {
|
|
497
|
+
const enabled = P.showTrail && !P.manualPlane;
|
|
498
|
+
const speedBurst = clamp((orbitSpeed - 1) / 0.86, 0, 1);
|
|
499
|
+
const base = enabled ? P.trailStrength * lerp(0.82, 1.24, speedBurst) : 0;
|
|
500
|
+
const frontBase = base * plane.frontness;
|
|
501
|
+
const backBase = base * (1 - plane.frontness) * P.backOpacity;
|
|
502
|
+
const drift = timeProgress * P.duration;
|
|
503
|
+
const mainD = trailPathD(timeProgress, 0.145, 0.010, 18);
|
|
504
|
+
const shortD = trailPathD(timeProgress, 0.090, 0.006, 12);
|
|
505
|
+
const longD = trailPathD(timeProgress, 0.190, 0.016, 22);
|
|
506
|
+
const mainOffset = -drift * 0.36;
|
|
507
|
+
const accentOffset = -drift * 0.58;
|
|
508
|
+
|
|
509
|
+
setTrailLayer(els.trailBackSoft, longD, backBase * 0.12, 0.62, 'none', 0);
|
|
510
|
+
setTrailLayer(els.trailBackMain, mainD, backBase * 0.42, 0.30, '0.72 0.62', mainOffset);
|
|
511
|
+
setTrailLayer(els.trailBackAccent, shortD, backBase * 0.22, 0.20, '1.16 0.55', accentOffset);
|
|
512
|
+
setTrailLayer(els.trailFrontSoft, longD, frontBase * 0.12, 0.62, 'none', 0);
|
|
513
|
+
setTrailLayer(els.trailFrontMain, mainD, frontBase * 0.42, 0.30, '0.72 0.62', mainOffset);
|
|
514
|
+
setTrailLayer(els.trailFrontAccent, shortD, frontBase * 0.22, 0.20, '1.16 0.55', accentOffset);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
function getAutoPlaneVisual(s) {
|
|
518
|
+
const p = {
|
|
519
|
+
x: s.p.x + P.planeOffsetX,
|
|
520
|
+
y: s.p.y + P.planeOffsetY
|
|
521
|
+
};
|
|
522
|
+
const tangentDeg = Math.atan2(s.d.y, s.d.x) * 180 / Math.PI;
|
|
523
|
+
const orbitFrontness = clamp((p.y - CENTER.y + 1.3) / 4.0, 0, 1);
|
|
524
|
+
const frontness = s.frontOverride ? 1 : orbitFrontness;
|
|
525
|
+
const depthScale = lerp(P.backScale, 1, frontness);
|
|
526
|
+
const totalScale = P.planeScale * depthScale;
|
|
527
|
+
const bank = (frontness - 0.5) * 7;
|
|
528
|
+
const rot = tangentDeg - visualForwardDeg() + bank + P.planeRotOffset;
|
|
529
|
+
const faceMix = smoothstepRange(-P.rollFade, P.rollFade, s.orbitDepth);
|
|
530
|
+
const rollStrength = smoothstepRange(0.10, 0.88, Math.abs(s.orbitDepth));
|
|
531
|
+
return {
|
|
532
|
+
phase: s.phase,
|
|
533
|
+
p,
|
|
534
|
+
tangentDeg,
|
|
535
|
+
frontness,
|
|
536
|
+
orbitT: s.orbitT,
|
|
537
|
+
orbitDepth: s.orbitDepth,
|
|
538
|
+
orbitProximity: s.orbitProximity,
|
|
539
|
+
topFaceOpacity: faceMix,
|
|
540
|
+
underFaceOpacity: 1 - faceMix,
|
|
541
|
+
rollForeshorten: lerp(P.rollMinScale, 1, rollStrength),
|
|
542
|
+
totalScale,
|
|
543
|
+
rot,
|
|
544
|
+
frontOpacity: s.opacity * frontness,
|
|
545
|
+
backOpacity: s.opacity * (1 - frontness) * P.backOpacity
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
function getPlaneVisual(s) {
|
|
550
|
+
if (!P.manualPlane) {
|
|
551
|
+
const auto = getAutoPlaneVisual(s);
|
|
552
|
+
if (!P.manualRotOverride) return auto;
|
|
553
|
+
return {
|
|
554
|
+
...auto,
|
|
555
|
+
phase: 'orbit+manual-rot',
|
|
556
|
+
tangentDeg: P.manualRot,
|
|
557
|
+
rot: P.manualRot
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
return {
|
|
561
|
+
phase: 'manual',
|
|
562
|
+
p: { x: P.manualX, y: P.manualY },
|
|
563
|
+
tangentDeg: P.manualRot,
|
|
564
|
+
frontness: 1,
|
|
565
|
+
orbitDepth: 1,
|
|
566
|
+
orbitProximity: 1,
|
|
567
|
+
topFaceOpacity: 1,
|
|
568
|
+
underFaceOpacity: 0,
|
|
569
|
+
rollForeshorten: 1,
|
|
570
|
+
totalScale: P.manualScale,
|
|
571
|
+
rot: P.manualRot,
|
|
572
|
+
frontOpacity: 1,
|
|
573
|
+
backOpacity: 0
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
function renderAt(progress) {
|
|
578
|
+
const s = getPlaneState(progress);
|
|
579
|
+
const plane = getPlaneVisual(s);
|
|
580
|
+
const morph = cloudMorphFor(s.orbitProximity);
|
|
581
|
+
const cloudD = pointsToSmoothPath(morphPoints(basePoints, P.cloudR, morph));
|
|
582
|
+
els.cloudPath.setAttribute('d', cloudD);
|
|
583
|
+
els.cloudClipPath.setAttribute('d', cloudD);
|
|
584
|
+
els.edgeContact.setAttribute('d', cloudD);
|
|
585
|
+
els.edgeRimSoft.setAttribute('d', cloudD);
|
|
586
|
+
els.edgeRimTight.setAttribute('d', cloudD);
|
|
587
|
+
|
|
588
|
+
const lookDx = plane.p.x - CENTER.x;
|
|
589
|
+
const lookDy = plane.p.y - CENTER.y;
|
|
590
|
+
const lookLen = Math.max(Math.hypot(lookDx, lookDy), 0.001);
|
|
591
|
+
const eyeDrive = P.eyeShift;
|
|
592
|
+
const eyeX = lookDx / lookLen * eyeDrive;
|
|
593
|
+
const eyeY = lookDy / lookLen * eyeDrive * 0.55;
|
|
594
|
+
const eyeScale = lerp(1, 0.82, morph / Math.max(P.morphMax, 0.001));
|
|
595
|
+
els.eyeGroup.setAttribute('transform', `translate(${eyeX.toFixed(3)} ${eyeY.toFixed(3)}) translate(12 12) scale(${eyeScale.toFixed(3)}) translate(-12 -12)`);
|
|
596
|
+
els.eyeL.setAttribute('opacity', lerp(1, 0.88, morph).toFixed(3));
|
|
597
|
+
els.eyeR.setAttribute('opacity', lerp(1, 0.88, morph).toFixed(3));
|
|
598
|
+
const tNow = performance.now() / 1000;
|
|
599
|
+
const blinkScale = getBlinkScale(tNow);
|
|
600
|
+
applyBlink(els.eyeL, EYE_BASE.l, blinkScale);
|
|
601
|
+
applyBlink(els.eyeR, EYE_BASE.r, blinkScale);
|
|
602
|
+
const flowOffset = Math.sin(2 * Math.PI * tNow / P.eyeFlowPeriod) * P.eyeFlowAmp;
|
|
603
|
+
els.eyeGrad.setAttribute('y1', (3 + flowOffset).toFixed(2));
|
|
604
|
+
els.eyeGrad.setAttribute('y2', (21 + flowOffset).toFixed(2));
|
|
605
|
+
|
|
606
|
+
const transform = `translate(${plane.p.x.toFixed(3)} ${plane.p.y.toFixed(3)}) rotate(${plane.rot.toFixed(3)}) scale(${plane.totalScale.toFixed(4)} ${(plane.totalScale * plane.rollForeshorten).toFixed(4)}) translate(${(-P.pivotX).toFixed(3)} ${(-P.pivotY).toFixed(3)})`;
|
|
607
|
+
els.planeFront.setAttribute('transform', transform);
|
|
608
|
+
els.planeBack.setAttribute('transform', transform);
|
|
609
|
+
els.planeFront.setAttribute('opacity', plane.frontOpacity.toFixed(3));
|
|
610
|
+
els.planeBack.setAttribute('opacity', plane.backOpacity.toFixed(3));
|
|
611
|
+
els.planeFrontTop.setAttribute('opacity', plane.topFaceOpacity.toFixed(3));
|
|
612
|
+
els.planeBackTop.setAttribute('opacity', plane.topFaceOpacity.toFixed(3));
|
|
613
|
+
els.planeFrontUnder.setAttribute('opacity', plane.underFaceOpacity.toFixed(3));
|
|
614
|
+
els.planeBackUnder.setAttribute('opacity', plane.underFaceOpacity.toFixed(3));
|
|
615
|
+
|
|
616
|
+
renderTrailLines(progress, s.orbitSpeed, plane);
|
|
617
|
+
|
|
618
|
+
els.scrub.value = progress.toFixed(3);
|
|
619
|
+
els.scrubV.textContent = `${Math.round(progress * 100)}%`;
|
|
620
|
+
els.readout.textContent =
|
|
621
|
+
`phase=${plane.phase} progress=${progress.toFixed(3)}
|
|
622
|
+
plane=(${plane.p.x.toFixed(2)}, ${plane.p.y.toFixed(2)}) rot=${plane.rot.toFixed(1)}deg tangent=${plane.tangentDeg.toFixed(1)}deg frontness=${plane.frontness.toFixed(2)}
|
|
623
|
+
cloud morph=${Math.round(morph * 100)}% sidePass=${s.orbitProximity.toFixed(2)} depth=${s.orbitDepth.toFixed(2)} range=${Math.round(P.morphMin * 100)}-${Math.round(P.morphMax * 100)}%
|
|
624
|
+
roll top=${plane.topFaceOpacity.toFixed(2)} under=${plane.underFaceOpacity.toFixed(2)} squash=${plane.rollForeshorten.toFixed(2)}
|
|
625
|
+
eyes dx=${eyeX.toFixed(2)} dy=${eyeY.toFixed(2)} blink=${blinkScale.toFixed(2)} flow=${flowOffset.toFixed(1)}
|
|
626
|
+
orbit t=${s.orbitT.toFixed(3)} speed=${s.orbitSpeed.toFixed(2)}x rx=${P.rx.toFixed(1)} ry=${P.ry.toFixed(1)} tilt=${P.tilt.toFixed(0)}deg start=${P.theta.toFixed(0)}deg
|
|
627
|
+
plane global offset=(${P.planeOffsetX.toFixed(1)}, ${P.planeOffsetY.toFixed(1)}) rotOffset=${P.planeRotOffset.toFixed(0)}deg pivot=(${P.pivotX.toFixed(1)}, ${P.pivotY.toFixed(1)})
|
|
628
|
+
palette=${P.planePalette} (${PLANE_PALETTES[P.planePalette]?.label || 'custom'})
|
|
629
|
+
manual=${P.manualPlane ? `position on x=${P.manualX.toFixed(1)} y=${P.manualY.toFixed(1)} rot=${P.manualRot.toFixed(0)} scale=${P.manualScale.toFixed(2)}` : `position off rotOverride=${P.manualRotOverride ? `on rot=${P.manualRot.toFixed(0)}` : 'off'}`}
|
|
630
|
+
trail style=short dash
|
|
631
|
+
note: right side has a short rush; trail variants are line-based for review.`;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
let startTime = performance.now();
|
|
635
|
+
let currentProgress = 0;
|
|
636
|
+
|
|
637
|
+
function loop(now) {
|
|
638
|
+
if (!P.pause) {
|
|
639
|
+
currentProgress = ((now - startTime) / 1000 / P.duration) % 1;
|
|
640
|
+
}
|
|
641
|
+
renderAt(currentProgress);
|
|
642
|
+
requestAnimationFrame(loop);
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
applyPlanePalette(P.planePalette);
|
|
646
|
+
requestAnimationFrame(loop);
|
|
647
|
+
]]></script>
|
|
648
|
+
</svg>
|