Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 201 additions & 0 deletions src/lib/components/docs/pages/ScrollVelocityDemo.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
<script lang="ts">
import TabsLayout from '$lib/components/docs/preview/TabsLayout.svelte';
import Customize from '$lib/components/docs/preview/Customize.svelte';
import PreviewSlider from '$lib/components/docs/preview/PreviewSlider.svelte';
import PropTable, { type PropRow } from '$lib/components/docs/preview/PropTable.svelte';
import DemoCodeTab from '$lib/components/docs/preview/DemoCodeTab.svelte';
import ReplayButton from '$lib/components/docs/preview/ReplayButton.svelte';
import ScrollVelocity from '$lib/components/library/TextAnimations/ScrollVelocity/ScrollVelocity.svelte';
import source from '$lib/components/library/TextAnimations/ScrollVelocity/ScrollVelocity.svelte?raw';

const DEFAULTS = {
velocity: 100,
numCopies: 6,
damping: 50,
stiffness: 400
};

let velocity = $state(DEFAULTS.velocity);
let numCopies = $state(DEFAULTS.numCopies);
let damping = $state(DEFAULTS.damping);
let stiffness = $state(DEFAULTS.stiffness);
let replay = $state(0);

const hasChanges = $derived(
velocity !== DEFAULTS.velocity ||
numCopies !== DEFAULTS.numCopies ||
damping !== DEFAULTS.damping ||
stiffness !== DEFAULTS.stiffness
);

function reset() {
velocity = DEFAULTS.velocity;
numCopies = DEFAULTS.numCopies;
damping = DEFAULTS.damping;
stiffness = DEFAULTS.stiffness;
replay++;
}

const usage = $derived(`<ScrollVelocity
texts={['Svelte Bits', 'Scroll Down']}
velocity={${velocity}}
numCopies={${numCopies}}
damping={${damping}}
stiffness={${stiffness}}
/>`);

const props: PropRow[] = [
{
name: 'scrollContainer',
type: 'HTMLElement | null',
default: 'null',
description: 'Optional custom scroll container to track. Defaults to window.'
},
{
name: 'texts',
type: 'string[]',
default: '[]',
description: 'Array of strings to render as scrolling rows. Odd-indexed rows scroll in the opposite direction.'
},
{
name: 'velocity',
type: 'number',
default: '100',
description: 'Base scrolling velocity in px per second. Sign flips for odd-indexed rows.'
},
{
name: 'class',
type: 'string',
default: '""',
description: 'CSS class applied to each text copy span.'
},
{
name: 'damping',
type: 'number',
default: '50',
description: 'Damping coefficient for the spring smoothing scroll velocity.'
},
{
name: 'stiffness',
type: 'number',
default: '400',
description: 'Stiffness coefficient for the spring smoothing scroll velocity.'
},
{
name: 'numCopies',
type: 'number',
default: '6',
description: 'Number of text copies rendered in each row for a continuous loop.'
},
{
name: 'velocityMapping',
type: '{ input: [number, number]; output: [number, number] }',
default: '{ input: [0, 1000], output: [0, 5] }',
description: 'Linear mapping from scroll velocity to motion multiplier.'
},
{
name: 'parallaxClass',
type: 'string',
default: '"parallax"',
description: 'CSS class for the parallax container of each row.'
},
{
name: 'scrollerClass',
type: 'string',
default: '"scroller"',
description: 'CSS class for the inner scroller div of each row.'
},
{
name: 'parallaxStyle',
type: 'string',
default: '""',
description: 'Inline style applied to each parallax container.'
},
{
name: 'scrollerStyle',
type: 'string',
default: '""',
description: 'Inline style applied to each scroller div.'
}
];
</script>

<svelte:head><title>Scroll Velocity - svelte-bits</title></svelte:head>

<h1 class="sub-category">Scroll Velocity</h1>

<TabsLayout onreset={reset} {hasChanges} componentName="ScrollVelocity" {usage} {source} {props}>
{#snippet preview()}
<div
class="demo-container relative flex w-full items-center justify-center overflow-hidden"
style="height:400px;padding:0;"
>
<ReplayButton onClick={() => replay++} />
{#key replay}
<div class="w-full">
<ScrollVelocity
texts={['Svelte Bits', 'Scroll Down']}
{velocity}
{numCopies}
{damping}
{stiffness}
/>
</div>
{/key}
</div>
{/snippet}
{#snippet code()}
<DemoCodeTab slug="scroll-velocity" {usage} {source} />
{/snippet}
{#snippet customize()}
<Customize>
<PreviewSlider
title="Velocity"
min={10}
max={500}
step={10}
value={velocity}
onChange={(v) => {
velocity = v;
replay++;
}}
/>
<PreviewSlider
title="Num Copies"
min={2}
max={12}
step={1}
value={numCopies}
onChange={(v) => {
numCopies = v;
replay++;
}}
/>
<PreviewSlider
title="Damping"
min={10}
max={100}
step={5}
value={damping}
onChange={(v) => {
damping = v;
replay++;
}}
/>
<PreviewSlider
title="Stiffness"
min={100}
max={800}
step={50}
value={stiffness}
onChange={(v) => {
stiffness = v;
replay++;
}}
/>
</Customize>
{/snippet}
{#snippet propTable()}
<PropTable rows={props} />
{/snippet}
</TabsLayout>
1 change: 1 addition & 0 deletions src/lib/components/docs/pages/demoRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,4 +136,5 @@ export const DOC_PAGE_REGISTRY: Record<string, DemoLoader> = {
'rotating-text': () => import('./RotatingTextDemo.svelte'),
'scroll-reveal': () => import('./ScrollRevealDemo.svelte'),
'ascii-text': () => import('./ASCIITextDemo.svelte'),
'scroll-velocity': () => import('./ScrollVelocityDemo.svelte'),
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
<!-- @svelte-bits
{
"title": "Scroll Velocity",
"description": "Multi-row marquee that scrolls horizontally at a base velocity and accelerates with spring-smoothed page-scroll movement.",
"dependencies": []
}
-->
<script lang="ts">
type VelocityMapping = { input: [number, number]; output: [number, number] };

type Props = {
scrollContainer?: HTMLElement | null;
texts?: string[];
velocity?: number;
class?: string;
damping?: number;
stiffness?: number;
numCopies?: number;
velocityMapping?: VelocityMapping;
parallaxClass?: string;
scrollerClass?: string;
parallaxStyle?: string;
scrollerStyle?: string;
};

let {
scrollContainer = null,
texts = [],
velocity = 100,
class: className = '',
damping = 50,
stiffness = 400,
numCopies = 6,
velocityMapping = { input: [0, 1000], output: [0, 5] },
parallaxClass = 'parallax',
scrollerClass = 'scroller',
parallaxStyle = '',
scrollerStyle = ''
}: Props = $props();

let copyEls: (HTMLSpanElement | undefined)[] = $state([]);
let scrollerEls: (HTMLDivElement | undefined)[] = $state([]);

function wrap(min: number, max: number, v: number): number {
const range = max - min;
const mod = (((v - min) % range) + range) % range;
return mod + min;
}

$effect(() => {
if (typeof window === 'undefined') return;

const target: HTMLElement | Window = scrollContainer ?? window;
const getScrollY = () =>
target === window
? window.scrollY || window.pageYOffset || 0
: (target as HTMLElement).scrollTop;

const count = texts.length;
const baseX = new Array(count).fill(0);
const directionFactors = new Array(count).fill(1);

let prevScrollY = getScrollY();
let smoothVelocity = 0;
let springVel = 0;
let lastTime = performance.now();

const [iMin, iMax] = velocityMapping?.input ?? [0, 1000];
const [oMin, oMax] = velocityMapping?.output ?? [0, 5];
const inputSpan = iMax - iMin || 1;

let raf = 0;
const tick = (t: number) => {
const dtRaw = (t - lastTime) / 1000;
const dt = Math.min(dtRaw, 0.05);
lastTime = t;

const sy = getScrollY();
const scrollVelocity = dtRaw > 0 ? (sy - prevScrollY) / dtRaw : 0;
prevScrollY = sy;

const accel = stiffness * (scrollVelocity - smoothVelocity) - damping * springVel;
springVel += accel * dt;
smoothVelocity += springVel * dt;

const velocityFactor = ((smoothVelocity - iMin) / inputSpan) * (oMax - oMin) + oMin;

for (let i = 0; i < count; i++) {
const baseVelocity = i % 2 !== 0 ? -velocity : velocity;
let moveBy = directionFactors[i] * baseVelocity * dt;

if (velocityFactor < 0) directionFactors[i] = -1;
else if (velocityFactor > 0) directionFactors[i] = 1;

moveBy += directionFactors[i] * moveBy * velocityFactor;
baseX[i] += moveBy;

const copy = copyEls[i];
const scroller = scrollerEls[i];
if (!copy || !scroller) continue;

const copyWidth = copy.offsetWidth;
if (copyWidth > 0) {
const x = wrap(-copyWidth, 0, baseX[i]);
scroller.style.transform = `translate3d(${x}px, 0, 0)`;
}
}

raf = requestAnimationFrame(tick);
};
raf = requestAnimationFrame(tick);

return () => cancelAnimationFrame(raf);
});
</script>

<section>
{#each texts as text, i (i)}
<div class={parallaxClass} style={parallaxStyle}>
<div bind:this={scrollerEls[i]} class={scrollerClass} style={scrollerStyle}>
{#each Array.from({ length: Math.max(numCopies, 1) }, (_, j) => j) as j (j)}
{#if j === 0}
<span bind:this={copyEls[i]} class={className}>{text}&nbsp;</span>
{:else}
<span class={className}>{text}&nbsp;</span>
{/if}
{/each}
</div>
</div>
{/each}
</section>

<style>
section :global(.parallax) {
position: relative;
overflow: hidden;
}
section :global(.scroller) {
display: flex;
white-space: nowrap;
text-align: center;
font-family: sans-serif;
font-size: 2.25rem;
font-weight: bold;
letter-spacing: -0.02em;
filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.1));
}
section :global(.scroller span) {
flex-shrink: 0;
}
@media (min-width: 768px) {
section :global(.scroller) {
font-size: 5rem;
line-height: 5rem;
}
}
</style>
1 change: 1 addition & 0 deletions src/lib/constants/categories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ export const IMPLEMENTED_DEMOS = new Set<string>([
'rotating-text',
'scroll-reveal',
'ascii-text',
'scroll-velocity',
]);

// Helper: is this subcategory label fully ported?
Expand Down
2 changes: 1 addition & 1 deletion static/r/curved-loop.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"type": "registry:component",
"path": "CurvedLoop.svelte",
"target": "$lib/components/svelte-bits/CurvedLoop.svelte",
"content": "<script lang=\"ts\">\n\ttype Direction = 'left' | 'right';\n\n\ttype Props = {\n\t\tmarqueeText?: string;\n\t\tspeed?: number;\n\t\tclass?: string;\n\t\tcurveAmount?: number;\n\t\tdirection?: Direction;\n\t\tinteractive?: boolean;\n\t};\n\n\tlet {\n\t\tmarqueeText = '',\n\t\tspeed = 2,\n\t\tclass: className = '',\n\t\tcurveAmount = 400,\n\t\tdirection = 'left',\n\t\tinteractive = true\n\t}: Props = $props();\n\n\tconst text = $derived.by(() => {\n\t\tconst hasTrailing = /\\s| $/.test(marqueeText);\n\t\treturn (hasTrailing ? marqueeText.replace(/\\s+$/, '') : marqueeText) + ' ';\n\t});\n\n\tlet measureEl: SVGTextElement | undefined = $state();\n\tlet textPathEl: SVGTextPathElement | undefined = $state();\n\tlet spacing = $state(0);\n\tlet offset = $state(0);\n\tlet isDragging = $state(false);\n\n\tconst uid = $props.id();\n\tconst pathId = `curve-${uid}`;\n\tconst pathD = $derived(`M-100,40 Q500,${40 + curveAmount} 1540,40`);\n\n\tlet dragActive = false;\n\tlet lastX = 0;\n\tlet velX = 0;\n\tlet dirInternal: Direction = direction;\n\n\t$effect(() => {\n\t\tdirInternal = direction;\n\t});\n\n\tconst totalText = $derived.by(() => {\n\t\tconst len = spacing;\n\t\tif (!len) return text;\n\t\treturn Array(Math.ceil(1800 / len) + 2)\n\t\t\t.fill(text)\n\t\t\t.join('');\n\t});\n\tconst ready = $derived(spacing > 0);\n\n\t$effect(() => {\n\t\tvoid text;\n\t\tvoid className;\n\t\tif (measureEl) {\n\t\t\tspacing = measureEl.getComputedTextLength();\n\t\t}\n\t});\n\n\t$effect(() => {\n\t\tif (!spacing) return;\n\t\tif (textPathEl) {\n\t\t\tconst initial = -spacing;\n\t\t\ttextPathEl.setAttribute('startOffset', initial + 'px');\n\t\t\toffset = initial;\n\t\t}\n\t});\n\n\t$effect(() => {\n\t\tif (!spacing || !ready) return;\n\t\tvoid speed;\n\t\tlet frame = 0;\n\t\tconst step = () => {\n\t\t\tif (!dragActive && textPathEl) {\n\t\t\t\tconst delta = dirInternal === 'right' ? speed : -speed;\n\t\t\t\tconst currentOffset = parseFloat(textPathEl.getAttribute('startOffset') || '0');\n\t\t\t\tlet newOffset = currentOffset + delta;\n\n\t\t\t\tconst wrapPoint = spacing;\n\t\t\t\tif (newOffset <= -wrapPoint) newOffset += wrapPoint;\n\t\t\t\tif (newOffset > 0) newOffset -= wrapPoint;\n\n\t\t\t\ttextPathEl.setAttribute('startOffset', newOffset + 'px');\n\t\t\t\toffset = newOffset;\n\t\t\t}\n\t\t\tframe = requestAnimationFrame(step);\n\t\t};\n\t\tframe = requestAnimationFrame(step);\n\t\treturn () => cancelAnimationFrame(frame);\n\t});\n\n\tfunction onPointerDown(e: PointerEvent) {\n\t\tif (!interactive) return;\n\t\tdragActive = true;\n\t\tisDragging = true;\n\t\tlastX = e.clientX;\n\t\tvelX = 0;\n\t\t(e.target as Element)?.setPointerCapture?.(e.pointerId);\n\t}\n\n\tfunction onPointerMove(e: PointerEvent) {\n\t\tif (!interactive || !dragActive || !textPathEl) return;\n\t\tconst dx = e.clientX - lastX;\n\t\tlastX = e.clientX;\n\t\tvelX = dx;\n\n\t\tconst currentOffset = parseFloat(textPathEl.getAttribute('startOffset') || '0');\n\t\tlet newOffset = currentOffset + dx;\n\n\t\tconst wrapPoint = spacing;\n\t\tif (newOffset <= -wrapPoint) newOffset += wrapPoint;\n\t\tif (newOffset > 0) newOffset -= wrapPoint;\n\n\t\ttextPathEl.setAttribute('startOffset', newOffset + 'px');\n\t\toffset = newOffset;\n\t}\n\n\tfunction endDrag() {\n\t\tif (!interactive) return;\n\t\tdragActive = false;\n\t\tisDragging = false;\n\t\tdirInternal = velX > 0 ? 'right' : 'left';\n\t}\n\n\tconst cursorStyle = $derived(interactive ? (isDragging ? 'grabbing' : 'grab') : 'auto');\n</script>\n\n<div\n\tclass=\"curved-loop-jacket\"\n\tstyle:visibility={ready ? 'visible' : 'hidden'}\n\tstyle:cursor={cursorStyle}\n\tonpointerdown={onPointerDown}\n\tonpointermove={onPointerMove}\n\tonpointerup={endDrag}\n\tonpointerleave={endDrag}\n>\n\t<svg class=\"curved-loop-svg\" viewBox=\"0 0 1440 120\">\n\t\t<text\n\t\t\tbind:this={measureEl}\n\t\t\txml:space=\"preserve\"\n\t\t\tstyle=\"visibility:hidden;opacity:0;pointer-events:none;\"\n\t\t>{text}</text>\n\t\t<defs>\n\t\t\t<path id={pathId} d={pathD} fill=\"none\" stroke=\"transparent\" />\n\t\t</defs>\n\t\t{#if ready}\n\t\t\t<text font-weight=\"bold\" xml:space=\"preserve\" class={className}>\n\t\t\t\t<textPath\n\t\t\t\t\tbind:this={textPathEl}\n\t\t\t\t\thref={`#${pathId}`}\n\t\t\t\t\tstartOffset={offset + 'px'}\n\t\t\t\t\txml:space=\"preserve\">{totalText}</textPath>\n\t\t\t</text>\n\t\t{/if}\n\t</svg>\n</div>\n\n<style>\n\t.curved-loop-jacket {\n\t\tmin-height: 100vh;\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\twidth: 100%;\n\t}\n\n\t.curved-loop-svg {\n\t\tuser-select: none;\n\t\twidth: 100%;\n\t\taspect-ratio: 100 / 12;\n\t\toverflow: visible;\n\t\tdisplay: block;\n\t\tfont-size: 6rem;\n\t\tfill: #ffffff;\n\t\t-moz-user-select: none;\n\t\t-webkit-user-select: none;\n\t\tfont-weight: 700;\n\t\ttext-transform: uppercase;\n\t\tline-height: 1;\n\t}\n</style>\n"
"content": "<script lang=\"ts\">\n\ttype Direction = 'left' | 'right';\n\n\ttype Props = {\n\t\tmarqueeText?: string;\n\t\tspeed?: number;\n\t\tclass?: string;\n\t\tcurveAmount?: number;\n\t\tdirection?: Direction;\n\t\tinteractive?: boolean;\n\t};\n\n\tlet {\n\t\tmarqueeText = '',\n\t\tspeed = 2,\n\t\tclass: className = '',\n\t\tcurveAmount = 400,\n\t\tdirection = 'left',\n\t\tinteractive = true\n\t}: Props = $props();\n\n\tconst text = $derived.by(() => {\n\t\tconst hasTrailing = /\\s|\\u00A0$/.test(marqueeText);\n\t\treturn (hasTrailing ? marqueeText.replace(/\\s+$/, '') : marqueeText) + ' ';\n\t});\n\n\tlet measureEl: SVGTextElement | undefined = $state();\n\tlet textPathEl: SVGTextPathElement | undefined = $state();\n\tlet spacing = $state(0);\n\tlet offset = $state(0);\n\tlet isDragging = $state(false);\n\n\tconst uid = $props.id();\n\tconst pathId = `curve-${uid}`;\n\tconst pathD = $derived(`M-100,40 Q500,${40 + curveAmount} 1540,40`);\n\n\tlet dragActive = false;\n\tlet lastX = 0;\n\tlet velX = 0;\n\t// svelte-ignore state_referenced_locally\n\tlet dirInternal: Direction = direction;\n\n\t$effect(() => {\n\t\tdirInternal = direction;\n\t});\n\n\tconst totalText = $derived.by(() => {\n\t\tconst len = spacing;\n\t\tif (!len) return text;\n\t\treturn Array(Math.ceil(1800 / len) + 2)\n\t\t\t.fill(text)\n\t\t\t.join('');\n\t});\n\tconst ready = $derived(spacing > 0);\n\n\t$effect(() => {\n\t\tvoid text;\n\t\tvoid className;\n\t\tif (measureEl) {\n\t\t\tspacing = measureEl.getComputedTextLength();\n\t\t}\n\t});\n\n\t$effect(() => {\n\t\tif (!spacing) return;\n\t\tif (textPathEl) {\n\t\t\tconst initial = -spacing;\n\t\t\ttextPathEl.setAttribute('startOffset', initial + 'px');\n\t\t\toffset = initial;\n\t\t}\n\t});\n\n\t$effect(() => {\n\t\tif (!spacing || !ready) return;\n\t\tvoid speed;\n\t\tlet frame = 0;\n\t\tconst step = () => {\n\t\t\tif (!dragActive && textPathEl) {\n\t\t\t\tconst delta = dirInternal === 'right' ? speed : -speed;\n\t\t\t\tconst currentOffset = parseFloat(textPathEl.getAttribute('startOffset') || '0');\n\t\t\t\tlet newOffset = currentOffset + delta;\n\n\t\t\t\tconst wrapPoint = spacing;\n\t\t\t\tif (newOffset <= -wrapPoint) newOffset += wrapPoint;\n\t\t\t\tif (newOffset > 0) newOffset -= wrapPoint;\n\n\t\t\t\ttextPathEl.setAttribute('startOffset', newOffset + 'px');\n\t\t\t\toffset = newOffset;\n\t\t\t}\n\t\t\tframe = requestAnimationFrame(step);\n\t\t};\n\t\tframe = requestAnimationFrame(step);\n\t\treturn () => cancelAnimationFrame(frame);\n\t});\n\n\tfunction onPointerDown(e: PointerEvent) {\n\t\tif (!interactive) return;\n\t\tdragActive = true;\n\t\tisDragging = true;\n\t\tlastX = e.clientX;\n\t\tvelX = 0;\n\t\t(e.target as Element)?.setPointerCapture?.(e.pointerId);\n\t}\n\n\tfunction onPointerMove(e: PointerEvent) {\n\t\tif (!interactive || !dragActive || !textPathEl) return;\n\t\tconst dx = e.clientX - lastX;\n\t\tlastX = e.clientX;\n\t\tvelX = dx;\n\n\t\tconst currentOffset = parseFloat(textPathEl.getAttribute('startOffset') || '0');\n\t\tlet newOffset = currentOffset + dx;\n\n\t\tconst wrapPoint = spacing;\n\t\tif (newOffset <= -wrapPoint) newOffset += wrapPoint;\n\t\tif (newOffset > 0) newOffset -= wrapPoint;\n\n\t\ttextPathEl.setAttribute('startOffset', newOffset + 'px');\n\t\toffset = newOffset;\n\t}\n\n\tfunction endDrag() {\n\t\tif (!interactive) return;\n\t\tdragActive = false;\n\t\tisDragging = false;\n\t\tdirInternal = velX > 0 ? 'right' : 'left';\n\t}\n\n\tconst cursorStyle = $derived(interactive ? (isDragging ? 'grabbing' : 'grab') : 'auto');\n</script>\n\n<!-- svelte-ignore a11y_no_static_element_interactions -->\n<div\n\tclass=\"curved-loop-jacket\"\n\tstyle:visibility={ready ? 'visible' : 'hidden'}\n\tstyle:cursor={cursorStyle}\n\tonpointerdown={onPointerDown}\n\tonpointermove={onPointerMove}\n\tonpointerup={endDrag}\n\tonpointerleave={endDrag}\n>\n\t<svg class=\"curved-loop-svg\" viewBox=\"0 0 1440 120\">\n\t\t<text\n\t\t\tbind:this={measureEl}\n\t\t\txml:space=\"preserve\"\n\t\t\tstyle=\"visibility:hidden;opacity:0;pointer-events:none;\"\n\t\t>{text}</text>\n\t\t<defs>\n\t\t\t<path id={pathId} d={pathD} fill=\"none\" stroke=\"transparent\" />\n\t\t</defs>\n\t\t{#if ready}\n\t\t\t<text font-weight=\"bold\" xml:space=\"preserve\" class={className}>\n\t\t\t\t<textPath\n\t\t\t\t\tbind:this={textPathEl}\n\t\t\t\t\thref={`#${pathId}`}\n\t\t\t\t\tstartOffset={offset + 'px'}\n\t\t\t\t\txml:space=\"preserve\">{totalText}</textPath>\n\t\t\t</text>\n\t\t{/if}\n\t</svg>\n</div>\n\n<style>\n\t.curved-loop-jacket {\n\t\tmin-height: 100vh;\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\twidth: 100%;\n\t}\n\n\t.curved-loop-svg {\n\t\tuser-select: none;\n\t\twidth: 100%;\n\t\taspect-ratio: 100 / 12;\n\t\toverflow: visible;\n\t\tdisplay: block;\n\t\tfont-size: 6rem;\n\t\tfill: #ffffff;\n\t\t-moz-user-select: none;\n\t\t-webkit-user-select: none;\n\t\tfont-weight: 700;\n\t\ttext-transform: uppercase;\n\t\tline-height: 1;\n\t}\n</style>\n"
}
],
"registryDependencies": [],
Expand Down
Loading