mcpField
S
spline-interactive

spline-interactive

github.com/freshtechbro设计与 UI1.2k2.8k 次安装49 周前更新
代码仓库

关于 spline-interactive

面向 3D 创作者和开发者的 Spline 交互式 3D 设计指导,介绍可视化建模、状态动画、事件交互与场景导出。内容也涵盖 React 集成、移动端优化及常见故障处理。

主要功能

  1. 01可视化 3D 建模与场景组织
  2. 02基于状态的动画与交互事件
  3. 03导出 React、网页代码及模型
  4. 04React 场景嵌入与对象控制
  5. 05加载与移动端性能优化

适用场景

  1. 01制作交互式产品展示
  2. 02在营销页面嵌入 3D 场景
  3. 03构建产品配置器原型
  4. 04将场景导出到 React 项目

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/freshtechbro/claudedesignskills --skill spline-interactive

安装后在 Claude Code 中输入/spline-interactive确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

assets/
README.md
references/
api_reference.md
scripts/
component_builder.py
project_generator.py

详细介绍

Spline 交互式设计与动画平台——基于浏览器的 3D 工具

概述

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 开发者

核心概念

1. 场景结构

Spline 将项目组织为场景,场景包含:

  • 对象:3D 模型、形状、文本、图像
  • 灯光:方向光、点光源、聚光灯
  • 摄像机:轨道、透视、正交
  • 事件:交互触发器
  • 状态:动画关键帧
2. 组件系统

可重复使用的元素,可以:

  • 从任意对象或群组创建
  • 多次实例化
  • 在所有实例中统一更新
  • 按实例单独覆盖
3. 基于状态的动画

动画定义为状态之间的转换:

  • 默认状态:初始外观
  • 附加状态:目标外观
  • 事件:触发状态转换的条件
  • 转换:时长、缓动、属性
4. 交互模型

事件驱动系统包含:

  • 事件:用户操作或场景触发器
  • 条件:逻辑门(if/else)
  • 操作:状态变更、音频、场景切换
  • 变量:来自 API 或用户输入的动态数据
5. 导出选项

多种部署方式:

  • 公开 URL:可直接分享的链接
  • 代码导出:React 组件或原生 JS
  • Spline Viewer:嵌入式 iframe
  • 自托管:下载并独立托管

常见模式

模式 1:React 基础集成

适用场景:在 React 应用中嵌入 Spline 场景

实现:

# Installation
npm install @splinetool/react-spline @splinetool/runtime
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 导出对话框
  • 组件填满父容器
  • 自动处理加载和渲染
模式 2:事件处理与对象交互

适用场景:响应用户对特定对象的点击

实现:

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}
    />
  );
}

可用事件处理程序:

  • onSplineMouseDown - 按下对象上的鼠标按键
  • onSplineMouseUp - 释放鼠标按键
  • onSplineMouseHover - 鼠标悬停在对象上
  • onSplineKeyDown - 按下键盘按键
  • onSplineKeyUp - 释放键盘按键
  • onSplineStart - 场景加载并启动
  • onSplineLookAt - 摄像机注视事件
  • onSplineFollow - 摄像机跟随事件
  • onSplineScroll - 滚动事件
模式 3:以编程方式控制对象

适用场景:通过 React 代码修改对象属性

实现:

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>
  );
}

可修改的对象属性:

  • position - { x, y, z }
  • rotation - { x, y, z }(弧度)
  • scale - { x, y, z }
  • material.color - 颜色十六进制值
  • visible - 布尔值
模式 4:触发 Spline 动画

用例:从 React 触发 Spline 中定义的动画

实现:

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>
  );
}

可用事件类型:

  • mouseDown - 鼠标按下
  • mouseHover - 悬停效果
  • mouseUp - 鼠标松开
  • keyDown - 按下按键
  • keyUp - 松开按键
  • start - 开始事件
  • lookAt - 注视摄像机
  • follow - 跟随摄像机
模式 5:使用 SSR 集成 Next.js

用例:在 Next.js 中使用 Spline,享受服务器端渲染的优势

实现:

// 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
模式 6:延迟加载以提升性能

用例:延迟加载 Spline,直到需要时再加载

实现:

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>
  );
}

优势:

  • 减小初始包大小
  • 提升页面加载性能
  • 显示自定义加载界面
模式 7:响应式 Spline 场景

用例:让 Spline 场景适配不同屏幕尺寸

实现:

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>
  );
}

替代方案(单个场景):

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}
    />
  );
}

集成模式

与 Three.js(threejs-webgl)集成

对于高级用例,可将 Spline 设计的资源与 Three.js 代码结合使用:

  1. 从 Spline 导出:使用 GLTF/GLB 导出
  2. 在 Three.js 中导入:使用 GLTFLoader 加载
  3. 通过代码增强:添加自定义着色器、物理效果或特效
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
});
与 GSAP(gsap-scrolltrigger)集成

滚动时触发 Spline 动画:

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>
  );
}
与 Framer Motion(motion-framer)集成

使用 Framer Motion 为容器添加动画,同时由 Spline 处理 3D 内容:

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>
  );
}

性能优化

1. 启用按需渲染

仅在场景变化时渲染,而不是每帧都渲染:

<Spline
  scene="https://prod.spline.design/YOUR-SCENE-ID/scene.splinecode"
  renderOnDemand={true} // Default is true
/>
2. 在 Spline 编辑器中优化场景

在 Spline 中:

  • 减少多边形数量(使用简化)
  • 压缩纹理(降低分辨率,优先使用 JPG 而非 PNG)
  • 限制光源数量(最多 2-3 个)
  • 尽可能使用简单材质
  • 为远处物体启用 LOD(细节层次)
3. 延迟加载大型场景

使用模式 6 中展示的 React.lazy()

4. 预加载关键场景
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" />
  );
}
5. 移动设备优化
  • 创建细节较少的独立移动端场景
  • 降低移动设备上的画布分辨率
  • 禁用阴影和反射
  • 使用更简单的材质
<Spline
  scene={isMobile ? mobileSceneUrl : desktopSceneUrl}
  style={{
    width: '100%',
    height: isMobile ? '300px' : '600px'
  }}
/>

常见问题及解决方案

问题 1:场景未加载

问题:Spline 组件已渲染,但场景没有显示

解决方案:

// ❌ 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} />

另请检查:

  • 场景已在 Spline 编辑器中发布
  • Network 标签页显示文件已成功下载
  • 控制台中没有 CORS 错误
问题 2:重新渲染后对象引用丢失

问题:组件更新后,对象引用变为 undefined

解决方案:

// ❌ 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');
}
问题 3:移动设备上的性能问题

问题:场景在移动设备上运行缓慢

解决方案:

// 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} />
问题 4:事件未触发

问题:点击或悬停事件未触发

解决方案:

// ❌ 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
问题 5:未以编程方式触发动画

问题:emitEvent() 未触发动画

解决方案:

// ❌ 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.)
问题 6:Next.js 中的水合错误

问题:服务器端渲染与客户端渲染不匹配

解决方案:

// ❌ 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 }
);

资源

官方文档
Spline 编辑器
学习资源
导出格式
  • React 组件(通过 @splinetool/react-spline)
  • 原生 JavaScript(Web Code API)
  • GLTF/GLB(用于 Three.js、Babylon.js)
  • USDZ(用于 Apple AR)
  • STL(用于 3D 打印)
  • 视频/GIF(用于营销)

相关技能

  • threejs-webgl:适用于掌控度更高的代码优先 3D 开发
  • react-three-fiber:适用于使用 React 和 JSX 构建 3D 场景
  • babylonjs-engine:可通过编辑器工作流使用的替代 3D 引擎
  • motion-framer:适用于为 Spline 容器和 UI 元素添加动画
  • gsap-scrolltrigger:适用于由滚动驱动的 Spline 动画
  • figma-dev-mode:适用于设计转代码工作流(视觉方法类似)

脚本

此技能包含实用脚本:

  • project_generator.py - 生成 Spline + React 入门项目
  • component_builder.py - 构建带事件的 Spline 组件包装器

从技能目录运行脚本:

./scripts/project_generator.py
./scripts/component_builder.py

资源

入门模板和示例:

  • starter_spline/ - 完整的 React + Spline 模板
  • examples/ - 真实场景中的集成模式

评论

支持 Markdown