npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@vvfx/shader2ge

v0.0.1-beta.0

Published

Shader to Galacean Effects conversion engine

Readme

@vvfx/shader2ge

将 GLSL Fragment Shader 转换为 Galacean Effects (GE) 格式的转换引擎。支持原生 GE 格式与 Shadertoy 格式(自动桥接 mainImage / iTime / iResolution / iChannel0~3)。

支持矩阵

输入与运行环境

| 输入类型 | API 调用 | 运行环境 | 说明 | | --- | --- | --- | --- | | GE 原生 fragment shader | convert(source) | 浏览器 / Node.js | void main() + varying vec2 vUV + varying float vTime | | Shadertoy fragment shader | convert(source) | 浏览器 / Node.js | 检测到 mainImage 自动桥接,无需改写源码 | | 带纹理输入 | convert(source, { uniformOverrides }) | 浏览器 / Node.js | 通过 TextureInputsampler2D 赋图 URL | | Shadertoy 通道纹理 | convert(source, { shadertoyChannels }) | 浏览器 / Node.js | 映射 iChannel0~3 到纹理 URL | | 仅解析不生成 | parseShader(source) | 浏览器 / Node.js | 返回桥接后的源码、uniform 列表、Shadertoy 标志、结构警告 |

Uniform 类型覆盖

| GLSL 类型 | 状态 | 说明 | | --- | --- | --- | | float / int | ✅ 已支持 | 通过 materials.floats / materials.ints | | vec2 / vec3 / vec4 | ✅ 已支持 | 一律写入 materials.vector4s(vec2/vec3 自动 padding) | | sampler2D | ✅ 已支持 | 通过 TextureInput 提供 URL,未提供时使用 1×1 白纹理 | | mat4 等矩阵类型 | ❌ 不支持 | 与 GE Material 字段约定不兼容 |

Shadertoy 自动桥接内容

| Shadertoy 变量/函数 | 桥接处理 | | --- | --- | | void mainImage(out vec4 fragColor, in vec2 fragCoord) | 包装为 void main() + 写入 gl_FragColor | | iTime | #define iTime vTime(GE 的 _Time.y) | | iResolution | uniform vec4 iResolution(由 previewSize 填充) | | fragCoord | vUV * iResolution.xy | | iChannel0~3 | 自动注入 uniform sampler2D iChannelN;,通过 shadertoyChannels 提供纹理 |

已知限制

  1. 基于 WebGL 1.0:vertex shader 是固定模板(全屏 Quad),fragment shader 必须遵守 GLSL ES 1.0 语法(不能用 #version 300 es / in/out 修饰符 / texture() / 整数 mod() 等)。
  2. 向量 uniform 必须声明为 vec4:因为 GE Material 的向量字段统一用 glUniform4f 设值,uniform vec2/vec3 会触发运行时报错 Uniform size does not match。需要 vec2/vec3 时声明为 vec4 后通过 swizzle 取用。
  3. Shadertoy 多 Pass 不支持:仅支持单 Image pass。Buffer A/B/C/D、iMouseiFrameiDateiChannelResolution 暂未实现。
  4. uTime 自动桥接:源码中的 uniform float uTime; 会被替换为 varying float vTime; + #define uTime vTime。建议直接使用 vTime
  5. 构造函数参数限制:WebGL 1.0 下 vec2() / vec3() / vec4() 的参数必须是简单变量或常量,不能含算术运算。搬运 Shadertoy 时如遇 'constructor' : too many arguments,需要将复杂表达式拆为临时变量。

安装

npm install @vvfx/shader2ge
# 或
pnpm add @vvfx/shader2ge

快速开始

转换 GE 原生 shader

import { convert } from '@vvfx/shader2ge';

const result = convert(`
  precision highp float;
  varying vec2 vUV;
  varying float vTime;
  void main() {
    vec3 col = 0.5 + 0.5 * cos(vTime + vUV.xyx + vec3(0, 2, 4));
    gl_FragColor = vec4(col, 1.0);
  }
`, {
  sceneName: 'CosineGradient',
  duration: 5,
  previewSize: [1280, 720],
});

console.log(result.scene);     // GE JSONScene,可直接交给 @galacean/effects 播放
console.log(result.uniforms);  // 解析出的 uniform 列表
console.log(result.warnings);  // 转换警告(如缺 main()、未写 gl_FragColor 等)

搬运 Shadertoy

无需改写源码——检测到 mainImage 后自动桥接:

const result = convert(`
  void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    vec2 uv = fragCoord / iResolution.xy;
    vec3 col = 0.5 + 0.5 * cos(iTime + uv.xyx + vec3(0, 2, 4));
    fragColor = vec4(col, 1.0);
  }
`);

带纹理输入

const result = convert(`
  precision highp float;
  varying vec2 vUV;
  uniform sampler2D uMainTex;
  void main() {
    gl_FragColor = texture2D(uMainTex, vUV);
  }
`, {
  uniformOverrides: {
    uMainTex: { url: 'https://example.com/image.png' },
  },
});

Shadertoy 带纹理通道

const result = convert(shadertoyCode, {
  shadertoyChannels: {
    iChannel0: { url: 'https://example.com/noise.png', wrapS: 10497, wrapT: 10497 },
    iChannel1: { url: 'https://example.com/gradient.png' },
  },
});

未提供的通道使用内置 1×1 白纹理(DEFAULT_WHITE_TEXTURE_URL)。

仅解析不生成(轻量预检)

某些场景下你只想了解 shader 结构(uniform 列表、是否 Shadertoy、有没有结构错误),并不需要完整生成 JSONScene。例如 AI 流水线中先 parse 检视 warnings 决定是否重试,节省一次完整转换的开销:

import { parseShader } from '@vvfx/shader2ge';

const parsed = parseShader(source);

console.log(parsed.fragment);    // 桥接 / 兜底处理后的最终 GLSL 源码(GE-ready)
console.log(parsed.uniforms);    // [{ name: 'uColor', type: 'vec4' }, ...]
console.log(parsed.isShadertoy); // 是否为 Shadertoy 格式
console.log(parsed.warnings);    // ['Fragment shader does not contain a main() function...']

if (parsed.warnings.length === 0) {
  // 结构 OK,可以走完整 convert
}

parseShaderConvertOptions 完全无关——convert 内部就是先调它再做选项应用与 scene 生成。

配合 GE Player 播放

import { Player } from '@galacean/effects';
import { convert } from '@vvfx/shader2ge';

const { scene } = convert(fragmentShader, { previewSize: [1280, 720] });
const player = new Player({ container: document.getElementById('canvas')! });
await player.loadScene(scene);

API 参考

convert(fragmentShader, options?)

主入口。将 GLSL fragment shader 源码转换为可播放的 GE JSONScene。

function convert(
  fragmentShader: string,
  options?: ConvertOptions,
): ConvertResult;

interface ConvertOptions {
  /** 场景名称,默认 "ShaderScene" */
  sceneName?: string;
  /** 合成时长(秒),默认 5 */
  duration?: number;
  /** 合成结束行为,默认 EndBehavior.Restart(循环) */
  endBehavior?: EndBehavior;
  /** 预览尺寸 [width, height],默认 [512, 512];自动注入到 uResolution */
  previewSize?: [number, number];
  /** uniform 默认值覆盖(float / vec / color / TextureInput) */
  uniformOverrides?: Record<string, UniformValue>;
  /** Shadertoy 纹理通道映射,key 为 iChannel0~3 */
  shadertoyChannels?: Record<string, TextureInput>;
}

interface ConvertResult {
  /** 生成的可播放 GE JSONScene */
  scene: JSONScene;
  /** 解析出的 uniform 列表 */
  uniforms: ParsedUniform[];
  /** 转换过程中的警告(结构问题 + 纹理缺省提示等) */
  warnings: string[];
}

parseShader(source)

输入解析阶段。返回 shader 的中间表示(IR),不依赖任何 ConvertOptions。

function parseShader(source: string): ParsedShader;

interface ParsedShader {
  /** 桥接 / 兜底处理后的最终 GLSL fragment shader 源码 */
  fragment: string;
  /** 解析出的 uniform 列表(uTime 桥接后已从中移除) */
  uniforms: ParsedUniform[];
  /** 输入是否为 Shadertoy 格式(含 mainImage 函数) */
  isShadertoy: boolean;
  /** 解析阶段产生的警告 */
  warnings: string[];
}

parseUniforms(source)

更底层的工具函数,仅做 uniform 声明的正则提取,不做 Shadertoy 桥接、不做结构校验。需要细粒度控制时使用,否则推荐用 parseShader

function parseUniforms(source: string): ParsedUniform[];

interface ParsedUniform {
  name: string;
  type: 'float' | 'vec2' | 'vec3' | 'vec4' | 'int' | 'sampler2D';
  comment?: string;
}

generateScene(fragment, uniforms, options, isShadertoy)

低阶 API,convert 内部使用。一般业务不需要直接调;适合已经在外面做完所有 parse 工作、只想拼装 JSONScene 的场景。

类型定义

type UniformValue =
  | number
  | { x: number; y: number }                              // vec2
  | { x: number; y: number; z: number }                   // vec3
  | { x: number; y: number; z: number; w: number }        // vec4
  | { r: number; g: number; b: number; a: number }        // color
  | TextureInput;                                          // sampler2D

interface TextureInput {
  /** 图片 URL(http / https / data URI / 相对路径) */
  url: string;
  /** GL 纹理环绕模式 S,默认 REPEAT (10497) */
  wrapS?: number;
  /** GL 纹理环绕模式 T,默认 REPEAT (10497) */
  wrapT?: number;
  /** GL 放大过滤,默认 LINEAR (9729) */
  magFilter?: number;
  /** GL 缩小过滤,默认 LINEAR (9729) */
  minFilter?: number;
  /** 是否翻转 Y 轴,默认 true */
  flipY?: boolean;
}

enum EndBehavior {
  Destroy = 0,
  Forward = 2,
  Freeze = 4,
  Restart = 5,
}

模板常量

也作为 named export 暴露,便于业务侧自行拼装场景或对齐默认值:

import {
  DEFAULT_VERTEX_SHADER,        // 全屏 Quad vertex shader(固定模板)
  FALLBACK_FRAGMENT_SHADER,     // 兜底 fragment shader(输入为空时使用)
  DEFAULT_WHITE_TEXTURE_URL,    // 1×1 白纹理 base64 data URI
  GL_TEXTURE_WRAP_REPEAT,       // 10497
  GL_TEXTURE_WRAP_CLAMP_TO_EDGE,// 33071
  GL_TEXTURE_FILTER_LINEAR,     // 9729
  GL_TEXTURE_FILTER_NEAREST,    // 9728
  GL_TEXTURE_2D,                // 3553
} from '@vvfx/shader2ge';

自动注入的内置 uniform

转换引擎会按需注入这些 uniform,即使源码里没有声明也可以使用:

| Uniform | 类型 | 来源 | | --- | --- | --- | | vTime | varying float | GE _Time.y(vertex shader 桥接) | | vUV | varying vec2 | 全屏 Quad 顶点 UV | | uResolution | vec4 | shader 声明了 uniform vec4 uResolution 时,由 options.previewSize 自动填充为 (width, height, 1, 0),避免预览尺寸变化后宽高比矫正错位 | | iTime | #define iTime vTime | Shadertoy 模式 | | iResolution | uniform vec4 | Shadertoy 模式,由 previewSize 填充 | | iChannel0~3 | uniform sampler2D | Shadertoy 模式 + 引用了对应通道时自动注入 |

架构

shader2ge 内部分两阶段:

源码  ──parseShader──▶  ParsedShader IR  ──convert──▶  ConvertResult
                       (fragment, uniforms,                  (scene, uniforms,
                        isShadertoy, warnings)                warnings)
  • parseShader:纯输入理解,与 options 无关
  • convert:应用 ConvertOptions(uniformOverrides / shadertoyChannels / previewSize / sceneName / duration),生成 JSONScene

如果你只关心 shader 元信息或想在转换前预检,调 parseShader 即可,避免支付 scene 生成的开销。

License

MIT