spline-interactive by freshtechbro/claudedesignskills
npx skills add https://github.com/freshtechbro/claudedesignskills --skill spline-interactiveSpline 是一个基于浏览器的 3D 设计和动画平台,使创作者无需代码或专业软件知识即可构建交互式 3D 体验。它提供了一个协作式可视化编辑器,用于跨多个平台设计、动画和导出 3D 场景。
主要特性:
何时使用此技能:
替代方案:
Spline 将项目组织为包含以下内容的场景:
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
可重复使用的元素,可以:
动画被定义为状态之间的过渡:
事件驱动系统包含:
多种部署方法:
使用场景:在 React 应用程序中嵌入 Spline 场景
实现方式:
# 安装
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>
);
}
关键点:
使用场景:响应用户对特定对象的点击
实现方式:
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 - 滚动事件使用场景:从 React 代码修改对象属性
实现方式:
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}>旋转</button>
<button onClick={changeColor}>更改颜色</button>
<button onClick={moveProduct}>移动</button>
</div>
</div>
);
}
可以修改的对象属性:
position - { x, y, z }rotation - { x, y, z }(弧度)scale - { x, y, z }material.color - 颜色十六进制值visible - 布尔值使用场景:从 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() {
// 在 '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}>悬停效果</button>
<button onClick={triggerClickAnimation}>点击效果</button>
<button onClick={reverseAnimation}>反向</button>
</div>
);
}
可用的事件类型:
mouseDown - 鼠标按下mouseHover - 悬停效果mouseUp - 鼠标释放keyDown - 按键按下keyUp - 按键释放start - 开始事件lookAt - 注视相机follow - 跟随相机使用场景:在 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>
);
}
优势:
使用场景:延迟加载 Spline 直到需要时
实现方式:
import React, { Suspense } from 'react';
// 动态导入 Spline
const Spline = React.lazy(() => import('@splinetool/react-spline'));
export default function LazyScene() {
return (
<div>
<h1>我的页面内容</h1>
<Suspense fallback={<div>加载 3D 场景中...</div>}>
<div style={{ width: '100%', height: '500px' }}>
<Spline scene="https://prod.spline.design/YOUR-SCENE-ID/scene.splinecode" />
</div>
</Suspense>
<p>下方更多内容</p>
</div>
);
}
优势:
使用场景:使 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) {
// 在移动设备上缩小
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}
/>
);
}
对于高级用例,将 Spline 设计的资源与 Three.js 代码结合:
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
const loader = new GLTFLoader();
loader.load('spline-model.glb', (gltf) => {
scene.add(gltf.scene);
// 添加自定义行为
});
在滚动时触发 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>
);
}
在 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>
);
}
仅在场景更改时渲染,而不是每一帧:
<Spline
scene="https://prod.spline.design/YOUR-SCENE-ID/scene.splinecode"
renderOnDemand={true} // 默认为 true
/>
在 Spline 中:
如模式 6 所示使用 React.lazy()
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" />
);
}
创建细节度较低的单独移动端场景
在移动端降低画布分辨率
禁用阴影和反射
使用更简单的材质
<Spline scene={isMobile ? mobileSceneUrl : desktopSceneUrl} style={{ width: '100%', height: isMobile ? '300px' : '600px' }} />
问题:Spline 组件渲染但场景未显示
解决方案:
// ❌ 错误:无效的场景 URL
<Spline scene="my-scene.splinecode" />
// ✅ 正确:来自 Spline 导出的完整 URL
<Spline scene="https://prod.spline.design/KFonZGtsoUXP-qx7/scene.splinecode" />
// 检查错误
function onLoad(app) {
console.log('场景加载成功', app);
}
<Spline scene={sceneUrl} onLoad={onLoad} />
还需检查:
问题:组件更新后对象引用变为 undefined
解决方案:
// ❌ 错误:未使用正确的引用存储对象
let myObject;
function onLoad(spline) {
myObject = spline.findObjectByName('Cube'); // 重新渲染时丢失
}
// ✅ 正确:使用 React 引用
const myObject = useRef();
function onLoad(spline) {
myObject.current = spline.findObjectByName('Cube');
}
问题:场景在移动设备上运行缓慢
解决方案:
// 在 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} />
问题:点击或悬停事件未触发
解决方案:
// ❌ 错误:使用了错误的事件名称
<Spline onMouseDown={handler} /> // 不是 Spline 属性
// ✅ 正确:使用 Spline 事件属性
<Spline onSplineMouseDown={handler} />
// 同时确保对象在 Spline 编辑器中设置了事件:
// 1. 在 Spline 中选择对象
// 2. 在“事件”面板中添加事件
// 3. 分配状态转换或动作
问题:emitEvent() 未触发动画
解决方案:
// ❌ 错误:在场景加载前调用
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 事件已配置
// - 事件具有动作(状态转换等)
问题:服务器端和客户端渲染不匹配
解决方案:
// ❌ 错误:在 Next.js 中使用标准导入
import Spline from '@splinetool/react-spline';
// ✅ 正确:使用 Next.js 特定导入
import Spline from '@splinetool/react-spline/next';
// 或使用带有 ssr: false 的动态导入
import dynamic from 'next/dynamic';
const Spline = dynamic(
() => import('@splinetool/react-spline'),
{ ssr: false }
);
@splinetool/react-spline)此技能包含实用脚本:
project_generator.py - 生成 Spline + React 入门项目component_builder.py - 构建带有事件的 Spline 组件包装器从技能目录运行脚本:
./scripts/project_generator.py
./scripts/component_builder.py
入门模板和示例:
starter_spline/ - 完整的 React + Spline 模板examples/ - 真实世界的集成模式每周安装量
112
代码仓库
GitHub 星标数
11
首次出现
2026年2月27日
安全审计
安装于
opencode112
kimi-cli110
gemini-cli110
github-copilot110
amp110
cline110
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 :
When to Use This Skill :
Alternatives :
Spline organizes projects into scenes containing:
Reusable elements that can be:
Animations are defined as transitions between states:
Event-driven system with:
Multiple deployment methods:
Use Case : Embed a Spline scene in a React application
Implementation :
# 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>
);
}
Key Points :
Use Case : Respond to user clicks on specific objects
Implementation :
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 objectonSplineMouseUp - Mouse releaseonSplineMouseHover - Mouse over objectonSplineKeyDown - Keyboard pressonSplineKeyUp - Keyboard releaseonSplineStart - Scene loaded and startedonSplineLookAt - Camera look-at eventonSplineFollow - Camera follow eventonSplineScroll - Scroll eventUse Case : Modify object properties from React code
Implementation :
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 valuevisible - BooleanUse Case : Trigger animations defined in Spline from React
Implementation :
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 pressmouseHover - Hover effectmouseUp - Mouse releasekeyDown - Key presskeyUp - Key releasestart - Start eventlookAt - Look at camerafollow - Follow cameraUse Case : Use Spline in Next.js with server-side rendering benefits
Implementation :
// 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 :
Use Case : Defer Spline loading until needed
Implementation :
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 :
Use Case : Make Spline scenes adapt to different screen sizes
Implementation :
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):
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}
/>
);
}
For advanced use cases, combine Spline-designed assets with Three.js code:
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
});
Trigger Spline animations on scroll:
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>
);
}
Animate container while Spline handles 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>
);
}
Render only when scene changes, not every frame:
<Spline
scene="https://prod.spline.design/YOUR-SCENE-ID/scene.splinecode"
renderOnDemand={true} // Default is true
/>
In Spline :
Use React.lazy() as shown in Pattern 6
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" />
);
}
Create separate mobile scenes with lower detail
Reduce canvas resolution on mobile
Disable shadows and reflections
Use simpler materials
<Spline scene={isMobile ? mobileSceneUrl : desktopSceneUrl} style={{ width: '100%', height: isMobile ? '300px' : '600px' }} />
Problem : Spline component renders but scene doesn't appear
Solutions :
// ❌ 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 :
Problem : Object refs become undefined after component updates
Solution :
// ❌ 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');
}
Problem : Scene runs slowly on mobile devices
Solutions :
// 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} />
Problem : Click or hover events don't trigger
Solutions :
// ❌ 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
Problem : emitEvent() doesn't trigger animation
Solutions :
// ❌ 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.)
Problem : Mismatch between server and client render
Solution :
// ❌ 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 }
);
@splinetool/react-spline)This skill includes utility scripts:
project_generator.py - Generate Spline + React starter projectscomponent_builder.py - Build Spline component wrappers with eventsRun scripts from the skill directory:
./scripts/project_generator.py
./scripts/component_builder.py
Starter templates and examples:
starter_spline/ - Complete React + Spline templateexamples/ - Real-world integration patternsWeekly Installs
112
Repository
GitHub Stars
11
First Seen
Feb 27, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykWarn
Installed on
opencode112
kimi-cli110
gemini-cli110
github-copilot110
amp110
cline110
前端设计技能指南:避免AI垃圾美学,打造独特生产级界面
46,600 周安装