spline-interactive

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Spline Interactive - Browser-Based 3D Design and Animation

Spline Interactive - 基于浏览器的3D设计与动画工具

Overview

概述

Spline is a browser-based 3D design and animation platform that enables creators to build interactive 3D experiences without requiring code or specialized software knowledge. It provides a collaborative visual editor for designing, animating, and exporting 3D scenes across multiple platforms.
Key Features:
  • Visual 3D modeling with parametric shapes, extrusion, and boolean operations
  • State-based animation system with timeline controls
  • Interactive event system (mouse, keyboard, collision, scroll)
  • Multiple export options (React components, web code, public URLs)
  • Real-time collaboration with team libraries
  • AI-powered generation (3D from text, textures, style transfer)
  • Built-in physics and particle systems
When to Use This Skill:
  • Creating 3D web experiences without writing Three.js code
  • Designing interactive product showcases or configurators
  • Prototyping 3D UI/UX concepts visually
  • Building marketing pages with 3D elements
  • Collaborating with designers on 3D content
  • Exporting scenes for React or vanilla JS integration
Alternatives:
  • Three.js (threejs-webgl): For developers who prefer code-first approach and need maximum control
  • Babylon.js (babylonjs-engine): For game-focused projects with built-in physics
  • React Three Fiber (react-three-fiber): For React developers who want to build 3D with JSX
Spline是一款基于浏览器的3D设计与动画平台,创作者无需代码或专业软件知识即可构建交互式3D体验。它提供了协同式可视化编辑器,支持跨多平台设计、制作动画和导出3D场景。
核心功能:
  • 支持参数化形状、挤出、布尔运算的可视化3D建模
  • 带时间轴控制的基于状态的动画系统
  • 交互式事件系统(鼠标、键盘、碰撞、滚动)
  • 多格式导出选项(React组件、Web代码、公开URL)
  • 带团队资源库的实时协作功能
  • AI生成能力(文本生成3D、纹理生成、风格迁移)
  • 内置物理引擎和粒子系统
适用场景:
  • 无需编写Three.js代码即可创建3D Web体验
  • 设计交互式产品展示页或配置器
  • 可视化制作3D UI/UX概念原型
  • 构建带3D元素的营销页面
  • 和设计师协同创作3D内容
  • 导出场景用于React或原生JS集成
替代方案:
  • Three.js (threejs-webgl): 适合偏好代码优先开发模式、需要最大化控制力的开发者
  • Babylon.js (babylonjs-engine): 适合侧重游戏开发、需要内置物理引擎的项目
  • React Three Fiber (react-three-fiber): 适合想要用JSX构建3D内容的React开发者

Core Concepts

核心概念

1. Scene Structure

1. 场景结构

Spline organizes projects into scenes containing:
  • Objects: 3D models, shapes, text, images
  • Lights: Directional, point, spot lights
  • Cameras: Orbital, perspective, orthographic
  • Events: Interaction triggers
  • States: Animation keyframes
Spline将项目组织为场景,包含以下元素:
  • 对象: 3D模型、形状、文本、图片
  • 光源: 平行光、点光源、聚光灯
  • 相机: 轨道相机、透视相机、正交相机
  • 事件: 交互触发器
  • 状态: 动画关键帧

2. Components System

2. 组件系统

Reusable elements that can be:
  • Created from any object or group
  • Instantiated multiple times
  • Updated across all instances
  • Overridden per instance
可复用元素,支持以下操作:
  • 从任意对象或对象组创建
  • 多次实例化
  • 全局同步更新所有实例
  • 单实例属性覆盖

3. State-Based Animation

3. 基于状态的动画

Animations are defined as transitions between states:
  • Default State: Initial appearance
  • Additional States: Target appearances
  • Events: Triggers that cause state transitions
  • Transitions: Duration, easing, properties
动画通过状态之间的过渡定义:
  • 默认状态: 初始外观
  • 自定义状态: 目标外观
  • 事件: 触发状态过渡的条件
  • 过渡参数: 时长、缓动函数、作用属性

4. Interactivity Model

4. 交互模型

Event-driven system with:
  • Events: User actions or scene triggers
  • Conditions: Logic gates (if/else)
  • Actions: State changes, audio, scene switches
  • Variables: Dynamic data from APIs or user input
事件驱动系统,包含:
  • 事件: 用户操作或场景触发器
  • 条件: 逻辑判断(if/else)
  • 动作: 状态变更、音频播放、场景切换
  • 变量: 来自API或用户输入的动态数据

5. Export Options

5. 导出选项

Multiple deployment methods:
  • Public URL: Direct shareable link
  • Code Export: React component or vanilla JS
  • Spline Viewer: Embedded iframe
  • Self-Hosted: Download and host independently
多部署方式支持:
  • 公开URL: 可直接分享的链接
  • 代码导出: React组件或原生JS
  • Spline Viewer: 嵌入式iframe
  • 自托管: 下载资源独立部署

Common Patterns

常用模式

Pattern 1: Basic React Integration

模式1: 基础React集成

Use Case: Embed a Spline scene in a React application
Implementation:
bash
undefined
使用场景: 在React应用中嵌入Spline场景
实现代码:
bash
undefined

Installation

安装依赖

npm install @splinetool/react-spline @splinetool/runtime

```jsx
import Spline from '@splinetool/react-spline';

export default function Hero() {
  return (
    <div style={{ width: '100%', height: '600px' }}>
      <Spline scene="https://prod.spline.design/YOUR-SCENE-ID/scene.splinecode" />
    </div>
  );
}
Key Points:
  • Scene URL comes from Spline export dialog
  • Component fills parent container
  • Automatically handles loading and rendering
npm install @splinetool/react-spline @splinetool/runtime

```jsx
import Spline from '@splinetool/react-spline';

export default function Hero() {
  return (
    <div style={{ width: '100%', height: '600px' }}>
      <Spline scene="https://prod.spline.design/YOUR-SCENE-ID/scene.splinecode" />
    </div>
  );
}
核心要点:
  • 场景URL来自Spline导出对话框
  • 组件会自动填充父容器
  • 自动处理加载和渲染流程

Pattern 2: Event Handling and Object Interaction

模式2: 事件处理与对象交互

Use Case: Respond to user clicks on specific objects
Implementation:
jsx
import Spline from '@splinetool/react-spline';

export default function InteractiveScene() {
  function onSplineMouseDown(e) {
    // Check if clicked object is the button
    if (e.target.name === 'Button') {
      console.log('Button clicked!');

      // Get object properties
      console.log('Position:', e.target.position);
      console.log('Rotation:', e.target.rotation);
      console.log('Scale:', e.target.scale);
    }
  }

  function onSplineMouseHover(e) {
    if (e.target.name === 'Button') {
      console.log('Hovering over button');
    }
  }

  return (
    <Spline
      scene="https://prod.spline.design/YOUR-SCENE-ID/scene.splinecode"
      onSplineMouseDown={onSplineMouseDown}
      onSplineMouseHover={onSplineMouseHover}
    />
  );
}
Available Event Handlers:
  • onSplineMouseDown
    - Mouse press on object
  • onSplineMouseUp
    - Mouse release
  • onSplineMouseHover
    - Mouse over object
  • onSplineKeyDown
    - Keyboard press
  • onSplineKeyUp
    - Keyboard release
  • onSplineStart
    - Scene loaded and started
  • onSplineLookAt
    - Camera look-at event
  • onSplineFollow
    - Camera follow event
  • onSplineScroll
    - Scroll event
使用场景: 响应用户对特定对象的点击操作
实现代码:
jsx
import Spline from '@splinetool/react-spline';

export default function InteractiveScene() {
  function onSplineMouseDown(e) {
    // 检查点击的对象是否是按钮
    if (e.target.name === 'Button') {
      console.log('Button clicked!');

      // 获取对象属性
      console.log('Position:', e.target.position);
      console.log('Rotation:', e.target.rotation);
      console.log('Scale:', e.target.scale);
    }
  }

  function onSplineMouseHover(e) {
    if (e.target.name === 'Button') {
      console.log('Hovering over button');
    }
  }

  return (
    <Spline
      scene="https://prod.spline.design/YOUR-SCENE-ID/scene.splinecode"
      onSplineMouseDown={onSplineMouseDown}
      onSplineMouseHover={onSplineMouseHover}
    />
  );
}
可用事件处理器:
  • onSplineMouseDown
    - 鼠标按下对象
  • onSplineMouseUp
    - 鼠标松开
  • onSplineMouseHover
    - 鼠标悬停对象
  • onSplineKeyDown
    - 键盘按下
  • onSplineKeyUp
    - 键盘松开
  • onSplineStart
    - 场景加载完成并启动
  • onSplineLookAt
    - 相机看向目标事件
  • onSplineFollow
    - 相机跟随事件
  • onSplineScroll
    - 滚动事件

Pattern 3: Programmatic Object Control

模式3: 程序化控制对象

Use Case: Modify object properties from React code
Implementation:
jsx
import { useRef } from 'react';
import Spline from '@splinetool/react-spline';

export default function ProductViewer() {
  const cube = useRef();
  const splineApp = useRef();

  function onLoad(spline) {
    // Save Spline instance
    splineApp.current = spline;

    // Find object by name
    const obj = spline.findObjectByName('Product');
    // Or by ID
    // const obj = spline.findObjectById('8E8C2DDD-18B6-4C54-861D-7ED2519DE20E');

    cube.current = obj;
  }

  function rotateProduct() {
    if (cube.current) {
      // Rotate 45 degrees around Y axis
      cube.current.rotation.y += Math.PI / 4;
    }
  }

  function changeColor() {
    if (cube.current) {
      // Change material color (hex color)
      cube.current.material.color.set(0xff6b6b);
    }
  }

  function moveProduct() {
    if (cube.current) {
      cube.current.position.x += 50;
      cube.current.position.y += 10;
    }
  }

  return (
    <div>
      <Spline
        scene="https://prod.spline.design/YOUR-SCENE-ID/scene.splinecode"
        onLoad={onLoad}
      />
      <div style={{ position: 'absolute', top: 20, left: 20 }}>
        <button onClick={rotateProduct}>Rotate</button>
        <button onClick={changeColor}>Change Color</button>
        <button onClick={moveProduct}>Move</button>
      </div>
    </div>
  );
}
Object Properties You Can Modify:
  • position
    - { x, y, z }
  • rotation
    - { x, y, z } (radians)
  • scale
    - { x, y, z }
  • material.color
    - Color hex value
  • visible
    - Boolean
使用场景: 从React代码中修改对象属性
实现代码:
jsx
import { useRef } from 'react';
import Spline from '@splinetool/react-spline';

export default function ProductViewer() {
  const cube = useRef();
  const splineApp = useRef();

  function onLoad(spline) {
    // 保存Spline实例
    splineApp.current = spline;

    // 按名称查找对象
    const obj = spline.findObjectByName('Product');
    // 或按ID查找
    // const obj = spline.findObjectById('8E8C2DDD-18B6-4C54-861D-7ED2519DE20E');

    cube.current = obj;
  }

  function rotateProduct() {
    if (cube.current) {
      // 沿Y轴旋转45度
      cube.current.rotation.y += Math.PI / 4;
    }
  }

  function changeColor() {
    if (cube.current) {
      // 修改材质颜色(十六进制颜色值)
      cube.current.material.color.set(0xff6b6b);
    }
  }

  function moveProduct() {
    if (cube.current) {
      cube.current.position.x += 50;
      cube.current.position.y += 10;
    }
  }

  return (
    <div>
      <Spline
        scene="https://prod.spline.design/YOUR-SCENE-ID/scene.splinecode"
        onLoad={onLoad}
      />
      <div style={{ position: 'absolute', top: 20, left: 20 }}>
        <button onClick={rotateProduct}>Rotate</button>
        <button onClick={changeColor}>Change Color</button>
        <button onClick={moveProduct}>Move</button>
      </div>
    </div>
  );
}
可修改的对象属性:
  • position
    - { x, y, z }
  • rotation
    - { x, y, z }(弧度单位)
  • scale
    - { x, y, z }
  • material.color
    - 十六进制颜色值
  • visible
    - 布尔值

Pattern 4: Triggering Spline Animations

模式4: 触发Spline动画

Use Case: Trigger animations defined in Spline from React
Implementation:
jsx
import { useRef } from 'react';
import Spline from '@splinetool/react-spline';

export default function AnimatedCard() {
  const splineApp = useRef();

  function onLoad(app) {
    splineApp.current = app;
  }

  function triggerHoverAnimation() {
    // Emit mouseHover event on 'Card' object
    splineApp.current.emitEvent('mouseHover', 'Card');
  }

  function triggerClickAnimation() {
    // Emit mouseDown event on 'Button' object
    splineApp.current.emitEvent('mouseDown', 'Button');
  }

  function reverseAnimation() {
    // Play animation in reverse
    splineApp.current.emitEventReverse('mouseHover', 'Card');
  }

  return (
    <div>
      <Spline
        scene="https://prod.spline.design/YOUR-SCENE-ID/scene.splinecode"
        onLoad={onLoad}
      />
      <button onClick={triggerHoverAnimation}>Hover Effect</button>
      <button onClick={triggerClickAnimation}>Click Effect</button>
      <button onClick={reverseAnimation}>Reverse</button>
    </div>
  );
}
Available Event Types:
  • mouseDown
    - Mouse press
  • mouseHover
    - Hover effect
  • mouseUp
    - Mouse release
  • keyDown
    - Key press
  • keyUp
    - Key release
  • start
    - Start event
  • lookAt
    - Look at camera
  • follow
    - Follow camera
使用场景: 从React代码中触发Spline内定义的动画
实现代码:
jsx
import { useRef } from 'react';
import Spline from '@splinetool/react-spline';

export default function AnimatedCard() {
  const splineApp = useRef();

  function onLoad(app) {
    splineApp.current = app;
  }

  function triggerHoverAnimation() {
    // 在'Card'对象上触发mouseHover事件
    splineApp.current.emitEvent('mouseHover', 'Card');
  }

  function triggerClickAnimation() {
    // 在'Button'对象上触发mouseDown事件
    splineApp.current.emitEvent('mouseDown', 'Button');
  }

  function reverseAnimation() {
    // 反向播放动画
    splineApp.current.emitEventReverse('mouseHover', 'Card');
  }

  return (
    <div>
      <Spline
        scene="https://prod.spline.design/YOUR-SCENE-ID/scene.splinecode"
        onLoad={onLoad}
      />
      <button onClick={triggerHoverAnimation}>Hover Effect</button>
      <button onClick={triggerClickAnimation}>Click Effect</button>
      <button onClick={reverseAnimation}>Reverse</button>
    </div>
  );
}
可用事件类型:
  • mouseDown
    - 鼠标按下
  • mouseHover
    - 悬停效果
  • mouseUp
    - 鼠标松开
  • keyDown
    - 按键按下
  • keyUp
    - 按键松开
  • start
    - 启动事件
  • lookAt
    - 看向相机
  • follow
    - 跟随相机

Pattern 5: Next.js Integration with SSR

模式5: Next.js SSR集成

Use Case: Use Spline in Next.js with server-side rendering benefits
Implementation:
jsx
// app/page.js (Next.js 13+ App Router)
import Spline from '@splinetool/react-spline/next';

export default function Home() {
  return (
    <main>
      <div style={{ width: '100vw', height: '100vh' }}>
        <Spline scene="https://prod.spline.design/YOUR-SCENE-ID/scene.splinecode" />
      </div>
    </main>
  );
}
Benefits:
  • Placeholder image shown during SSR
  • Faster perceived load times
  • Better SEO with fallback content
使用场景: 在Next.js中使用Spline并享受服务端渲染优势
实现代码:
jsx
// app/page.js (Next.js 13+ App Router)
import Spline from '@splinetool/react-spline/next';

export default function Home() {
  return (
    <main>
      <div style={{ width: '100vw', height: '100vh' }}>
        <Spline scene="https://prod.spline.design/YOUR-SCENE-ID/scene.splinecode" />
      </div>
    </main>
  );
}
优势:
  • SSR阶段展示占位图
  • 更快的感知加载速度
  • 降级内容优化SEO效果

Pattern 6: Lazy Loading for Performance

模式6: 懒加载优化性能

Use Case: Defer Spline loading until needed
Implementation:
jsx
import React, { Suspense } from 'react';

// Dynamically import Spline
const Spline = React.lazy(() => import('@splinetool/react-spline'));

export default function LazyScene() {
  return (
    <div>
      <h1>My Page Content</h1>

      <Suspense fallback={<div>Loading 3D scene...</div>}>
        <div style={{ width: '100%', height: '500px' }}>
          <Spline scene="https://prod.spline.design/YOUR-SCENE-ID/scene.splinecode" />
        </div>
      </Suspense>

      <p>More content below</p>
    </div>
  );
}
Benefits:
  • Reduces initial bundle size
  • Improves page load performance
  • Shows custom loading UI
使用场景: 延迟Spline加载直到需要时再加载
实现代码:
jsx
import React, { Suspense } from 'react';

// 动态导入Spline
const Spline = React.lazy(() => import('@splinetool/react-spline'));

export default function LazyScene() {
  return (
    <div>
      <h1>My Page Content</h1>

      <Suspense fallback={<div>Loading 3D scene...</div>}>
        <div style={{ width: '100%', height: '500px' }}>
          <Spline scene="https://prod.spline.design/YOUR-SCENE-ID/scene.splinecode" />
        </div>
      </Suspense>

      <p>More content below</p>
    </div>
  );
}
优势:
  • 减小初始包体积
  • 提升页面加载性能
  • 支持自定义加载UI

Pattern 7: Responsive Spline Scenes

模式7: 响应式Spline场景

Use Case: Make Spline scenes adapt to different screen sizes
Implementation:
jsx
import Spline from '@splinetool/react-spline';
import { useState, useEffect } from 'react';

export default function ResponsiveScene() {
  const [isMobile, setIsMobile] = useState(false);

  useEffect(() => {
    const checkMobile = () => {
      setIsMobile(window.innerWidth < 768);
    };

    checkMobile();
    window.addEventListener('resize', checkMobile);
    return () => window.removeEventListener('resize', checkMobile);
  }, []);

  return (
    <div style={{
      width: '100%',
      height: isMobile ? '400px' : '600px'
    }}>
      <Spline
        scene={
          isMobile
            ? "https://prod.spline.design/YOUR-MOBILE-SCENE/scene.splinecode"
            : "https://prod.spline.design/YOUR-DESKTOP-SCENE/scene.splinecode"
        }
      />
    </div>
  );
}
Alternative Approach (Single Scene):
jsx
import Spline from '@splinetool/react-spline';
import { useRef, useEffect } from 'react';

export default function ResponsiveScene() {
  const splineApp = useRef();

  function onLoad(app) {
    splineApp.current = app;
    adjustForScreenSize();
  }

  function adjustForScreenSize() {
    if (!splineApp.current) return;

    const camera = splineApp.current.findObjectByName('Camera');
    const isMobile = window.innerWidth < 768;

    if (isMobile) {
      // Zoom out on mobile
      splineApp.current.setZoom(0.7);
      // Adjust camera position
      camera.position.z = 1500;
    }
  }

  useEffect(() => {
    window.addEventListener('resize', adjustForScreenSize);
    return () => window.removeEventListener('resize', adjustForScreenSize);
  }, []);

  return (
    <Spline
      scene="https://prod.spline.design/YOUR-SCENE-ID/scene.splinecode"
      onLoad={onLoad}
    />
  );
}
使用场景: 让Spline场景适配不同屏幕尺寸
实现代码:
jsx
import Spline from '@splinetool/react-spline';
import { useState, useEffect } from 'react';

export default function ResponsiveScene() {
  const [isMobile, setIsMobile] = useState(false);

  useEffect(() => {
    const checkMobile = () => {
      setIsMobile(window.innerWidth < 768);
    };

    checkMobile();
    window.addEventListener('resize', checkMobile);
    return () => window.removeEventListener('resize', checkMobile);
  }, []);

  return (
    <div style={{
      width: '100%',
      height: isMobile ? '400px' : '600px'
    }}>
      <Spline
        scene={
          isMobile
            ? "https://prod.spline.design/YOUR-MOBILE-SCENE/scene.splinecode"
            : "https://prod.spline.design/YOUR-DESKTOP-SCENE/scene.splinecode"
        }
      />
    </div>
  );
}
替代方案(单场景实现):
jsx
import Spline from '@splinetool/react-spline';
import { useRef, useEffect } from 'react';

export default function ResponsiveScene() {
  const splineApp = useRef();

  function onLoad(app) {
    splineApp.current = app;
    adjustForScreenSize();
  }

  function adjustForScreenSize() {
    if (!splineApp.current) return;

    const camera = splineApp.current.findObjectByName('Camera');
    const isMobile = window.innerWidth < 768;

    if (isMobile) {
      // 移动端缩小缩放比例
      splineApp.current.setZoom(0.7);
      // 调整相机位置
      camera.position.z = 1500;
    }
  }

  useEffect(() => {
    window.addEventListener('resize', adjustForScreenSize);
    return () => window.removeEventListener('resize', adjustForScreenSize);
  }, []);

  return (
    <Spline
      scene="https://prod.spline.design/YOUR-SCENE-ID/scene.splinecode"
      onLoad={onLoad}
    />
  );
}

Integration Patterns

集成模式

With Three.js (threejs-webgl)

与Three.js集成 (threejs-webgl)

For advanced use cases, combine Spline-designed assets with Three.js code:
  1. Export from Spline: Use GLTF/GLB export
  2. Import in Three.js: Load using GLTFLoader
  3. Enhance with code: Add custom shaders, physics, or effects
javascript
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';

const loader = new GLTFLoader();
loader.load('spline-model.glb', (gltf) => {
  scene.add(gltf.scene);
  // Add custom behaviors
});
针对高级场景,可将Spline设计的资产与Three.js代码结合使用:
  1. 从Spline导出: 使用GLTF/GLB格式导出
  2. 导入到Three.js: 使用GLTFLoader加载
  3. 代码增强: 添加自定义着色器、物理效果或特效
javascript
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';

const loader = new GLTFLoader();
loader.load('spline-model.glb', (gltf) => {
  scene.add(gltf.scene);
  // 添加自定义行为
});

With GSAP (gsap-scrolltrigger)

与GSAP集成 (gsap-scrolltrigger)

Trigger Spline animations on scroll:
jsx
import { useEffect, useRef } from 'react';
import Spline from '@splinetool/react-spline';
import gsap from 'gsap';
import ScrollTrigger from 'gsap/ScrollTrigger';

gsap.registerPlugin(ScrollTrigger);

export default function ScrollAnimated() {
  const splineApp = useRef();

  function onLoad(app) {
    splineApp.current = app;

    ScrollTrigger.create({
      trigger: '.scene-container',
      start: 'top center',
      onEnter: () => {
        app.emitEvent('mouseHover', 'Product');
      }
    });
  }

  return (
    <div className="scene-container">
      <Spline
        scene="https://prod.spline.design/YOUR-SCENE-ID/scene.splinecode"
        onLoad={onLoad}
      />
    </div>
  );
}
滚动时触发Spline动画:
jsx
import { useEffect, useRef } from 'react';
import Spline from '@splinetool/react-spline';
import gsap from 'gsap';
import ScrollTrigger from 'gsap/ScrollTrigger';

gsap.registerPlugin(ScrollTrigger);

export default function ScrollAnimated() {
  const splineApp = useRef();

  function onLoad(app) {
    splineApp.current = app;

    ScrollTrigger.create({
      trigger: '.scene-container',
      start: 'top center',
      onEnter: () => {
        app.emitEvent('mouseHover', 'Product');
      }
    });
  }

  return (
    <div className="scene-container">
      <Spline
        scene="https://prod.spline.design/YOUR-SCENE-ID/scene.splinecode"
        onLoad={onLoad}
      />
    </div>
  );
}

With Framer Motion (motion-framer)

与Framer Motion集成 (motion-framer)

Animate container while Spline handles 3D:
jsx
import { motion } from 'framer-motion';
import Spline from '@splinetool/react-spline';

export default function AnimatedContainer() {
  return (
    <motion.div
      initial={{ opacity: 0, y: 50 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ duration: 0.8 }}
      style={{ width: '100%', height: '600px' }}
    >
      <Spline scene="https://prod.spline.design/YOUR-SCENE-ID/scene.splinecode" />
    </motion.div>
  );
}
容器使用Framer Motion动画,Spline处理3D内容:
jsx
import { motion } from 'framer-motion';
import Spline from '@splinetool/react-spline';

export default function AnimatedContainer() {
  return (
    <motion.div
      initial={{ opacity: 0, y: 50 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ duration: 0.8 }}
      style={{ width: '100%', height: '600px' }}
    >
      <Spline scene="https://prod.spline.design/YOUR-SCENE-ID/scene.splinecode" />
    </motion.div>
  );
}

Performance Optimization

性能优化

1. Enable On-Demand Rendering

1. 启用按需渲染

Render only when scene changes, not every frame:
jsx
<Spline
  scene="https://prod.spline.design/YOUR-SCENE-ID/scene.splinecode"
  renderOnDemand={true} // Default is true
/>
仅在场景变更时渲染,而非每帧都渲染:
jsx
<Spline
  scene="https://prod.spline.design/YOUR-SCENE-ID/scene.splinecode"
  renderOnDemand={true} // 默认值为true
/>

2. Optimize Scene in Spline Editor

2. 在Spline编辑器中优化场景

In Spline:
  • Reduce polygon count (use decimation)
  • Compress textures (lower resolution, use JPG over PNG)
  • Limit lights (2-3 lights maximum)
  • Use simple materials when possible
  • Enable LOD (Level of Detail) for distant objects
Spline内操作:
  • 减少多边形数量(使用减面工具)
  • 压缩纹理(降低分辨率,优先用JPG而非PNG)
  • 限制光源数量(最多2-3个光源)
  • 尽可能使用简单材质
  • 为远处对象启用LOD(细节层级)

3. Lazy Load Heavy Scenes

3. 懒加载重型场景

Use React.lazy() as shown in Pattern 6
使用模式6中提到的React.lazy()实现

4. Preload Critical Scenes

4. 预加载关键场景

jsx
import { useEffect } from 'react';
import Spline from '@splinetool/react-spline';

export default function PreloadedScene() {
  useEffect(() => {
    // Preload scene assets
    const link = document.createElement('link');
    link.rel = 'prefetch';
    link.href = 'https://prod.spline.design/YOUR-SCENE-ID/scene.splinecode';
    document.head.appendChild(link);
  }, []);

  return (
    <Spline scene="https://prod.spline.design/YOUR-SCENE-ID/scene.splinecode" />
  );
}
jsx
import { useEffect } from 'react';
import Spline from '@splinetool/react-spline';

export default function PreloadedScene() {
  useEffect(() => {
    // 预加载场景资源
    const link = document.createElement('link');
    link.rel = 'prefetch';
    link.href = 'https://prod.spline.design/YOUR-SCENE-ID/scene.splinecode';
    document.head.appendChild(link);
  }, []);

  return (
    <Spline scene="https://prod.spline.design/YOUR-SCENE-ID/scene.splinecode" />
  );
}

5. Mobile Optimizations

5. 移动端优化

  • Create separate mobile scenes with lower detail
  • Reduce canvas resolution on mobile
  • Disable shadows and reflections
  • Use simpler materials
jsx
<Spline
  scene={isMobile ? mobileSceneUrl : desktopSceneUrl}
  style={{
    width: '100%',
    height: isMobile ? '300px' : '600px'
  }}
/>
  • 单独制作低细节的移动端场景
  • 降低移动端的画布分辨率
  • 关闭阴影和反射效果
  • 使用更简单的材质
jsx
<Spline
  scene={isMobile ? mobileSceneUrl : desktopSceneUrl}
  style={{
    width: '100%',
    height: isMobile ? '300px' : '600px'
  }}
/>

Common Pitfalls and Solutions

常见问题与解决方案

Pitfall 1: Scene Not Loading

问题1: 场景加载失败

Problem: Spline component renders but scene doesn't appear
Solutions:
jsx
// ❌ Wrong: Invalid scene URL
<Spline scene="my-scene.splinecode" />

// ✅ Correct: Full URL from Spline export
<Spline scene="https://prod.spline.design/KFonZGtsoUXP-qx7/scene.splinecode" />

// Check for errors
function onLoad(app) {
  console.log('Scene loaded successfully', app);
}

<Spline scene={sceneUrl} onLoad={onLoad} />
Also Check:
  • Scene is published in Spline editor
  • Network tab shows successful file downloads
  • No CORS errors in console
问题描述: Spline组件渲染完成但场景不显示
解决方案:
jsx
// ❌ 错误: 无效的场景URL
<Spline scene="my-scene.splinecode" />

// ✅ 正确: 使用Spline导出的完整URL
<Spline scene="https://prod.spline.design/KFonZGtsoUXP-qx7/scene.splinecode" />

// 检查错误
function onLoad(app) {
  console.log('Scene loaded successfully', app);
}

<Spline scene={sceneUrl} onLoad={onLoad} />
其他检查项:
  • 场景已在Spline编辑器中发布
  • 网络面板显示文件下载成功
  • 控制台无CORS错误

Pitfall 2: Object References Lost After Re-render

问题2: 重渲染后对象引用丢失

Problem: Object refs become undefined after component updates
Solution:
jsx
// ❌ Wrong: Storing objects without proper refs
let myObject;

function onLoad(spline) {
  myObject = spline.findObjectByName('Cube'); // Lost on re-render
}

// ✅ Correct: Use React refs
const myObject = useRef();

function onLoad(spline) {
  myObject.current = spline.findObjectByName('Cube');
}
问题描述: 组件更新后对象引用变为undefined
解决方案:
jsx
// ❌ 错误: 没有用正确的ref存储对象
let myObject;

function onLoad(spline) {
  myObject = spline.findObjectByName('Cube'); // 重渲染后会丢失
}

// ✅ 正确: 使用React refs
const myObject = useRef();

function onLoad(spline) {
  myObject.current = spline.findObjectByName('Cube');
}

Pitfall 3: Performance Issues on Mobile

问题3: 移动端性能不佳

Problem: Scene runs slowly on mobile devices
Solutions:
jsx
// Create mobile-optimized version in Spline editor
// - Fewer polygons (< 50k triangles)
// - Smaller textures (512x512 or less)
// - No shadows or reflections
// - Simpler materials

// Load appropriate version
const isMobile = window.innerWidth < 768;
const sceneUrl = isMobile
  ? 'https://prod.spline.design/MOBILE-SCENE/scene.splinecode'
  : 'https://prod.spline.design/DESKTOP-SCENE/scene.splinecode';

<Spline scene={sceneUrl} renderOnDemand={true} />
问题描述: 场景在移动设备上运行卡顿
解决方案:
jsx
// 在Spline编辑器中制作移动端优化版本
// - 减少多边形数量(少于5万三角面)
// - 缩小纹理尺寸(512x512或更小)
// - 关闭阴影和反射
// - 使用简单材质

// 加载对应版本
const isMobile = window.innerWidth < 768;
const sceneUrl = isMobile
  ? 'https://prod.spline.design/MOBILE-SCENE/scene.splinecode'
  : 'https://prod.spline.design/DESKTOP-SCENE/scene.splinecode';

<Spline scene={sceneUrl} renderOnDemand={true} />

Pitfall 4: Events Not Firing

问题4: 事件不触发

Problem: Click or hover events don't trigger
Solutions:
jsx
// ❌ Wrong: Using wrong event name
<Spline onMouseDown={handler} /> // Not a Spline prop

// ✅ Correct: Use Spline event props
<Spline onSplineMouseDown={handler} />

// Also ensure object has events in Spline editor:
// 1. Select object in Spline
// 2. Add event in "Events" panel
// 3. Assign state transition or action
问题描述: 点击或悬停事件没有触发
解决方案:
jsx
// ❌ 错误: 使用错误的事件名称
<Spline onMouseDown={handler} /> // 不是Spline支持的属性

// ✅ 正确: 使用Spline专属事件属性
<Spline onSplineMouseDown={handler} />

// 同时确认Spline编辑器中对象已配置事件:
// 1. 在Spline中选中对象
// 2. 在「事件」面板中添加事件
// 3. 分配状态过渡或动作

Pitfall 5: Animation Not Triggering Programmatically

问题5: 程序化触发动画失败

Problem:
emitEvent()
doesn't trigger animation
Solutions:
jsx
// ❌ Wrong: Calling before scene loads
function triggerAnimation() {
  splineApp.current.emitEvent('mouseHover', 'Button'); // Error if not loaded
}

// ✅ Correct: Ensure scene is loaded
const [isLoaded, setIsLoaded] = useState(false);

function onLoad(app) {
  splineApp.current = app;
  setIsLoaded(true);
}

function triggerAnimation() {
  if (isLoaded && splineApp.current) {
    splineApp.current.emitEvent('mouseHover', 'Button');
  }
}

// Also verify in Spline editor:
// - Object has the correct name ('Button')
// - mouseHover event is configured
// - Event has action (state transition, etc.)
问题描述:
emitEvent()
没有触发动画
解决方案:
jsx
// ❌ 错误: 场景加载完成前就调用
function triggerAnimation() {
  splineApp.current.emitEvent('mouseHover', 'Button'); // 未加载时会报错
}

// ✅ 正确: 确保场景已加载完成
const [isLoaded, setIsLoaded] = useState(false);

function onLoad(app) {
  splineApp.current = app;
  setIsLoaded(true);
}

function triggerAnimation() {
  if (isLoaded && splineApp.current) {
    splineApp.current.emitEvent('mouseHover', 'Button');
  }
}

// 同时在Spline编辑器中确认:
// - 对象名称正确('Button')
// - 已配置mouseHover事件
// - 事件已关联动作(状态过渡等)

Pitfall 6: Hydration Errors in Next.js

问题6: Next.js中出现 hydration 错误

Problem: Mismatch between server and client render
Solution:
jsx
// ❌ Wrong: Using standard import in Next.js
import Spline from '@splinetool/react-spline';

// ✅ Correct: Use Next.js-specific import
import Spline from '@splinetool/react-spline/next';

// Or use dynamic import with ssr: false
import dynamic from 'next/dynamic';

const Spline = dynamic(
  () => import('@splinetool/react-spline'),
  { ssr: false }
);
问题描述: 服务端和客户端渲染内容不匹配
解决方案:
jsx
// ❌ 错误: 在Next.js中使用标准导入
import Spline from '@splinetool/react-spline';

// ✅ 正确: 使用Next.js专属导入
import Spline from '@splinetool/react-spline/next';

// 或使用关闭SSR的动态导入
import dynamic from 'next/dynamic';

const Spline = dynamic(
  () => import('@splinetool/react-spline'),
  { ssr: false }
);

Resources

资源

Official Documentation

官方文档

Spline Editor

Spline 编辑器

Learning Resources

学习资源

Export Formats

导出格式

  • React component (via
    @splinetool/react-spline
    )
  • Vanilla JavaScript (Web Code API)
  • GLTF/GLB (for Three.js, Babylon.js)
  • USDZ (for Apple AR)
  • STL (for 3D printing)
  • Video/GIF (for marketing)
  • React组件(通过
    @splinetool/react-spline
  • 原生JavaScript(Web Code API)
  • GLTF/GLB(适用于Three.js、Babylon.js)
  • USDZ(适用于Apple AR)
  • STL(适用于3D打印)
  • 视频/GIF(适用于营销场景)

Related Skills

相关技能

  • threejs-webgl: For code-first 3D development with more control
  • react-three-fiber: For building 3D scenes with React and JSX
  • babylonjs-engine: Alternative 3D engine with editor workflow
  • motion-framer: For animating Spline containers and UI elements
  • gsap-scrolltrigger: For scroll-driven Spline animations
  • figma-dev-mode: For design-to-code workflow (similar visual approach)
  • threejs-webgl: 适合需要更多控制力的代码优先3D开发
  • react-three-fiber: 适合用React和JSX构建3D场景
  • babylonjs-engine: 带编辑器工作流的替代3D引擎
  • motion-framer: 用于为Spline容器和UI元素添加动画
  • gsap-scrolltrigger: 用于实现滚动驱动的Spline动画
  • figma-dev-mode: 用于设计转代码工作流(类似的可视化思路)

Scripts

脚本

This skill includes utility scripts:
  • project_generator.py
    - Generate Spline + React starter projects
  • component_builder.py
    - Build Spline component wrappers with events
Run scripts from the skill directory:
bash
./scripts/project_generator.py
./scripts/component_builder.py
本技能包含实用脚本:
  • project_generator.py
    - 生成Spline + React 启动项目
  • component_builder.py
    - 构建带事件的Spline组件封装
从技能目录运行脚本:
bash
./scripts/project_generator.py
./scripts/component_builder.py

Assets

资源文件

Starter templates and examples:
  • starter_spline/
    - Complete React + Spline template
  • examples/
    - Real-world integration patterns
启动模板和示例:
  • starter_spline/
    - 完整的React + Spline模板
  • examples/
    - 实际业务集成模式示例