Merge pull request #91 from Utkarsh-Singhal-26/feat/liquid-ether

FEAT: 🎉 New <LiquidEther /> component
This commit is contained in:
David
2025-09-06 11:24:55 +03:00
committed by GitHub
6 changed files with 1518 additions and 3 deletions

View File

@@ -19,10 +19,10 @@
/>
<div class="hero-main-content">
<router-link to="/backgrounds/staggered-menu" class="hero-new-badge-container">
<router-link to="/backgrounds/liquid-ether" class="hero-new-badge-container">
<span class="hero-new-badge">New 🎉</span>
<div class="hero-new-badge-text">
<span>Staggered Menu</span>
<span>Liquid Ether</span>
<i class="pi-arrow-right pi" style="font-size: 0.8rem"></i>
</div>
</router-link>

View File

@@ -1,5 +1,5 @@
// Highlighted sidebar items
export const NEW = ['Staggered Menu', 'Pixel Blast', 'Gradual Blur', 'Gradient Blinds', 'Bubble Menu', 'Prism', 'Plasma', 'Electric Border', 'Target Cursor', 'Pill Nav', 'Card Nav', 'Logo Loop', 'Prismatic Burst'];
export const NEW = ['Liquid Ether', 'Staggered Menu', 'Pixel Blast', 'Gradual Blur', 'Gradient Blinds', 'Bubble Menu', 'Prism', 'Plasma', 'Electric Border', 'Target Cursor', 'Pill Nav', 'Card Nav', 'Logo Loop', 'Prismatic Burst'];
export const UPDATED = [];
// Used for main sidebar navigation
@@ -111,6 +111,7 @@ export const CATEGORIES = [
'Hyperspeed',
'Faulty Terminal',
'Plasma',
'Liquid Ether',
'Ripple Grid',
'Silk',
'Lightning',

View File

@@ -114,6 +114,7 @@ const backgrounds = {
'gradient-blinds': () => import('../demo/Backgrounds/GradientBlindsDemo.vue'),
'prismatic-burst': () => import('../demo/Backgrounds/PrismaticBurstDemo.vue'),
'pixel-blast': () => import('../demo/Backgrounds/PixelBlastDemo.vue'),
'liquid-ether': () => import('../demo/Backgrounds/LiquidEtherDemo.vue'),
};
export const componentMap = {

View File

@@ -0,0 +1,31 @@
import code from '@content/Backgrounds/LiquidEther/LiquidEther.vue?raw';
import { createCodeObject } from '../../../types/code';
export const liquidEther = createCodeObject(code, 'Backgrounds/LiquidEther', {
installation: `npm install three`,
usage: `<template>
<div style="width: 100%; height: 600px; position: relative">
<LiquidEther
:colors="['#48FF28', '#A2FFC6', '#9EF19E']"
:mouseForce="20"
:cursorSize="100"
:isViscous="false"
:viscous="30"
:iterationsViscous="32"
:iterationsPoisson="32"
:resolution="0.5"
:isBounce="false"
:autoDemo="true"
:autoSpeed="0.5"
:autoIntensity="2.2"
:takeoverDuration="0.25"
:autoResumeDelay="3000"
:autoRampDuration="0.6"
/>
</div>
</template>
<script setup lang="ts">
import LiquidEther from './LiquidEther.vue'
</script>`
});

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,217 @@
<template>
<TabbedLayout>
<template #preview>
<div class="relative p-0 h-[600px] overflow-hidden demo-container">
<LiquidEther
:colors="userColors"
:mouse-force="mouseForce"
:cursor-size="cursorSize"
:resolution="resolution"
:is-viscous="isViscous"
:viscous="viscous"
:iterations-viscous="iterationsViscous"
:iterations-poisson="iterationsPoisson"
:is-bounce="isBounce"
:auto-demo="autoDemo"
:auto-speed="autoSpeed"
:auto-intensity="autoIntensity"
:auto-resume-delay="500"
/>
<BackgroundContent pill-text="New Background" headline="The web, made fluid at your fingertips." />
</div>
<Customize>
<div class="flex gap-4">
<p class="mt-2 mb-1 text-sm">Color</p>
<PreviewColor v-model="color0" />
<PreviewColor v-model="color1" />
<PreviewColor v-model="color2" />
</div>
<PreviewSlider :min="0" :max="60" :step="1" v-model="mouseForce" title="Mouse Force" />
<PreviewSlider :min="10" :max="200" :step="5" v-model="cursorSize" title="Cursor Size" />
<PreviewSlider :min="0.2" :max="0.5" :step="0.05" v-model="resolution" title="Resolution" />
<PreviewSlider :min="0" :max="1" :step="0.05" v-model="autoSpeed" title="Auto Speed" />
<PreviewSlider :min="0" :max="4" :step="0.1" v-model="autoIntensity" title="Auto Intensity" />
<PreviewSlider :min="1" :max="64" :step="1" v-model="iterationsPoisson" title="Pressure" />
<PreviewSwitch title="Bounce Edges" v-model="isBounce" />
<PreviewSwitch title="Auto Animate" v-model="autoDemo" />
<PreviewSwitch title="Viscous" v-model="isViscous" />
<PreviewSlider v-if="isViscous" :min="1" :max="100" :step="1" v-model="viscous" title="Viscous Coef" />
<PreviewSlider
v-if="isViscous"
:min="1"
:max="64"
:step="1"
v-model="iterationsViscous"
title="Viscous Iterations"
/>
</Customize>
<PropTable :data="propData" />
<Dependencies :dependency-list="['three']" />
</template>
<template #code>
<CodeExample :code-object="liquidEther" />
</template>
<template #cli>
<CliInstallation :command="liquidEther.cli" />
</template>
</TabbedLayout>
</template>
<script setup lang="ts">
import { liquidEther } from '@/constants/code/Backgrounds/liquidEtherCode';
import { computed, ref } from 'vue';
import CliInstallation from '../../components/code/CliInstallation.vue';
import CodeExample from '../../components/code/CodeExample.vue';
import Dependencies from '../../components/code/Dependencies.vue';
import BackgroundContent from '../../components/common/BackgroundContent.vue';
import Customize from '../../components/common/Customize.vue';
import PreviewColor from '../../components/common/PreviewColor.vue';
import PreviewSwitch from '../../components/common/PreviewSwitch.vue';
import PreviewSlider from '../../components/common/PreviewSlider.vue';
import PropTable from '../../components/common/PropTable.vue';
import TabbedLayout from '../../components/common/TabbedLayout.vue';
import LiquidEther from '../../content/Backgrounds/LiquidEther/LiquidEther.vue';
const mouseForce = ref(20);
const cursorSize = ref(100);
const resolution = ref(0.5);
const isViscous = ref(true);
const viscous = ref(30);
const iterationsViscous = ref(32);
const iterationsPoisson = ref(32);
const isBounce = ref(false);
const autoDemo = ref(true);
const autoSpeed = ref(0.5);
const autoIntensity = ref(2.2);
const color0 = ref('#48FF28');
const color1 = ref('#A2FFC6');
const color2 = ref('#9EF19E');
const userColors = computed(() => [color0.value, color1.value, color2.value].filter(Boolean) as string[]);
const propData = [
{
name: 'colors',
type: 'string[]',
default: `["#48FF28", "#A2FFC6", "#9EF19E"]`,
description: 'Array of hex color stops used to build the velocity-to-color palette.'
},
{
name: 'mouseForce',
type: 'number',
default: '20',
description: 'Strength multiplier applied to mouse / touch movement when injecting velocity.'
},
{
name: 'cursorSize',
type: 'number',
default: '100',
description: 'Radius (in pixels at base resolution) of the force brush.'
},
{
name: 'resolution',
type: 'number',
default: '0.5',
description: 'Simulation texture scale relative to canvas size (lower = better performance, more blur).'
},
{
name: 'dt',
type: 'number',
default: '0.014',
description: 'Fixed simulation timestep used inside the advection / diffusion passes.'
},
{
name: 'BFECC',
type: 'boolean',
default: 'true',
description: 'Enable BFECC advection (error-compensated) for crisper flow; disable for slight performance gain.'
},
{
name: 'isViscous',
type: 'boolean',
default: 'false',
description: 'Toggle iterative viscosity solve (smoother, thicker motion when enabled).'
},
{
name: 'viscous',
type: 'number',
default: '30',
description: 'Viscosity coefficient used when isViscous is true.'
},
{
name: 'iterationsViscous',
type: 'number',
default: '32',
description: 'Number of Gauss-Seidel iterations for viscosity (higher = smoother, slower).'
},
{
name: 'iterationsPoisson',
type: 'number',
default: '32',
description: 'Number of pressure Poisson iterations to enforce incompressibility.'
},
{
name: 'isBounce',
type: 'boolean',
default: 'false',
description: 'If true, shows bounce boundaries (velocity clamped at edges).'
},
{
name: 'autoDemo',
type: 'boolean',
default: 'true',
description: 'Enable idle auto-driving of the pointer when no user interaction.'
},
{
name: 'autoSpeed',
type: 'number',
default: '0.5',
description: 'Speed (normalized units/sec) for auto pointer motion.'
},
{
name: 'autoIntensity',
type: 'number',
default: '2.2',
description: 'Multiplier applied to velocity delta while in auto mode.'
},
{
name: 'takeoverDuration',
type: 'number',
default: '0.25',
description: 'Seconds to interpolate from auto pointer to real cursor when user moves mouse.'
},
{
name: 'autoResumeDelay',
type: 'number',
default: '1000',
description: 'Milliseconds of inactivity before auto mode resumes.'
},
{
name: 'autoRampDuration',
type: 'number',
default: '0.6',
description: 'Seconds to ramp auto movement speed from 0 to full after activation.'
},
{
name: 'className',
type: 'string',
default: "''",
description: 'Optional class for the root container.'
},
{
name: 'style',
type: 'CSSProperties',
default: '{}',
description: 'Inline styles applied to the root container.'
}
];
</script>