openvibers/openvibe.shared items.css

items.css

main 17.6 KB · 386 lines · css

1/*
2 * openvibe-shared/items.css — what people wear, drawn the same on every OpenVibe site (plan T21 "equip everywhere").
3 *
4 * The renderers OpenVibe.Inventory's kinds name (each kind's `surfaces[].renderer`):
5 * live.name_effect.css@1 the item's art.token is a class on the name: <span class="ov-fx name-fx-rainbow">Ana</span>
6 * live.hat.glyph@1 the hat's emoji before the name: <span class="ov-hat ov-hat-pulse">👑</span>
7 * live.particle.css@1 `ov-px` + the token on the name; items.js spawns `.ov-px-p` characters in a burst
8 * network.badge.image@1 <img class="ov-badge"> before the name (a Workshop badge, from OpenVibe.Media)
9 * items.js adds the classes from the person's equipped set; a page that already knows the token (a server-rendered
10 * profile) writes the class itself. These are Live's own name effects (OpenVibe.Live public/css/cosmetics.css),
11 * unchanged, so a name looks the same in Live's chat and everywhere else. The network's Calm setting
12 * (data-ov-motion=reduced on <html>, theme-loader.js) plays them slower; with motion off the colour stays and nothing moves.
13 */
14.ov-fx { display: inline-block; }
15
16/* Rainbow — cycling hue */
17.name-fx-rainbow {
18 background: linear-gradient(90deg, #ff0000, #ff8800, #ffff00, #00ff00, #0088ff, #8800ff, #ff0088);
19 background-size: 400% 100%;
20 -webkit-background-clip: text;
21 -webkit-text-fill-color: transparent;
22 background-clip: text;
23 animation: nameFxRainbow 3s linear infinite;
24}
25@keyframes nameFxRainbow {
26 0% { background-position: 0% 50%; }
27 100% { background-position: 400% 50%; }
28}
29
30/* Fire — warm pulse with glow. The darkest frame is #ff7a1f, not #ff6600: on a red-tinted chat row (#581e1c) the old one
31 read at 4.42:1, under WCAG AA's 4.5 (axe on openvibe.chat, 11-03); #ff7a1f reads at 4.98 there and 7.2 on the page. */
32.name-fx-fire {
33 color: #ff7a1f !important;
34 text-shadow: 0 0 6px #ff4400, 0 0 12px #ff220088, 0 0 20px #cc110044;
35 animation: nameFxFire 1.5s ease-in-out infinite alternate;
36}
37@keyframes nameFxFire {
38 0% { text-shadow: 0 0 6px #ff4400, 0 0 12px #ff220088; color: #ff7a1f; }
39 100% { text-shadow: 0 0 10px #ff8800, 0 0 20px #ff440088, 0 0 30px #cc220044; color: #ffaa00; }
40}
41
42/* Ice — cool blue shimmer */
43.name-fx-ice {
44 color: #88ddff !important;
45 text-shadow: 0 0 6px #44bbff88, 0 0 12px #2288cc44;
46 animation: nameFxIce 2s ease-in-out infinite alternate;
47}
48@keyframes nameFxIce {
49 0% { text-shadow: 0 0 4px #44bbff88; color: #88ddff; }
50 100% { text-shadow: 0 0 10px #66eeff, 0 0 20px #44bbff88; color: #bbffff; }
51}
52
53/* Golden — shimmering gold */
54.name-fx-golden {
55 background: linear-gradient(90deg, #ffd700, #ffec80, #ffd700, #ffb800);
56 background-size: 300% 100%;
57 -webkit-background-clip: text;
58 -webkit-text-fill-color: transparent;
59 background-clip: text;
60 animation: nameFxGolden 2s ease-in-out infinite;
61 filter: drop-shadow(0 0 4px #ffd70066);
62}
63@keyframes nameFxGolden {
64 0%, 100% { background-position: 0% 50%; }
65 50% { background-position: 100% 50%; }
66}
67
68/* Neon — glowing pulse */
69.name-fx-neon {
70 color: #00ff88 !important;
71 text-shadow: 0 0 8px #00ff88, 0 0 16px #00ff8888, 0 0 24px #00cc6644;
72 animation: nameFxNeon 1.2s ease-in-out infinite alternate;
73}
74@keyframes nameFxNeon {
75 0% { text-shadow: 0 0 4px #00ff88, 0 0 8px #00ff8866; }
76 100% { text-shadow: 0 0 12px #00ff88, 0 0 24px #00ff88aa, 0 0 36px #00cc6666; }
77}
78
79/* Galaxy — cosmic swirl */
80.name-fx-galaxy {
81 background: linear-gradient(90deg, #8b5cf6, #ec4899, #3b82f6, #8b5cf6);
82 background-size: 400% 100%;
83 -webkit-background-clip: text;
84 -webkit-text-fill-color: transparent;
85 background-clip: text;
86 animation: nameFxGalaxy 4s linear infinite;
87 filter: drop-shadow(0 0 6px #8b5cf644);
88}
89@keyframes nameFxGalaxy {
90 0% { background-position: 0% 50%; }
91 100% { background-position: 400% 50%; }
92}
93
94/* Void — dark matter warp */
95.name-fx-void {
96 color: #9900ff !important;
97 text-shadow: 0 0 8px #6600cc, 0 0 16px #33006688, 0 0 24px #11003344;
98 animation: nameFxVoid 2s ease-in-out infinite;
99}
100@keyframes nameFxVoid {
101 0%, 100% { text-shadow: 0 0 8px #6600cc, 0 0 16px #33006688; transform: scale(1); }
102 50% { text-shadow: 0 0 12px #9900ff, 0 0 24px #6600ccaa, 0 0 36px #33006666; transform: scale(1.03); }
103}
104
105/* Toxic — green pulse */
106.name-fx-toxic {
107 background: linear-gradient(90deg, #00ff44, #88ff00, #ccff00, #00ff88);
108 background-size: 200% 100%;
109 -webkit-background-clip: text;
110 -webkit-text-fill-color: transparent;
111 background-clip: text;
112 animation: nameFxToxic 1.8s ease-in-out infinite alternate;
113}
114@keyframes nameFxToxic {
115 0% { background-position: 0% 50%; filter: brightness(1); }
116 100% { background-position: 200% 50%; filter: brightness(1.3); }
117}
118
119/* Blood — crimson drip */
120.name-fx-blood {
121 background: linear-gradient(180deg, #ff0000, #880000, #ff2222);
122 background-size: 100% 200%;
123 -webkit-background-clip: text;
124 -webkit-text-fill-color: transparent;
125 background-clip: text;
126 animation: nameFxBlood 2s ease-in-out infinite;
127}
128@keyframes nameFxBlood {
129 0%, 100% { background-position: 50% 0%; }
130 50% { background-position: 50% 200%; }
131}
132
133/* Shadow — dark mist */
134.name-fx-shadow {
135 color: #aa88cc !important;
136 animation: nameFxShadow 2s ease-in-out infinite;
137}
138@keyframes nameFxShadow {
139 0%, 100% { text-shadow: 0 0 6px rgba(0,0,0,0.8), 0 0 12px rgba(80,0,120,0.6), 2px 2px 4px rgba(0,0,0,0.9); }
140 50% { text-shadow: 0 0 12px rgba(0,0,0,0.9), 0 0 24px rgba(80,0,120,0.8), 4px 4px 8px rgba(0,0,0,1); }
141}
142
143/* Glitch — jittery digital */
144.name-fx-glitch {
145 color: #00ff88 !important;
146 animation: nameFxGlitch 0.15s infinite;
147 text-shadow: 2px 0 #ff0044, -2px 0 #00ccff;
148}
149@keyframes nameFxGlitch {
150 0% { transform: translate(0); }
151 20% { transform: translate(-1px, 1px); }
152 40% { transform: translate(1px, -1px); }
153 60% { transform: translate(-1px, 0); }
154 80% { transform: translate(1px, 1px); }
155 100% { transform: translate(0); }
156}
157
158/* Hologram — flickering translucent */
159.name-fx-hologram {
160 background: linear-gradient(90deg, #00ffcc, #00ccff, #8888ff, #00ffaa);
161 background-size: 300% 100%;
162 -webkit-background-clip: text;
163 -webkit-text-fill-color: transparent;
164 background-clip: text;
165 animation: nameFxHoloFlicker 0.12s infinite, nameFxHoloShift 3s linear infinite;
166}
167@keyframes nameFxHoloFlicker { 0%,45%,55%,100% { opacity: 1; } 50% { opacity: 0.6; } }
168@keyframes nameFxHoloShift { 0% { background-position: 0% 50%; } 100% { background-position: 300% 50%; } }
169
170/* Divine — holy radiance */
171.name-fx-divine {
172 background: linear-gradient(90deg, #ffffff, #ffe066, #ffffff, #ffcc00, #ffffff);
173 background-size: 300% 100%;
174 -webkit-background-clip: text;
175 -webkit-text-fill-color: transparent;
176 background-clip: text;
177 animation: nameFxDivine 2s ease-in-out infinite;
178 filter: drop-shadow(0 0 8px #ffe06688);
179}
180@keyframes nameFxDivine {
181 0%, 100% { background-position: 0% 50%; }
182 50% { background-position: 300% 50%; }
183}
184
185/* Josh Vegas: one of a kind (2026-10-22). The name in casino gold under marquee lights, between two slot reels that
186 spin through cherries, bells, diamonds, slot machines and lemons and land on 7, and the name pops like a jackpot the
187 moment they do. Only its one holder wears it (fx_vegas is never in the catalog). The reels are pseudo-elements, so they
188 carry their own fill, pause and reduced-motion rules. */
189.name-fx-vegas {
190 background: linear-gradient(90deg, #fff1b8 0%, #ffcf3f 22%, #ff9d00 40%, #ff3d7f 52%, #ffcf3f 66%, #fff1b8 82%, #ffcf3f 100%);
191 background-size: 280% 100%;
192 -webkit-background-clip: text;
193 background-clip: text;
194 -webkit-text-fill-color: transparent;
195 display: inline-block;
196 font-weight: 800;
197 letter-spacing: .02em;
198 white-space: nowrap;
199 transform-origin: 50% 60%;
200 animation: nameFxVegasShine 2.6s linear infinite, nameFxVegasLights 1.4s steps(1, end) infinite, nameFxVegasJackpot 3.2s ease-out infinite;
201}
202.name-fx-vegas::before,
203.name-fx-vegas::after {
204 content: '7';
205 display: inline-block;
206 box-sizing: border-box;
207 width: 2em;
208 margin-right: .4em;
209 border: 1px solid #ffcf3f;
210 border-radius: 3px;
211 background: linear-gradient(180deg, #3d0512 0%, #8f0f2c 48%, #3d0512 100%);
212 box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .45), 0 0 5px rgba(255, 207, 63, .6);
213 color: #ffe27a;
214 -webkit-text-fill-color: #ffe27a;
215 font-size: .72em;
216 font-weight: 900;
217 letter-spacing: 0;
218 line-height: 1.35;
219 text-align: center;
220 overflow: hidden;
221 vertical-align: .1em;
222 animation: nameFxVegasReel 3.2s steps(1, end) infinite;
223}
224.name-fx-vegas::after { margin: 0 0 0 .4em; animation-delay: .35s; }
225@keyframes nameFxVegasShine {
226 0% { background-position: 0% 50%; }
227 100% { background-position: 280% 50%; }
228}
229/* Marquee bulbs: the glow steps between gold and pink, like the lights around a casino sign. */
230@keyframes nameFxVegasLights {
231 0% { filter: drop-shadow(0 0 3px rgba(255, 207, 63, .9)) drop-shadow(0 0 9px rgba(255, 157, 0, .55)); }
232 50% { filter: drop-shadow(0 0 3px rgba(255, 61, 127, .9)) drop-shadow(0 0 9px rgba(255, 61, 127, .5)); }
233}
234/* Jackpot: as the reels land on 7, the whole name pops and settles (the reels' cycle, 3.2 s). */
235@keyframes nameFxVegasJackpot {
236 0%, 34% { transform: scale(1); }
237 38% { transform: scale(1.14) rotate(-2deg); }
238 43% { transform: scale(.97) rotate(1deg); }
239 48%, 100% { transform: scale(1); }
240}
241/* Each reel spins through the symbols, then lands on 7 and holds it (a browser that cannot animate `content` shows 7). */
242@keyframes nameFxVegasReel {
243 0% { content: '🍒'; }
244 7% { content: '🔔'; }
245 14% { content: '💎'; }
246 21% { content: '🎰'; }
247 28% { content: '🍋'; }
248 35%, 100% { content: '7'; }
249}
250html[data-ov-motion=off] .name-fx-vegas{filter: drop-shadow(0 0 3px rgba(255, 207, 63, .9))}
251
252/* 2fat Bass Drop (2026-10-23, one of a kind: 2fat, who brings the old classic bangers back): the name thumps on the beat,
253 a big drop then a smaller one, in club lights, with an equalizer dancing before it and a speaker after it. Only its
254 one holder wears it (fx_twofat is never in the catalog). The equalizer and the speaker are pseudo-elements, so they
255 carry their own fill and motion rules (the Calm setting and the system preference). */
256.name-fx-twofat {
257 background: linear-gradient(90deg, #ff2fd6 0%, #a855ff 25%, #3de0ff 50%, #a855ff 75%, #ff2fd6 100%);
258 background-size: 200% 100%;
259 -webkit-background-clip: text;
260 background-clip: text;
261 -webkit-text-fill-color: transparent;
262 display: inline-block;
263 font-weight: 900;
264 letter-spacing: .03em;
265 white-space: nowrap;
266 transform-origin: 50% 70%;
267 animation: nameFxTwofatLights 3s linear infinite, nameFxTwofatThump 1s ease-out infinite;
268}
269.name-fx-twofat::before {
270 content: '▂▅▇▃▆';
271 display: inline-block;
272 margin-right: .3em;
273 color: #3de0ff;
274 -webkit-text-fill-color: #3de0ff;
275 text-shadow: 0 0 4px rgba(61, 224, 255, .8);
276 font-size: .6em;
277 letter-spacing: .12em;
278 vertical-align: .1em;
279 animation: nameFxTwofatEq .5s steps(1, end) infinite;
280}
281.name-fx-twofat::after {
282 content: '🔊';
283 display: inline-block;
284 margin-left: .3em;
285 -webkit-text-fill-color: initial;
286 font-size: .85em;
287 animation: nameFxTwofatSpeaker 1s ease-out infinite;
288}
289@keyframes nameFxTwofatLights {
290 0% { background-position: 0% 50%; }
291 100% { background-position: 200% 50%; }
292}
293/* The beat: a big thump, then a smaller one, the glow flaring pink, then blue. */
294@keyframes nameFxTwofatThump {
295 0% { transform: scale(1.12); filter: drop-shadow(0 0 6px rgba(255, 47, 214, .95)); }
296 18% { transform: scale(1); filter: drop-shadow(0 0 2px rgba(168, 85, 255, .6)); }
297 50% { transform: scale(1.05); filter: drop-shadow(0 0 4px rgba(61, 224, 255, .85)); }
298 68%, 100% { transform: scale(1); filter: drop-shadow(0 0 2px rgba(168, 85, 255, .6)); }
299}
300/* The equalizer jumps four times a beat (a browser that cannot animate `content` shows the first frame). */
301@keyframes nameFxTwofatEq {
302 0% { content: '▂▅▇▃▆'; }
303 25% { content: '▅▃▆▇▂'; }
304 50% { content: '▇▆▂▅▃'; }
305 75% { content: '▃▇▅▂▆'; }
306}
307@keyframes nameFxTwofatSpeaker {
308 0% { transform: scale(1.25); }
309 25%, 100% { transform: scale(1); }
310}
311html[data-ov-motion=off] .name-fx-twofat{filter: drop-shadow(0 0 3px rgba(255, 47, 214, .9))}
312
313/* Community badges (network.badge.image@1): the reviewed image, a little larger than the text, just before the name. */
314.ov-badge { display: inline-block; width: 1.15em; height: 1.15em; margin-right: 3px; vertical-align: -0.2em; border-radius: 3px; object-fit: contain; }
315
316/* Hats (live.hat.glyph@1): the emoji just before the name, Live's float/pulse/warp motions. */
317.ov-hat { display: inline-block; margin-right: 2px; font-size: 0.9em; line-height: 1; vertical-align: -0.05em; }
318.ov-hat-float { animation: ovHatFloat 2s ease-in-out infinite; }
319.ov-hat-pulse { animation: ovHatPulse 1.5s ease-in-out infinite; }
320.ov-hat-warp { animation: ovHatWarp 2s ease-in-out infinite; }
321@keyframes ovHatFloat { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-3px); } }
322@keyframes ovHatPulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.2); } }
323@keyframes ovHatWarp { 0%, 100% { transform: scale(1) rotate(0deg); filter: hue-rotate(0deg); } 50% { transform: scale(1.1) rotate(5deg); filter: hue-rotate(180deg); } }
324
325/* Light themes (theme-loader sets html[data-theme-mode=light]): every effect above was drawn for a dark page, bright
326 * colour plus glow; on white some were unreadable (Neon and Glitch's #00ff88 at 1.3:1, Ice at 1.6:1, Divine's white).
327 * The same effect, same hue and motion, at a depth that reads on a light page (about 4.6:1 or more, 2026-11-01). Void
328 * (#9900ff) already reads on white and keeps its colour. */
329html[data-theme-mode="light"] .name-fx-rainbow { background-image: linear-gradient(90deg, #dc2626, #c2410c, #a16207, #15803d, #1d4ed8, #7c3aed, #be185d); }
330html[data-theme-mode="light"] .name-fx-fire { color: #c2410c !important; text-shadow: 0 0 6px #fb923c55; animation-name: nameFxFireLight; }
331@keyframes nameFxFireLight {
332 0% { text-shadow: 0 0 5px #fb923c55; color: #c2410c; }
333 100% { text-shadow: 0 0 9px #f9731666, 0 0 16px #fdba7444; color: #b45309; }
334}
335html[data-theme-mode="light"] .name-fx-ice { color: #0369a1 !important; text-shadow: 0 0 6px #38bdf855; animation-name: nameFxIceLight; }
336@keyframes nameFxIceLight {
337 0% { text-shadow: 0 0 4px #38bdf855; color: #0369a1; }
338 100% { text-shadow: 0 0 9px #7dd3fc88, 0 0 16px #38bdf844; color: #0e7490; }
339}
340html[data-theme-mode="light"] .name-fx-golden { background-image: linear-gradient(90deg, #a16207, #b45309, #a16207, #92400e); }
341html[data-theme-mode="light"] .name-fx-neon { color: #047857 !important; text-shadow: 0 0 5px #34d39966; animation-name: nameFxNeonLight; }
342@keyframes nameFxNeonLight {
343 0% { text-shadow: 0 0 3px #34d39955; }
344 100% { text-shadow: 0 0 8px #34d39988, 0 0 14px #6ee7b744; }
345}
346html[data-theme-mode="light"] .name-fx-glitch { color: #047857 !important; }
347html[data-theme-mode="light"] .name-fx-galaxy { background-image: linear-gradient(90deg, #6d28d9, #be185d, #1d4ed8, #6d28d9); }
348html[data-theme-mode="light"] .name-fx-toxic { background-image: linear-gradient(90deg, #15803d, #4d7c0f, #3f6212, #047857); }
349html[data-theme-mode="light"] .name-fx-blood { background-image: linear-gradient(180deg, #dc2626, #7f1d1d, #b91c1c); }
350html[data-theme-mode="light"] .name-fx-shadow { color: #6b4f8a !important; animation-name: nameFxShadowLight; }
351@keyframes nameFxShadowLight {
352 0%, 100% { text-shadow: 0 0 5px rgba(80, 0, 120, 0.3), 1px 1px 3px rgba(30, 10, 50, 0.3); }
353 50% { text-shadow: 0 0 10px rgba(80, 0, 120, 0.4), 2px 2px 5px rgba(30, 10, 50, 0.35); }
354}
355html[data-theme-mode="light"] .name-fx-void { text-shadow: 0 0 6px #a855f755; animation-name: nameFxVoidLight; }
356@keyframes nameFxVoidLight {
357 0%, 100% { text-shadow: 0 0 5px #a855f755, 0 0 10px #c084fc33; transform: scale(1); }
358 50% { text-shadow: 0 0 9px #a855f777, 0 0 16px #c084fc44; transform: scale(1.03); }
359}
360html[data-theme-mode="light"] .name-fx-hologram { background-image: linear-gradient(90deg, #0f766e, #0369a1, #4f46e5, #047857); }
361html[data-theme-mode="light"] .name-fx-divine { background-image: linear-gradient(90deg, #b45309, #a16207, #92400e, #a16207, #b45309); }
362html[data-theme-mode="light"] .name-fx-vegas { background-image: linear-gradient(90deg, #b45309 0%, #a16207 22%, #c2410c 40%, #be185d 52%, #a16207 66%, #b45309 82%, #a16207 100%); }
363html[data-theme-mode="light"] .name-fx-twofat { background-image: linear-gradient(90deg, #c026d3 0%, #7e22ce 25%, #0e7490 50%, #7e22ce 75%, #c026d3 100%); }
364
365/* Particles (live.particle.css@1): characters that float out of the name and fade, Live's colours. They reset the
366 name effect's text fill, so a gradient name still shows them. */
367.ov-px { position: relative; display: inline-block; }
368.ov-px-p {
369 position: absolute; top: 0; pointer-events: none; font-size: 10px; line-height: 1;
370 background: none; -webkit-text-fill-color: currentColor; opacity: 0;
371 animation: ovPxFloat 1.8s ease-out forwards;
372}
373@keyframes ovPxFloat {
374 0% { opacity: 1; transform: translate(0, 0) scale(1); }
375 100% { opacity: 0; transform: translate(var(--px-dx, 10px), var(--px-dy, -20px)) scale(0.4); }
376}
377.px-sparkle .ov-px-p { color: #ffd700; }
378.px-hearts .ov-px-p { color: #ff6b9d; }
379.px-flames .ov-px-p { color: #ff6600; }
380.px-stars .ov-px-p { color: #fbbf24; }
381.px-void .ov-px-p { color: #9900ff; }
382.px-vegas .ov-px-p { color: #ffcf3f; text-shadow: 0 0 4px rgba(255, 61, 127, .75); }
383.px-twofat .ov-px-p { color: #ff2fd6; text-shadow: 0 0 4px rgba(61, 224, 255, .8); }
384
385html[data-ov-motion=off] .ov-px-p{display: none}
386