diff --git a/package.json b/package.json
index b4e112d..80eceec 100644
--- a/package.json
+++ b/package.json
@@ -35,7 +35,7 @@
         "mutate-animate": "^1.4.2",
         "ogg-opus-decoder": "^1.6.14",
         "opus-decoder": "^0.7.7",
-        "vue": "^3.5.13"
+        "vue": "^3.5.17"
     },
     "devDependencies": {
         "@babel/cli": "^7.26.4",
diff --git a/packages-user/client-modules/src/render/fx/base.ts b/packages-user/client-modules/src/render/fx/base.ts
new file mode 100644
index 0000000..c5bb1d0
--- /dev/null
+++ b/packages-user/client-modules/src/render/fx/base.ts
@@ -0,0 +1,51 @@
+import { Shader, ShaderProgram } from '@motajs/render-core';
+
+export abstract class EffectBase<T> {
+    /** 当前使用的程序 */
+    protected readonly program: ShaderProgram;
+
+    constructor(
+        public readonly shader: Shader,
+        public readonly options: T
+    ) {
+        const vs = this.getVertex(options);
+        const fs = this.getFragment(options);
+        const program = shader.createProgram(ShaderProgram, vs, fs);
+        program.requestCompile();
+
+        this.program = program;
+    }
+
+    /**
+     * 获取片段着色器代码
+     * @param options 配置信息
+     */
+    protected abstract getVertex(options: T): string;
+
+    /**
+     * 获取顶点着色器代码
+     * @param options 配置信息
+     */
+    protected abstract getFragment(options: T): string;
+
+    /**
+     * 初始化着色器程序
+     * @param program 着色器程序
+     * @param options 配置信息
+     */
+    abstract initProgram(program: ShaderProgram, options: T): void;
+
+    /**
+     * 更新着色器渲染
+     */
+    requestUpdate() {
+        this.shader.update();
+    }
+
+    /**
+     * 使用此着色器
+     */
+    use() {
+        this.shader.useProgram(this.program);
+    }
+}
diff --git a/packages-user/client-modules/src/render/fx/image3d.ts b/packages-user/client-modules/src/render/fx/image3d.ts
new file mode 100644
index 0000000..b2dec33
--- /dev/null
+++ b/packages-user/client-modules/src/render/fx/image3d.ts
@@ -0,0 +1,109 @@
+import {
+    ITransformUpdatable,
+    ShaderProgram,
+    Transform3D
+} from '@motajs/render-core';
+import { EffectBase } from './base';
+
+export class Image3DEffect
+    extends EffectBase<void>
+    implements ITransformUpdatable
+{
+    /** 图片的模型变换 */
+    private model: Transform3D = new Transform3D();
+    /** 视角变换 */
+    private view: Transform3D = new Transform3D();
+    /** 投影变换 */
+    private proj: Transform3D = new Transform3D();
+
+    protected getVertex(): string {
+        return /* glsl */ `
+            uniform mat4 u_imageTransform;
+
+            void main() {
+                v_texCoord = a_texCoord;
+                gl_Position = u_imageTransform * a_position;
+            }
+        `;
+    }
+
+    protected getFragment(): string {
+        return /* glsl */ `
+            void main() {
+                gl_FragColor = texture2D(u_sampler, v_texCoord);
+            }
+        `;
+    }
+
+    initProgram(program: ShaderProgram): void {
+        program.defineUniformMatrix(
+            'u_imageTransform',
+            this.shader.U_MATRIX_4x4
+        );
+        const shader = this.shader;
+        const aspect = shader.width / shader.height;
+        this.proj.perspective((Math.PI * 2) / 3, aspect, 0.01, 1000);
+        this.model.bind(this);
+        this.view.bind(this);
+        this.proj.bind(this);
+    }
+
+    updateTransform(): void {
+        const matrix = this.program.getMatrix('u_imageTransform');
+        if (!matrix) return;
+        const trans = this.model.multiply(this.view).multiply(this.proj);
+        matrix.set(false, trans.mat);
+        this.requestUpdate();
+    }
+
+    /**
+     * 设置模型变换
+     * @param model 模型变换
+     */
+    setModel(model: Transform3D) {
+        this.model.bind();
+        this.model = model;
+        model.bind(this);
+    }
+
+    /**
+     * 设置视角变换
+     * @param model 视角变换
+     */
+    setView(view: Transform3D) {
+        this.view.bind();
+        this.view = view;
+        view.bind(this);
+    }
+
+    /**
+     * 设置投影变换
+     * @param model 投影变换
+     */
+    setProj(proj: Transform3D) {
+        this.proj.bind();
+        this.proj = proj;
+        proj.bind(this);
+    }
+
+    /**
+     * 获取模型变换
+     */
+    getModel() {
+        return this.model;
+    }
+
+    /**
+     * 获取视角变换
+     */
+    getView() {
+        return this.view;
+    }
+
+    /**
+     * 获取投影变换
+     */
+    getProj() {
+        return this.proj;
+    }
+}
diff --git a/packages-user/client-modules/src/render/fx/index.ts b/packages-user/client-modules/src/render/fx/index.ts
new file mode 100644
index 0000000..a40ef0c
--- /dev/null
+++ b/packages-user/client-modules/src/render/fx/index.ts
@@ -0,0 +1,2 @@
+export * from './base';
+export * from './image3d';
diff --git a/packages-user/legacy-plugin-client/src/fx/pointShader.ts b/packages-user/legacy-plugin-client/src/fx/pointShader.ts
index 72bdded..9b2178c 100644
--- a/packages-user/legacy-plugin-client/src/fx/pointShader.ts
+++ b/packages-user/legacy-plugin-client/src/fx/pointShader.ts
@@ -110,6 +110,7 @@ export class PointEffect {
     private toAdd: Set<number[]> = new Set();
     /** 每个特效的开始时间 */
     private startTime: Map<number, number> = new Map();
+
     /**
      * 为着色器创建程序
      * @param shader 着色器渲染元素
diff --git a/packages/render-core/src/transform.ts b/packages/render-core/src/transform.ts
index 2a45733..af53975 100644
--- a/packages/render-core/src/transform.ts
+++ b/packages/render-core/src/transform.ts
@@ -1,4 +1,4 @@
-import { mat3, ReadonlyMat3, ReadonlyVec3, vec2, vec3 } from 'gl-matrix';
+import { mat3, mat4, ReadonlyMat3, ReadonlyVec3, vec2, vec3 } from 'gl-matrix';
 
 export interface ITransformUpdatable {
     updateTransform?(): void;
@@ -38,6 +38,7 @@ export class Transform {
         this.scaleY = 1;
         this.rad = 0;
         this.modified = false;
+        this.bindedObject?.updateTransform?.();
     }
 
     /**
@@ -189,11 +190,9 @@ export class Transform {
      */
     multiply(transform: Transform): Transform {
         if (this.modified) {
-            const res = new Transform();
-            const mat = mat3.clone(this.mat);
-            mat3.multiply(mat, mat, transform.mat);
-            res.mat = mat;
-            return res;
+            const result = new Transform();
+            mat3.multiply(result.mat, this.mat, transform.mat);
+            return result;
         } else {
             return transform.clone();
         }
@@ -253,7 +252,9 @@ export class Transform {
     }
 
     /** 单位矩阵 */
-    static readonly identity = new Transform();
+    static get identity() {
+        return new Transform();
+    }
 }
 
 function multiplyVec3(mat: ReadonlyMat3, vec: ReadonlyVec3): vec3 {
@@ -278,3 +279,181 @@ function getScaling(mat: ReadonlyMat3): vec2 {
 function getRotation(mat: ReadonlyMat3): number {
     return Math.atan2(mat[3], mat[0]);
 }
+
+export class Transform3D {
+    mat: mat4 = mat4.create();
+
+    /** 绑定的可更新元素 */
+    bindedObject?: ITransformUpdatable;
+
+    /**
+     * 绑定可更新对象
+     * @param obj 要绑定的对象
+     */
+    bind(obj?: ITransformUpdatable) {
+        this.bindedObject = obj;
+    }
+
+    /**
+     * 重置为单位矩阵
+     */
+    reset(): this {
+        mat4.identity(this.mat);
+        this.bindedObject?.updateTransform?.();
+        return this;
+    }
+
+    /**
+     * 应用缩放变换
+     * @param x X轴缩放
+     * @param y Y轴缩放
+     * @param z Z轴缩放
+     */
+    scale(x: number, y: number, z: number): this {
+        mat4.scale(this.mat, this.mat, [x, y, z]);
+        this.bindedObject?.updateTransform?.();
+        return this;
+    }
+
+    /**
+     * 应用平移变换
+     * @param x X轴平移
+     * @param y Y轴平移
+     * @param z Z轴平移
+     */
+    translate(x: number, y: number, z: number): this {
+        mat4.translate(this.mat, this.mat, [x, y, z]);
+        this.bindedObject?.updateTransform?.();
+        return this;
+    }
+
+    /**
+     * 应用旋转变换
+     * @param rad 旋转角度(弧度)
+     * @param axis 旋转轴
+     */
+    rotate(rad: number, axis: vec3): this {
+        mat4.rotate(this.mat, this.mat, rad, axis);
+        this.bindedObject?.updateTransform?.();
+        return this;
+    }
+
+    /**
+     * 应用绕X轴旋转
+     * @param rad 旋转角度(弧度)
+     */
+    rotateX(rad: number): this {
+        return this.rotate(rad, [1, 0, 0]);
+    }
+
+    /**
+     * 应用绕Y轴旋转
+     * @param rad 旋转角度(弧度)
+     */
+    rotateY(rad: number): this {
+        return this.rotate(rad, [0, 1, 0]);
+    }
+
+    /**
+     * 应用绕Z轴旋转
+     * @param rad 旋转角度(弧度)
+     */
+    rotateZ(rad: number): this {
+        return this.rotate(rad, [0, 0, 1]);
+    }
+
+    /**
+     * 设置视图矩阵
+     * @param eye 摄像机位置
+     * @param center 目标位置
+     * @param up 上方向量
+     */
+    lookAt(eye: vec3, center: vec3, up: vec3): this {
+        mat4.lookAt(this.mat, eye, center, up);
+        this.bindedObject?.updateTransform?.();
+        return this;
+    }
+
+    /**
+     * 设置透视投影矩阵
+     * @param fovy 垂直视野角度(弧度)
+     * @param aspect 宽高比
+     * @param near 近平面
+     * @param far 远平面
+     */
+    perspective(fovy: number, aspect: number, near: number, far: number): this {
+        mat4.perspective(this.mat, fovy, aspect, near, far);
+        this.bindedObject?.updateTransform?.();
+        return this;
+    }
+
+    /**
+     * 设置正交投影矩阵
+     * @param left 左平面
+     * @param right 右平面
+     * @param bottom 底平面
+     * @param top 顶平面
+     * @param near 近平面
+     * @param far 远平面
+     */
+    ortho(
+        left: number,
+        right: number,
+        bottom: number,
+        top: number,
+        near: number,
+        far: number
+    ): this {
+        mat4.ortho(this.mat, left, right, bottom, top, near, far);
+        this.bindedObject?.updateTransform?.();
+        return this;
+    }
+
+    /**
+     * 与另一个变换矩阵相乘
+     * @param transform 另一个变换矩阵
+     */
+    multiply(transform: Transform3D): Transform3D {
+        const result = new Transform3D();
+        mat4.multiply(result.mat, this.mat, transform.mat);
+        return result;
+    }
+
+    /**
+     * 克隆当前变换矩阵
+     */
+    clone(): Transform3D {
+        const clone = new Transform3D();
+        mat4.copy(clone.mat, this.mat);
+        return clone;
+    }
+
+    /**
+     * 将点应用变换
+     * @param point 要变换的点
+     */
+    transformed(point: vec3): vec3 {
+        const result = vec3.create();
+        vec3.transformMat4(result, point, this.mat);
+        return result;
+    }
+
+    /**
+     * 将点应用逆变换
+     * @param point 要逆变换的点
+     */
+    untransformed(point: vec3): vec3 {
+        const inverse = mat4.create();
+        mat4.invert(inverse, this.mat);
+        const result = vec3.create();
+        vec3.transformMat4(result, point, inverse);
+        return result;
+    }
+
+    /**
+     * 静态方法:单位矩阵
+     */
+    static get identity(): Transform3D {
+        return new Transform3D();
+    }
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 957d586..e5b823f 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -54,7 +54,7 @@ importers:
         specifier: ^0.7.7
         version: 0.7.10
       vue:
-        specifier: ^3.5.13
+        specifier: ^3.5.17
         version: 3.5.17(typescript@5.8.3)
     devDependencies:
       '@babel/cli':