UNPKG

ng-cw-v12

Version:

Angular UI Component Library

1,293 lines 60.6 kB
import * as i0 from '@angular/core';
import { Component, ViewChild, Input, HostListener, NgModule } from '@angular/core';
import * as THREE from 'three';
import { CommonModule } from '@angular/common';

// ─── 顶点着色器(公用)───────────────────────────────────────────────────────
const face_vert = `
  attribute vec3 position;
  uniform vec2 px;
  uniform vec2 boundarySpace;
  varying vec2 uv;
  precision highp float;
  void main(){
    vec3 pos = position;
    vec2 scale = 1.0 - boundarySpace * 2.0;
    pos.xy = pos.xy * scale;
    uv = vec2(0.5) + (pos.xy) * 0.5;
    gl_Position = vec4(pos, 1.0);
  }
`;
// ─── 边界线顶点着色器 ──────────────────────────────────────────────────────
const line_vert = `
  attribute vec3 position;
  uniform vec2 px;
  precision highp float;
  varying vec2 uv;
  void main(){
    vec3 pos = position;
    uv = 0.5 + pos.xy * 0.5;
    vec2 n = sign(pos.xy);
    pos.xy = abs(pos.xy) - px * 1.0;
    pos.xy *= n;
    gl_Position = vec4(pos, 1.0);
  }
`;
// ─── 鼠标力顶点着色器 ──────────────────────────────────────────────────────
const mouse_vert = `
  precision highp float;
  attribute vec3 position;
  attribute vec2 uv;
  uniform vec2 center;
  uniform vec2 scale;
  uniform vec2 px;
  varying vec2 vUv;
  void main(){
    vec2 pos = position.xy * scale * 2.0 * px + center;
    vUv = uv;
    gl_Position = vec4(pos, 0.0, 1.0);
  }
`;
// ─── 平流片元着色器(BFECC)────────────────────────────────────────────────
const advection_frag = `
  precision highp float;
  uniform sampler2D velocity;
  uniform float dt;
  uniform bool isBFECC;
  uniform vec2 fboSize;
  uniform vec2 px;
  varying vec2 uv;
  void main(){
    vec2 ratio = max(fboSize.x, fboSize.y) / fboSize;
    if(isBFECC == false){
      vec2 vel = texture2D(velocity, uv).xy;
      vec2 uv2 = uv - vel * dt * ratio;
      vec2 newVel = texture2D(velocity, uv2).xy;
      gl_FragColor = vec4(newVel, 0.0, 0.0);
    } else {
      vec2 spot_new = uv;
      vec2 vel_old = texture2D(velocity, uv).xy;
      vec2 spot_old = spot_new - vel_old * dt * ratio;
      vec2 vel_new1 = texture2D(velocity, spot_old).xy;
      vec2 spot_new2 = spot_old + vel_new1 * dt * ratio;
      vec2 error = spot_new2 - spot_new;
      vec2 spot_new3 = spot_new - error / 2.0;
      vec2 vel_2 = texture2D(velocity, spot_new3).xy;
      vec2 spot_old2 = spot_new3 - vel_2 * dt * ratio;
      vec2 newVel2 = texture2D(velocity, spot_old2).xy;
      gl_FragColor = vec4(newVel2, 0.0, 0.0);
    }
  }
`;
// ─── 颜色输出片元着色器 ────────────────────────────────────────────────────
const color_frag = `
  precision highp float;
  uniform sampler2D velocity;
  uniform sampler2D palette;
  uniform vec4 bgColor;
  varying vec2 uv;
  void main(){
    vec2 vel = texture2D(velocity, uv).xy;
    float lenv = clamp(length(vel), 0.0, 1.0);
    vec3 c = texture2D(palette, vec2(lenv, 0.5)).rgb;
    vec3 outRGB = mix(bgColor.rgb, c, lenv);
    float outA = mix(bgColor.a, 1.0, lenv);
    gl_FragColor = vec4(outRGB, outA);
  }
`;
// ─── 散度片元着色器 ────────────────────────────────────────────────────────
const divergence_frag = `
  precision highp float;
  uniform sampler2D velocity;
  uniform float dt;
  uniform vec2 px;
  varying vec2 uv;
  void main(){
    float x0 = texture2D(velocity, uv - vec2(px.x, 0.0)).x;
    float x1 = texture2D(velocity, uv + vec2(px.x, 0.0)).x;
    float y0 = texture2D(velocity, uv - vec2(0.0, px.y)).y;
    float y1 = texture2D(velocity, uv + vec2(0.0, px.y)).y;
    float divergence = (x1 - x0 + y1 - y0) / 2.0;
    gl_FragColor = vec4(divergence / dt);
  }
`;
// ─── 外力片元着色器 ────────────────────────────────────────────────────────
const externalForce_frag = `
  precision highp float;
  uniform vec2 force;
  uniform vec2 center;
  uniform vec2 scale;
  uniform vec2 px;
  varying vec2 vUv;
  void main(){
    vec2 circle = (vUv - 0.5) * 2.0;
    float d = 1.0 - min(length(circle), 1.0);
    d *= d;
    gl_FragColor = vec4(force * d, 0.0, 1.0);
  }
`;
// ─── 泊松压力片元着色器 ────────────────────────────────────────────────────
const poisson_frag = `
  precision highp float;
  uniform sampler2D pressure;
  uniform sampler2D divergence;
  uniform vec2 px;
  varying vec2 uv;
  void main(){
    float p0 = texture2D(pressure, uv + vec2(px.x * 2.0, 0.0)).r;
    float p1 = texture2D(pressure, uv - vec2(px.x * 2.0, 0.0)).r;
    float p2 = texture2D(pressure, uv + vec2(0.0, px.y * 2.0)).r;
    float p3 = texture2D(pressure, uv - vec2(0.0, px.y * 2.0)).r;
    float div = texture2D(divergence, uv).r;
    float newP = (p0 + p1 + p2 + p3) / 4.0 - div;
    gl_FragColor = vec4(newP);
  }
`;
// ─── 压力梯度修正片元着色器 ────────────────────────────────────────────────
const pressure_frag = `
  precision highp float;
  uniform sampler2D pressure;
  uniform sampler2D velocity;
  uniform vec2 px;
  uniform float dt;
  varying vec2 uv;
  void main(){
    float step = 1.0;
    float p0 = texture2D(pressure, uv + vec2(px.x * step, 0.0)).r;
    float p1 = texture2D(pressure, uv - vec2(px.x * step, 0.0)).r;
    float p2 = texture2D(pressure, uv + vec2(0.0, px.y * step)).r;
    float p3 = texture2D(pressure, uv - vec2(0.0, px.y * step)).r;
    vec2 v = texture2D(velocity, uv).xy;
    vec2 gradP = vec2(p0 - p1, p2 - p3) * 0.5;
    v = v - gradP * dt;
    gl_FragColor = vec4(v, 0.0, 1.0);
  }
`;
// ─── 粘性扩散片元着色器 ────────────────────────────────────────────────────
const viscous_frag = `
  precision highp float;
  uniform sampler2D velocity;
  uniform sampler2D velocity_new;
  uniform float v;
  uniform vec2 px;
  uniform float dt;
  varying vec2 uv;
  void main(){
    vec2 old  = texture2D(velocity,     uv).xy;
    vec2 new0 = texture2D(velocity_new, uv + vec2(px.x * 2.0, 0.0)).xy;
    vec2 new1 = texture2D(velocity_new, uv - vec2(px.x * 2.0, 0.0)).xy;
    vec2 new2 = texture2D(velocity_new, uv + vec2(0.0, px.y * 2.0)).xy;
    vec2 new3 = texture2D(velocity_new, uv - vec2(0.0, px.y * 2.0)).xy;
    vec2 newv = 4.0 * old + v * dt * (new0 + new1 + new2 + new3);
    newv /= 4.0 * (1.0 + v * dt);
    gl_FragColor = vec4(newv, 0.0, 0.0);
  }
`;
// ─── 边界处理片元着色器:速度反弹 ──────────────────────────────────────────
const boundary_vel_frag = `
  precision highp float;
  uniform sampler2D velocity;
  uniform vec2 px;
  varying vec2 uv;
  void main(){
    vec2 n = sign(uv - 0.5);
    vec2 offset = n * px;
    vec2 vel = texture2D(velocity, uv - offset).xy;
    if(abs(n.x) > 0.5) vel.x *= -1.0;
    if(abs(n.y) > 0.5) vel.y *= -1.0;
    gl_FragColor = vec4(vel, 0.0, 1.0);
  }
`;
// ─── 边界处理片元着色器:压力一致 ──────────────────────────────────────────
const boundary_pres_frag = `
  precision highp float;
  uniform sampler2D pressure;
  uniform vec2 px;
  varying vec2 uv;
  void main(){
    vec2 n = sign(uv - 0.5);
    vec2 offset = n * px;
    float p = texture2D(pressure, uv - offset).r;
    gl_FragColor = vec4(p, 0.0, 0.0, 1.0);
  }
`;
class LiquidEtherBackgroundComponent {
    constructor(ngZone) {
        this.ngZone = ngZone;
        /** 背景颜色 */
        this.ncBgColor = 'black';
        /** 颜色数组,用于映射流体速度场的渲染颜色 */
        this.ncColors = ['#5227FF', '#FF9FFC', '#B19EEF'];
        /** 鼠标拖动产生的流体力度(0-60) */
        this.ncMouseForce = 20;
        /** 鼠标影响半径(单位:像素 10-300) */
        this.ncCursorSize = 100;
        /** 是否启用粘性模拟(启用后运动更平滑、更厚重) */
        this._isViscous = false;
        /** 粘性系数(仅在 ncIsViscous 为 true 时生效 1-100) */
        this.ncViscous = 30;
        /** 粘性扩散的迭代次数(仅在ncIsViscous为true时生效 1-64,次数越多,迭代越平滑,速度越慢)) */
        this.ncIterationsViscous = 32;
        /** 强制不可压缩性所需的压力泊松迭代次数(2-64) */
        this.ncIterationsPoisson = 32;
        /** 在对流/扩散过程中使用固定的模拟时间步长,数值越小越精确但性能开销更高 */
        this.ncDt = 0.014;
        /** 启用BFECC平流(误差补偿)可获得更清晰的流场;禁用可略微提高性能 */
        this._bfecc = true;
        /** 模拟纹理相对于画布大小的比例(0~1,越小性能越好,模糊程度越高) */
        this.ncResolution = 0.5;
        /** 是否开启边界反弹模式(流体在边界处反弹而非穿透) */
        this._isBounce = false;
        /** 是否开启自动演示模式(无用户操作时自动驱动流体运动) */
        this._autoDemo = true;
        /** 自动指针运动速度(标准化单位/秒,0-1) */
        this.ncAutoSpeed = 0.5;
        /** 在自动模式下,对速度增量应用乘数(0-4) */
        this.ncAutoIntensity = 2.2;
        /** 用户移动鼠标时,从自动指针到实际光标的插值时间(秒) */
        this.ncTakeoverDuration = 0.25;
        /** 自动模式恢复前,短暂的无操作时间(毫秒) */
        this.ncAutoResumeDelay = 1000;
        /** 激活后,自动移动速度从0加速到全速所需的时间(秒) */
        this.ncAutoRampDuration = 0.6;
        this.webgl = null;
        this.rafId = null;
        this.resizeRafId = null;
        this.isVisible = true;
    }
    set ncIsViscous(val) {
        this._isViscous = val !== null && val !== undefined && val !== false && val !== 'false';
    }
    get ncIsViscous() {
        return this._isViscous;
    }
    set ncBFECC(val) {
        this._bfecc = val !== null && val !== undefined && val !== false && val !== 'false';
    }
    get ncBFECC() {
        return this._bfecc;
    }
    set ncIsBounce(val) {
        this._isBounce = val !== null && val !== undefined && val !== false && val !== 'false';
    }
    get ncIsBounce() {
        return this._isBounce;
    }
    set ncAutoDemo(val) {
        this._autoDemo = val !== null && val !== undefined && val !== false && val !== 'false';
    }
    get ncAutoDemo() {
        return this._autoDemo;
    }
    ngOnInit() { }
    ngAfterViewInit() {
        this.ngZone.runOutsideAngular(() => {
            this.initWebGL();
        });
    }
    ngOnDestroy() {
        this.cleanup();
    }
    ngOnChanges(changes) {
        if (!this.webgl)
            return;
        // ncColors 变化需要重建调色板纹理,整体重新初始化
        if (changes['ncColors']) {
            this.cleanup();
            this.initWebGL();
            return;
        }
        // 其余参数变化时,直接写入 simulation.options
        this.applyOptions();
    }
    // ─── 初始化入口 ──────────────────────────────────────────────────────────
    initWebGL() {
        const container = this.containerRef.nativeElement;
        this.webgl = this.createWebGLManager(container);
        this.webgl.start();
        this.setupResizeObserver(container);
        this.setupIntersectionObserver(container);
    }
    // ─── 构建调色板纹理 ───────────────────────────────────────────────────────
    makePaletteTexture(stops) {
        let arr;
        if (Array.isArray(stops) && stops.length > 0) {
            arr = stops.length === 1 ? [stops[0], stops[0]] : stops;
        }
        else {
            arr = ['#ffffff', '#ffffff'];
        }
        const w = arr.length;
        const data = new Uint8Array(w * 4);
        for (let i = 0; i < w; i++) {
            const c = new THREE.Color(arr[i]);
            data[i * 4 + 0] = Math.round(c.r * 255);
            data[i * 4 + 1] = Math.round(c.g * 255);
            data[i * 4 + 2] = Math.round(c.b * 255);
            data[i * 4 + 3] = 255;
        }
        const tex = new THREE.DataTexture(data, w, 1, THREE.RGBAFormat);
        tex.magFilter = THREE.LinearFilter;
        tex.minFilter = THREE.LinearFilter;
        tex.wrapS = THREE.ClampToEdgeWrapping;
        tex.wrapT = THREE.ClampToEdgeWrapping;
        tex.generateMipmaps = false;
        tex.needsUpdate = true;
        return tex;
    }
    // ─── 创建 WebGL 管理器(包含所有仿真子类) ──────────────────────────────
    createWebGLManager(container) {
        const self = this;
        const paletteTex = this.makePaletteTexture(this.ncColors);
        const bgVec4 = new THREE.Vector4(0, 0, 0, 0); // 始终透明背景
        // ── Common:WebGL 渲染器与时钟 ──────────────────────────────────────
        class CommonClass {
            constructor() {
                this.width = 0;
                this.height = 0;
                this.aspect = 1;
                this.pixelRatio = 1;
                this.fboWidth = null;
                this.fboHeight = null;
                this.time = 0;
                this.delta = 0;
                this.container = null;
                this.renderer = null;
                this.clock = null;
            }
            init(c) {
                this.container = c;
                this.pixelRatio = Math.min(window.devicePixelRatio || 1, 2);
                this.resize();
                this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
                this.renderer.autoClear = false;
                this.renderer.setClearColor(new THREE.Color(0x000000), 0);
                this.renderer.setPixelRatio(this.pixelRatio);
                this.renderer.setSize(this.width, this.height);
                this.renderer.domElement.style.width = '100%';
                this.renderer.domElement.style.height = '100%';
                this.renderer.domElement.style.display = 'block';
                this.clock = new THREE.Clock();
                this.clock.start();
            }
            resize() {
                if (!this.container)
                    return;
                const rect = this.container.getBoundingClientRect();
                this.width = Math.max(1, Math.floor(rect.width));
                this.height = Math.max(1, Math.floor(rect.height));
                this.aspect = this.width / this.height;
                if (this.renderer)
                    this.renderer.setSize(this.width, this.height, false);
            }
            update() {
                this.delta = this.clock.getDelta();
                this.time += this.delta;
            }
        }
        const Common = new CommonClass();
        // ── Mouse:鼠标与触控事件 + 自动演示平滑过渡 ──────────────────────
        class MouseClass {
            constructor() {
                this.mouseMoved = false;
                this.coords = new THREE.Vector2();
                this.coords_old = new THREE.Vector2();
                this.diff = new THREE.Vector2();
                this.timer = null;
                this.container = null;
                this.docTarget = null;
                this.listenerTarget = null;
                this.isHoverInside = false;
                this.hasUserControl = false;
                this.isAutoActive = false;
                this.autoIntensity = 2.0;
                this.takeoverActive = false;
                this.takeoverStartTime = 0;
                this.takeoverDuration = 0.25;
                this.takeoverFrom = new THREE.Vector2();
                this.takeoverTo = new THREE.Vector2();
                this.onInteract = null;
            }
            init(c) {
                this.container = c;
            }
            dispose() {
                this.container = null;
            }
            isPointInside(clientX, clientY) {
                if (!this.container)
                    return false;
                const rect = this.container.getBoundingClientRect();
                if (rect.width === 0 || rect.height === 0)
                    return false;
                return clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom;
            }
            updateHoverState(clientX, clientY) {
                this.isHoverInside = this.isPointInside(clientX, clientY);
                return this.isHoverInside;
            }
            setCoords(x, y) {
                if (!this.container)
                    return;
                if (this.timer)
                    window.clearTimeout(this.timer);
                const rect = this.container.getBoundingClientRect();
                if (rect.width === 0 || rect.height === 0)
                    return;
                const nx = (x - rect.left) / rect.width;
                const ny = (y - rect.top) / rect.height;
                this.coords.set(nx * 2 - 1, -(ny * 2 - 1));
                this.mouseMoved = true;
                this.timer = window.setTimeout(() => { this.mouseMoved = false; }, 100);
            }
            setNormalized(nx, ny) {
                this.coords.set(nx, ny);
                this.mouseMoved = true;
            }
            onMouseMove(event) {
                if (!this.updateHoverState(event.clientX, event.clientY))
                    return;
                if (this.onInteract)
                    this.onInteract();
                if (this.isAutoActive && !this.hasUserControl && !this.takeoverActive) {
                    if (!this.container)
                        return;
                    const rect = this.container.getBoundingClientRect();
                    if (rect.width === 0 || rect.height === 0)
                        return;
                    const nx = (event.clientX - rect.left) / rect.width;
                    const ny = (event.clientY - rect.top) / rect.height;
                    this.takeoverFrom.copy(this.coords);
                    this.takeoverTo.set(nx * 2 - 1, -(ny * 2 - 1));
                    this.takeoverStartTime = performance.now();
                    this.takeoverActive = true;
                    this.hasUserControl = true;
                    this.isAutoActive = false;
                    return;
                }
                this.setCoords(event.clientX, event.clientY);
                this.hasUserControl = true;
            }
            onTouchStart(event) {
                if (event.touches.length !== 1)
                    return;
                const t = event.touches[0];
                if (!this.updateHoverState(t.clientX, t.clientY))
                    return;
                if (this.onInteract)
                    this.onInteract();
                this.setCoords(t.clientX, t.clientY);
                this.hasUserControl = true;
            }
            onTouchMove(event) {
                if (event.touches.length !== 1)
                    return;
                const t = event.touches[0];
                if (!this.updateHoverState(t.clientX, t.clientY))
                    return;
                if (this.onInteract)
                    this.onInteract();
                this.setCoords(t.clientX, t.clientY);
            }
            onTouchEnd() { this.isHoverInside = false; }
            onMouseLeave() { this.isHoverInside = false; }
            update() {
                if (this.takeoverActive) {
                    const t = (performance.now() - this.takeoverStartTime) / (this.takeoverDuration * 1000);
                    if (t >= 1) {
                        this.takeoverActive = false;
                        this.coords.copy(this.takeoverTo);
                        this.coords_old.copy(this.coords);
                        this.diff.set(0, 0);
                    }
                    else {
                        const k = t * t * (3 - 2 * t);
                        this.coords.copy(this.takeoverFrom).lerp(this.takeoverTo, k);
                    }
                }
                this.diff.subVectors(this.coords, this.coords_old);
                this.coords_old.copy(this.coords);
                if (this.coords_old.x === 0 && this.coords_old.y === 0)
                    this.diff.set(0, 0);
                if (this.isAutoActive && !this.takeoverActive)
                    this.diff.multiplyScalar(this.autoIntensity);
            }
        }
        const Mouse = new MouseClass();
        // ── AutoDriver:无人操作时自动漫游 ─────────────────────────────────
        class AutoDriver {
            constructor(mouse, manager, opts) {
                this.active = false;
                this.current = new THREE.Vector2(0, 0);
                this.target = new THREE.Vector2();
                this.lastTime = performance.now();
                this.activationTime = 0;
                this.margin = 0.2;
                this._tmpDir = new THREE.Vector2();
                this.mouse = mouse;
                this.manager = manager;
                this.enabled = opts.enabled;
                this.speed = opts.speed;
                this.resumeDelay = opts.resumeDelay || 3000;
                this.rampDurationMs = (opts.rampDuration || 0) * 1000;
                this.pickNewTarget();
            }
            pickNewTarget() {
                const r = Math.random;
                this.target.set((r() * 2 - 1) * (1 - this.margin), (r() * 2 - 1) * (1 - this.margin));
            }
            forceStop() {
                this.active = false;
                this.mouse.isAutoActive = false;
            }
            update() {
                if (!this.enabled)
                    return;
                const now = performance.now();
                const idle = now - this.manager.lastUserInteraction;
                if (idle < this.resumeDelay) {
                    if (this.active)
                        this.forceStop();
                    return;
                }
                if (this.mouse.isHoverInside) {
                    if (this.active)
                        this.forceStop();
                    return;
                }
                if (!this.active) {
                    this.active = true;
                    this.current.copy(this.mouse.coords);
                    this.lastTime = now;
                    this.activationTime = now;
                }
                this.mouse.isAutoActive = true;
                let dtSec = (now - this.lastTime) / 1000;
                this.lastTime = now;
                if (dtSec > 0.2)
                    dtSec = 0.016;
                const dir = this._tmpDir.subVectors(this.target, this.current);
                const dist = dir.length();
                if (dist < 0.01) {
                    this.pickNewTarget();
                    return;
                }
                dir.normalize();
                let ramp = 1;
                if (this.rampDurationMs > 0) {
                    const t = Math.min(1, (now - this.activationTime) / this.rampDurationMs);
                    ramp = t * t * (3 - 2 * t);
                }
                const step = this.speed * dtSec * ramp;
                const move = Math.min(step, dist);
                this.current.addScaledVector(dir, move);
                this.mouse.setNormalized(this.current.x, this.current.y);
            }
        }
        // ── ShaderPass:通用着色器渲染通道基类 ────────────────────────────
        class ShaderPass {
            constructor(props) {
                var _a;
                this.material = null;
                this.geometry = null;
                this.plane = null;
                this.props = props || {};
                this.uniforms = (_a = this.props.material) === null || _a === void 0 ? void 0 : _a.uniforms;
            }
            init() {
                this.scene = new THREE.Scene();
                this.camera = new THREE.Camera();
                if (this.uniforms) {
                    this.material = new THREE.RawShaderMaterial(this.props.material);
                    this.geometry = new THREE.PlaneGeometry(2.0, 2.0);
                    this.plane = new THREE.Mesh(this.geometry, this.material);
                    this.scene.add(this.plane);
                }
            }
            update(props) {
                Common.renderer.setRenderTarget(this.props.output || null);
                Common.renderer.render(this.scene, this.camera);
                Common.renderer.setRenderTarget(null);
            }
        }
        // ── Advection:速度场平流(含边界反弹线段) ────────────────────────
        class Advection extends ShaderPass {
            constructor(simProps) {
                super({
                    material: {
                        vertexShader: face_vert,
                        fragmentShader: advection_frag,
                        uniforms: {
                            boundarySpace: { value: simProps.cellScale },
                            px: { value: simProps.cellScale },
                            fboSize: { value: simProps.fboSize },
                            velocity: { value: simProps.src.texture },
                            dt: { value: simProps.dt },
                            isBFECC: { value: true }
                        }
                    },
                    output: simProps.dst
                });
                this.uniforms = this.props.material.uniforms;
                this.init();
            }
            init() {
                super.init();
                const boundaryG = new THREE.BufferGeometry();
                const verts = new Float32Array([-1, -1, 0, -1, 1, 0, -1, 1, 0, 1, 1, 0, 1, 1, 0, 1, -1, 0, 1, -1, 0, -1, -1, 0]);
                boundaryG.setAttribute('position', new THREE.BufferAttribute(verts, 3));
                const boundaryM = new THREE.RawShaderMaterial({
                    vertexShader: line_vert,
                    fragmentShader: boundary_vel_frag,
                    uniforms: this.uniforms
                });
                this.line = new THREE.LineSegments(boundaryG, boundaryM);
                this.scene.add(this.line);
            }
            update({ dt, isBounce, BFECC }) {
                this.uniforms.dt.value = dt;
                this.line.visible = isBounce;
                this.uniforms.isBFECC.value = BFECC;
                super.update();
            }
        }
        // ── ExternalForce:鼠标施力 ────────────────────────────────────────
        class ExternalForce extends ShaderPass {
            constructor(simProps) {
                super({ output: simProps.dst });
                this.initForce(simProps);
            }
            initForce(simProps) {
                super.init();
                const mouseG = new THREE.PlaneGeometry(1, 1);
                const mouseM = new THREE.RawShaderMaterial({
                    vertexShader: mouse_vert,
                    fragmentShader: externalForce_frag,
                    blending: THREE.AdditiveBlending,
                    depthWrite: false,
                    uniforms: {
                        px: { value: simProps.cellScale },
                        force: { value: new THREE.Vector2(0, 0) },
                        center: { value: new THREE.Vector2(0, 0) },
                        scale: { value: new THREE.Vector2(simProps.cursor_size, simProps.cursor_size) }
                    }
                });
                this.mouse = new THREE.Mesh(mouseG, mouseM);
                this.scene.add(this.mouse);
            }
            update(props) {
                const forceX = (Mouse.diff.x / 2) * props.mouse_force;
                const forceY = (Mouse.diff.y / 2) * props.mouse_force;
                const cursorSizeX = props.cursor_size * props.cellScale.x;
                const cursorSizeY = props.cursor_size * props.cellScale.y;
                const centerX = Math.min(Math.max(Mouse.coords.x, -1 + cursorSizeX + props.cellScale.x * 2), 1 - cursorSizeX - props.cellScale.x * 2);
                const centerY = Math.min(Math.max(Mouse.coords.y, -1 + cursorSizeY + props.cellScale.y * 2), 1 - cursorSizeY - props.cellScale.y * 2);
                const u = this.mouse.material.uniforms;
                u.force.value.set(forceX, forceY);
                u.center.value.set(centerX, centerY);
                u.scale.value.set(props.cursor_size, props.cursor_size);
                super.update();
            }
        }
        // ── Viscous:粘性扩散(雅可比迭代) ──────────────────────────────
        class Viscous extends ShaderPass {
            constructor(simProps) {
                super({
                    material: {
                        vertexShader: face_vert,
                        fragmentShader: viscous_frag,
                        uniforms: {
                            boundarySpace: { value: simProps.boundarySpace },
                            velocity: { value: simProps.src.texture },
                            velocity_new: { value: simProps.dst_.texture },
                            v: { value: simProps.viscous },
                            px: { value: simProps.cellScale },
                            dt: { value: simProps.dt }
                        }
                    },
                    output: simProps.dst,
                    output0: simProps.dst_,
                    output1: simProps.dst
                });
                this.init();
            }
            init() {
                super.init();
                const boundaryG = new THREE.BufferGeometry();
                const verts = new Float32Array([-1, -1, 0, -1, 1, 0, -1, 1, 0, 1, 1, 0, 1, 1, 0, 1, -1, 0, 1, -1, 0, -1, -1, 0]);
                boundaryG.setAttribute('position', new THREE.BufferAttribute(verts, 3));
                const boundaryM = new THREE.RawShaderMaterial({
                    vertexShader: line_vert,
                    fragmentShader: boundary_vel_frag,
                    uniforms: this.uniforms
                });
                this.line = new THREE.LineSegments(boundaryG, boundaryM);
                this.scene.add(this.line);
            }
            update({ viscous, iterations, dt, isBounce }) {
                let fbo_in, fbo_out;
                this.uniforms.v.value = viscous;
                this.line.visible = isBounce;
                for (let i = 0; i < iterations; i++) {
                    if (i % 2 === 0) {
                        fbo_in = this.props.output0;
                        fbo_out = this.props.output1;
                    }
                    else {
                        fbo_in = this.props.output1;
                        fbo_out = this.props.output0;
                    }
                    this.uniforms.velocity_new.value = fbo_in.texture;
                    this.props.output = fbo_out;
                    this.uniforms.dt.value = dt;
                    super.update();
                }
                return fbo_out;
            }
        }
        // ── Divergence:散度计算 ──────────────────────────────────────────
        class Divergence extends ShaderPass {
            constructor(simProps) {
                super({
                    material: {
                        vertexShader: face_vert,
                        fragmentShader: divergence_frag,
                        uniforms: {
                            boundarySpace: { value: simProps.boundarySpace },
                            velocity: { value: simProps.src.texture },
                            px: { value: simProps.cellScale },
                            dt: { value: simProps.dt }
                        }
                    },
                    output: simProps.dst
                });
                this.init();
            }
            update({ vel }) {
                this.uniforms.velocity.value = vel.texture;
                super.update();
            }
        }
        // ── Poisson:压力求解(雅可比迭代) ──────────────────────────────
        class Poisson extends ShaderPass {
            constructor(simProps) {
                super({
                    material: {
                        vertexShader: face_vert,
                        fragmentShader: poisson_frag,
                        uniforms: {
                            boundarySpace: { value: simProps.boundarySpace },
                            pressure: { value: simProps.dst_.texture },
                            divergence: { value: simProps.src.texture },
                            px: { value: simProps.cellScale }
                        }
                    },
                    output: simProps.dst,
                    output0: simProps.dst_,
                    output1: simProps.dst
                });
                this.init();
            }
            init() {
                super.init();
                const boundaryG = new THREE.BufferGeometry();
                const verts = new Float32Array([-1, -1, 0, -1, 1, 0, -1, 1, 0, 1, 1, 0, 1, 1, 0, 1, -1, 0, 1, -1, 0, -1, -1, 0]);
                boundaryG.setAttribute('position', new THREE.BufferAttribute(verts, 3));
                const boundaryM = new THREE.RawShaderMaterial({
                    vertexShader: line_vert,
                    fragmentShader: boundary_pres_frag,
                    uniforms: this.uniforms
                });
                this.line = new THREE.LineSegments(boundaryG, boundaryM);
                this.scene.add(this.line);
            }
            update({ iterations, isBounce }) {
                let p_in, p_out;
                this.line.visible = isBounce;
                for (let i = 0; i < iterations; i++) {
                    if (i % 2 === 0) {
                        p_in = this.props.output0;
                        p_out = this.props.output1;
                    }
                    else {
                        p_in = this.props.output1;
                        p_out = this.props.output0;
                    }
                    this.uniforms.pressure.value = p_in.texture;
                    this.props.output = p_out;
                    super.update();
                }
                return p_out;
            }
        }
        // ── Pressure:压力梯度修正 ────────────────────────────────────────
        class Pressure extends ShaderPass {
            constructor(simProps) {
                super({
                    material: {
                        vertexShader: face_vert,
                        fragmentShader: pressure_frag,
                        uniforms: {
                            boundarySpace: { value: simProps.boundarySpace },
                            pressure: { value: simProps.src_p.texture },
                            velocity: { value: simProps.src_v.texture },
                            px: { value: simProps.cellScale },
                            dt: { value: simProps.dt }
                        }
                    },
                    output: simProps.dst
                });
                this.init();
            }
            init() {
                super.init();
                const boundaryG = new THREE.BufferGeometry();
                const verts = new Float32Array([-1, -1, 0, -1, 1, 0, -1, 1, 0, 1, 1, 0, 1, 1, 0, 1, -1, 0, 1, -1, 0, -1, -1, 0]);
                boundaryG.setAttribute('position', new THREE.BufferAttribute(verts, 3));
                const boundaryM = new THREE.RawShaderMaterial({
                    vertexShader: line_vert,
                    fragmentShader: boundary_vel_frag,
                    uniforms: this.uniforms
                });
                this.line = new THREE.LineSegments(boundaryG, boundaryM);
                this.scene.add(this.line);
            }
            update({ vel, pressure, isBounce }) {
                this.uniforms.velocity.value = vel.texture;
                this.uniforms.pressure.value = pressure.texture;
                this.line.visible = isBounce;
                super.update();
            }
        }
        // ── Simulation:整合流体仿真管线 ─────────────────────────────────
        class Simulation {
            constructor(options) {
                this.fboSize = new THREE.Vector2();
                this.cellScale = new THREE.Vector2();
                this.boundarySpace = new THREE.Vector2();
                this.options = Object.assign({ iterations_poisson: 32, iterations_viscous: 32, mouse_force: 20, resolution: 0.5, cursor_size: 100, viscous: 30, isBounce: false, dt: 0.014, isViscous: false, BFECC: true }, (options || {}));
                this.fbos = { vel_0: null, vel_1: null, vel_viscous0: null, vel_viscous1: null, div: null, pressure_0: null, pressure_1: null };
                this.init();
            }
            init() {
                this.calcSize();
                this.createAllFBO();
                this.createShaderPass();
            }
            getFloatType() {
                const isIOS = /(iPad|iPhone|iPod)/i.test(navigator.userAgent);
                return isIOS ? THREE.HalfFloatType : THREE.FloatType;
            }
            createAllFBO() {
                const type = this.getFloatType();
                const opts = {
                    type, depthBuffer: false, stencilBuffer: false,
                    minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter,
                    wrapS: THREE.ClampToEdgeWrapping, wrapT: THREE.ClampToEdgeWrapping
                };
                for (const key in this.fbos) {
                    this.fbos[key] = new THREE.WebGLRenderTarget(this.fboSize.x, this.fboSize.y, opts);
                }
            }
            createShaderPass() {
                this.advection = new Advection({
                    cellScale: this.cellScale, fboSize: this.fboSize,
                    dt: this.options.dt, src: this.fbos.vel_0, dst: this.fbos.vel_1
                });
                this.externalForce = new ExternalForce({
                    cellScale: this.cellScale, cursor_size: this.options.cursor_size, dst: this.fbos.vel_1
                });
                this.viscous = new Viscous({
                    cellScale: this.cellScale, boundarySpace: this.boundarySpace,
                    viscous: this.options.viscous, src: this.fbos.vel_1,
                    dst: this.fbos.vel_viscous1, dst_: this.fbos.vel_viscous0, dt: this.options.dt
                });
                this.divergence = new Divergence({
                    cellScale: this.cellScale, boundarySpace: this.boundarySpace,
                    src: this.fbos.vel_viscous0, dst: this.fbos.div, dt: this.options.dt
                });
                this.poisson = new Poisson({
                    cellScale: this.cellScale, boundarySpace: this.boundarySpace,
                    src: this.fbos.div, dst: this.fbos.pressure_1, dst_: this.fbos.pressure_0
                });
                this.pressure = new Pressure({
                    cellScale: this.cellScale, boundarySpace: this.boundarySpace,
                    src_p: this.fbos.pressure_0, src_v: this.fbos.vel_viscous0,
                    dst: this.fbos.vel_0, dt: this.options.dt
                });
            }
            calcSize() {
                const width = Math.max(1, Math.round(this.options.resolution * Common.width));
                const height = Math.max(1, Math.round(this.options.resolution * Common.height));
                this.cellScale.set(1.0 / width, 1.0 / height);
                this.fboSize.set(width, height);
            }
            resize() {
                this.calcSize();
                for (const key in this.fbos) {
                    this.fbos[key].setSize(this.fboSize.x, this.fboSize.y);
                }
            }
            update() {
                if (this.options.isBounce)
                    this.boundarySpace.set(0, 0);
                else
                    this.boundarySpace.copy(this.cellScale);
                this.advection.update({ dt: this.options.dt, isBounce: this.options.isBounce, BFECC: this.options.BFECC });
                this.externalForce.update({ cursor_size: this.options.cursor_size, mouse_force: this.options.mouse_force, cellScale: this.cellScale });
                let vel = this.fbos.vel_1;
                if (this.options.isViscous) {
                    vel = this.viscous.update({ viscous: this.options.viscous, iterations: this.options.iterations_viscous, dt: this.options.dt, isBounce: this.options.isBounce });
                }
                this.divergence.update({ vel });
                const pressure = this.poisson.update({ iterations: this.options.iterations_poisson, isBounce: this.options.isBounce });
                this.pressure.update({ vel, pressure, isBounce: this.options.isBounce });
            }
        }
        // ── Output:最终颜色输出场景 ──────────────────────────────────────
        class Output {
            constructor() { this.init(); }
            init() {
                this.simulation = new Simulation();
                this.scene = new THREE.Scene();
                this.camera = new THREE.Camera();
                this.output = new THREE.Mesh(new THREE.PlaneGeometry(2, 2), new THREE.RawShaderMaterial({
                    vertexShader: face_vert,
                    fragmentShader: color_frag,
                    transparent: true,
                    depthWrite: false,
                    uniforms: {
                        velocity: { value: this.simulation.fbos.vel_0.texture },
                        boundarySpace: { value: new THREE.Vector2() },
                        palette: { value: paletteTex },
                        bgColor: { value: bgVec4 }
                    }
                }));
                this.scene.add(this.output);
            }
            resize() { this.simulation.resize(); }
            render() {
                Common.renderer.setRenderTarget(null);
                Common.renderer.render(this.scene, this.camera);
            }
            update() { this.simulation.update(); this.render(); }
        }
        // ── WebGLManager:顶层管理器,驱动动画循环 ───────────────────────
        class WebGLManager {
            constructor(props) {
                this.lastUserInteraction = performance.now();
                this.running = false;
                this.props = props;
                Common.init(props.$wrapper);
                this.mouse = Mouse;
                this.mouse.init(props.$wrapper);
                Mouse.autoIntensity = props.autoIntensity;
                Mouse.takeoverDuration = props.takeoverDuration;
                Mouse.onInteract = () => {
                    this.lastUserInteraction = performance.now();
                    if (this.autoDriver)
                        this.autoDriver.forceStop();
                };
                this.autoDriver = new AutoDriver(Mouse, this, {
                    enabled: props.autoDemo,
                    speed: props.autoSpeed,
                    resumeDelay: props.autoResumeDelay,
                    rampDuration: props.autoRampDuration
                });
                this.init();
                this._loop = this.loop.bind(this);
                this._resize = this.resize.bind(this);
                this._onVisibility = () => {
                    if (document.hidden) {
                        this.pause();
                    }
                    else if (self.isVisible) {
                        self.ngZone.runOutsideAngular(() => {
                            this.start();
                        });
                    }
                };
                window.addEventListener('resize', this._resize);
                document.addEventListener('visibilitychange', this._onVisibility);
            }
            init() {
                this.props.$wrapper.prepend(Common.renderer.domElement);
                this.output = new Output();
            }
            resize() {
                Common.resize();
                this.output.resize();
            }
            render() {
                if (this.autoDriver)
                    this.autoDriver.update();
                Mouse.update();
                Common.update();
                this.output.update();
            }
            loop() {
                if (!this.running)
                    return;
                this.render();
                self.rafId = requestAnimationFrame(this._loop);
            }
            start() {
                if (this.running)
                    return;
                this.running = true;
                this._loop();
            }
            pause() {
                this.running = false;
                if (self.rafId !== null) {
                    cancelAnimationFrame(self.rafId);
                    self.rafId = null;
                }
            }
            dispose() {
                try {
                    window.removeEventListener('resize', this._resize);
                    document.removeEventListener('visibilitychange', this._onVisibility);
                    this.mouse.dispose();
                    if (Common.renderer) {
                        const canvas = Common.renderer.domElement;
                        if (canvas && canvas.parentNode)
                            canvas.parentNode.removeChild(canvas);
                        Common.renderer.dispose();
                    }
                }
                catch (e) {
                    void 0;
                }
            }
        }
        // ─── 实例化并配置 ────────────────────────────────────────────────
        const webgl = new WebGLManager({
            $wrapper: container,
            autoDemo: self.ncAutoDemo,
            autoSpeed: self.ncAutoSpeed,
            autoIntensity: self.ncAutoIntensity,
            takeoverDuration: self.ncTakeoverDuration,
            autoResumeDelay: self.ncAutoResumeDelay,
            autoRampDuration: self.ncAutoRampDuration
        });
        this.applyOptionsToSimulation(webgl.output.simulation);
        return webgl;
    }
    // ─── 将 @Input 参数写入 simulation.options ───────────────────────────────
    applyOptions() {
        var _a, _b;
        if (!((_b = (_a = this.webgl) === null || _a === void 0 ? void 0 : _a.output) === null || _b === void 0 ? void 0 : _b.simulation))
            return;
        this.applyOptionsToSimulation(this.webgl.output.simulation);
    }
    applyOptionsToSimulation(sim) {
        var _a;
        const prevRes = sim.options.resolution;
        Object.assign(sim.options, {
            mouse_force: this.ncMouseForce,
            cursor_size: this.ncCursorSize,
            isViscous: this.ncIsViscous,
            viscous: this.ncViscous,
            iterations_viscous: this.ncIterationsViscous,
            iterations_poisson: this.ncIterationsPoisson,
            dt: this.ncDt,
            BFECC: this.ncBFECC,
            resolution: this.ncResolution,
            isBounce: this.ncIsBounce
        });
        if (this.ncResolution !== prevRes) {
            sim.resize();
        }
        // 同步 autoDriver 参数
        if ((_a = this.webgl) === null || _a === void 0 ? void 0 : _a.autoDriver) {
            this.webgl.autoDriver.enabled = this.ncAutoDemo;
            this.webgl.autoDriver.speed = this.ncAutoSpeed;
            this.webgl.autoDriver.resumeDelay = this.ncAutoResumeDelay;
            this.webgl.autoDriver.rampDurationMs = this.ncAutoRampDuration * 1000;
            if (this.webgl.autoDriver.mouse) {
                this.webgl.autoDriver.mouse.autoIntensity = this.ncAutoIntensity;
                this.webgl.autoDriver.mouse.takeoverDuration = this.ncTakeoverDuration;
            }
        }
    }
    // ─── ResizeObserver:容器尺寸变化时重新计算 ──────────────────────────────
    setupResizeObserver(container) {
        this.resizeObserver = new ResizeObserver(() => {
            if (!this.webgl)
                return;
            if (this.resizeRafId !== null)
                cancelAnimationFrame(this.resizeRafId);
            this.ngZone.runOutsideAngular(() => {
                this.resizeRafId = requestAnimationFrame(() => {
                    if (!this.webgl)
                        return;
                    this.webgl.resize();
                    this.resizeRafId = null;
                });
            });
        });
        this.resizeObserver.observe(container);
    }
    // ─── IntersectionObserver:不可见时暂停渲染以节省性能 ────────────────────
    setupIntersectionObserver(container) {
        this.intersectionObserver = new IntersectionObserver(entries => {
            const entry = entries[0];
            this.isVisible = entry.isIntersecting && entry.intersectionRatio > 0;
            if (!this.webgl)
                return;
            if (this.isVisible && !document.hidden) {
                this.ngZone.runOutsideAngular(() => {
                    this.webgl.start();
                });
            }
            else {
                this.webgl.pause();
            }
        }, { threshold: [0, 0.01, 0.1] });
        this.intersectionObserver.observe(container);
    }
    // ─── 清理资源 ─────────────────────────────────────────────────────────────
    cleanup() {
        var _a, _b;
        if (this.rafId !== null) {
            cancelAnimationFrame(this.rafId);
            this.rafId = null;
        }
        if (this.resizeRafId !== null) {
            cancelAnimationFrame(this.resizeRafId);
            this.resizeRafId = null;
        }
        try {
            (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
        }
        catch (e) {
            void 0;
        }
        try {
            (_b = this.intersectionObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
        }
        catch (e) {
            void 0;
        }
        if (this.webgl) {
            this.webgl.dispose();
            this.webgl = null;
        }
    }
    // ─── HostListeners for Mouse/Touch Interaction ──────────────────────────
    onMouseMove(event) {
        var _a, _b;
        (_b = (_a = this.webgl) === null || _a === void 0 ? void 0 : _a.mouse) === null || _b === void 0 ? void 0 : _b.onMouseMove(event);
    }
    onTouchStart(event) {
        var _a, _b;
        (_b = (_a = this.webgl) === null || _a === void 0 ? void 0 : _a.mouse) === null || _b === void 0 ? void 0 : _b.onTouchStart(event);
    }
    onTouchMove(event) {
        var _a, _b;
        (_b = (_a = this.webgl) === null || _a === void 0 ? void 0 : _a.mouse) === null || _b === void 0 ? void 0 : _b.onTouchMove(event);
    }
    onTouchEnd() {
        var _a, _b;
        (_b = (_a = this.webgl) === null || _a === void 0 ? void 0 : _a.mouse) === null || _b === void 0 ? void 0 : _b.onTouchEnd();
    }
    onMouseLeave() {
        var _a, _b;
        (_b = (_a = this.webgl) === null || _a === void 0 ? void 0 : _a.mouse) === null || _b === void 0 ? void 0 : _b.onMouseLeave();
    }
}
LiquidEtherBackgroundComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: LiquidEtherBackgroundComponent, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
LiquidEtherBackgroundComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.1.5", type: LiquidEtherBackgroundComponent, selector: "nc-liquid-ether-background", inputs: { ncBgColor: "ncBgColor", ncColors: "ncColors", ncMouseForce: "ncMouseForce", ncCursorSize: "ncCursorSize", ncIsViscous: "ncIsViscous", ncViscous: "ncViscous", ncIterationsViscous: "ncIterationsViscous", ncIterationsPoisson: "ncIterationsPoisson", ncDt: "ncDt", ncBFECC: "ncBFECC", ncResolution: "ncResolution", ncIsBounce: "ncIsBounce", ncAutoDemo: "ncAutoDemo", ncAutoSpeed: "ncAutoSpeed", ncAutoIntensity: "ncAutoIntensity", ncTakeoverDuration: "ncTakeoverDuration", ncAutoResumeDelay: "ncAutoResumeDelay", ncAutoRampDuration: "ncAutoRampDuration" }, host: { listeners: { "mousemove": "onMouseMove($event)", "touchstart": "onTouchStart($event)", "touchmove": "onTouchMove($event)", "touchend": "onTouchEnd()", "mouseleave": "onMouseLeave()" } }, viewQueries: [{ propertyName: "containerRef", first: true, predicate: ["container"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<div #container class=\"nc-liquid-ether-canvas-container\" [style.background-color]=\"ncBgColor\"></div>\r\n<div class=\"nc-content-wrapper\">\r\n    <ng-content></ng-content>\r\n</div>", styles: [":host{display:block;position:relative;width:100%;height:100%;overflow:hidden}.nc-liquid-ether-canvas-container{position:absolute;inset:0;z-index:0}.nc-content-wrapper{position:relative;z-index:1;width:100%;height:100%}\n"] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: LiquidEtherBackgroundComponent, decorators: [{
            type: Component,
            args: [{
                    selector: 'nc-liquid-ether-background',
                    templateUrl: './liquid-ether-background.component.html',
                    styleUrls: ['./liquid-ether-background.component.less']
                }]
        }], ctorParameters: function () { return [{ type: i0.NgZone }]; }, propDecorators: { containerRef: [{
                type: ViewChild,
                args: ['container', { static: true }]
            }], ncBgColor: [{
                type: Input
            }], ncColors: [{
                type: Input
            }], ncMouseForce: [{
                type: Input
            }], ncCursorSize: [{
                type: Input
            }], ncIsViscous: [{
                type: Input
            }], ncViscous: [{
                type: Input
            }], ncIterationsViscous: [{
                type: Input
            }], ncIterationsPoisson: [{
                type: Input
            }], ncDt: [{
                type: Input
            }], ncBFECC: [{
                type: Input
            }], ncResolution: [{
                type: Input
            }], ncIsBounce: [{
                type: Input
            }], ncAutoDemo: [{
                type: Input
            }], ncAutoSpeed: [{
                type: Input
            }], ncAutoIntensity: [{
                type: Input
            }], ncTakeoverDuration: [{
                type: Input
            }], ncAutoResumeDelay: [{
                type: Input
            }], ncAutoRampDuration: [{
                type: Input
            }], onMouseMove: [{
                type: HostListener,
                args: ['mousemove', ['$event']]
            }], onTouchStart: [{
                type: HostListener,
                args: ['touchstart', ['$event']]
            }], onTouchMove: [{
                type: HostListener,
                args: ['touchmove', ['$event']]
            }], onTouchEnd: [{
                type: HostListener,
                args: ['touchend']
            }], onMouseLeave: [{
                type: HostListener,
                args: ['mouseleave']
            }] } });

class NcLiquidEtherBackgroundModule {
}
NcLiquidEtherBackgroundModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcLiquidEtherBackgroundModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
NcLiquidEtherBackgroundModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcLiquidEtherBackgroundModule, declarations: [LiquidEtherBackgroundComponent], imports: [CommonModule], exports: [LiquidEtherBackgroundComponent] });
NcLiquidEtherBackgroundModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcLiquidEtherBackgroundModule, imports: [[
            CommonModule
        ]] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcLiquidEtherBackgroundModule, decorators: [{
            type: NgModule,
            args: [{
                    declarations: [
                        LiquidEtherBackgroundComponent
                    ],
                    imports: [
                        CommonModule
                    ],
                    exports: [
                        LiquidEtherBackgroundComponent
                    ]
                }]
        }] });

/**
 * Generated bundle index. Do not edit.
 */

export { LiquidEtherBackgroundComponent, NcLiquidEtherBackgroundModule };
//# sourceMappingURL=ng-cw-v12-liquid-ether-background.js.map