Embed Guide
Embedding is easy. Unicorn.studio uses a small (38kb gzipped) JavaScript library to execute your scenes with several implementation options. See the library on GitHub.
iFrame is not recommended for production sites
Framer Component
- Copy this component link:
https://framer.com/m/UnicornStudioEmbed-wWy9.js
- Paste into your Framer project
- Paste your scene's Project ID into the first field
- Done!
Additional details:
- You scene won't render in edit mode, preview or publish to see it action.
- If your scene isn't updating, it could be the Framer cache. See more below.
- If you have the Legend plan, you can paste your exported code into "Project JSON". This will make it load faster.
- If you need to update your library version, right click the component and select "Unlink". You can see the library link inside the code. Update the version in the link to match the latest version.
Webflow
-
In Site Settings > Custom Code, add to footer:
<script type="text/javascript">!function(){if(!window.UnicornStudio){window.UnicornStudio={isInitialized:!1};var i=document.createElement("script");i.src="https://cdn.jsdelivr.net/gh/hiunicornstudio/unicornstudio.js@v1.4.26/dist/unicornStudio.umd.js",i.onload=function(){window.UnicornStudio.isInitialized||(UnicornStudio.init(),window.UnicornStudio.isInitialized=!0)},(document.head || document.body).appendChild(i)}}();</script>
-
Choose the element you want to embed your scene in and click on the "settings" tab.
- Add a new "Custom Attribute". For name put
data-us-project
and for value add your project ID. - You may add additional attributes to customize your scene using the settings defined below.
The container div you add data-us-project
to must have a defined width and height.
Using code export
You can also use the data-us-project-src
attribute to point to a hosted project JSON file. This will make it load faster.
- Rename your code JSON to
[your-file-name].json.txt
- Upload it to your assets library
- Use the menu to copy link and paste it as the value for
data-us-project-src
Wix
- In your Site Settings menu, click Custom Code in the Advanced section
- Click + Add Custom Code
- Paste in the following script:
<script type="text/javascript">!function(){if(!window.UnicornStudio){window.UnicornStudio={isInitialized:!1};var i=document.createElement("script");i.src="https://cdn.jsdelivr.net/gh/hiunicornstudio/unicornstudio.js@v1.4.26/dist/unicornStudio.umd.js",i.onload=function(){window.UnicornStudio.isInitialized||(UnicornStudio.init(),window.UnicornStudio.isInitialized=!0)},(document.head || document.body).appendChild(i)}}();</script>
- Name it "Unicorn Studio SDK" (or whatever you want)
- Select All pages under "Add Code to Pages"
- Choose Head under "Place Code in"
- Click Apply
- In the Wix Editor, add an HTML Embed element where you want your scene to appear
- Click on the HTML Embed element and select Enter Code
- Paste your scene HTML (see "Example implementation" below)
- Click Update and Save
Figma Sites
- Create a new "Make" code layer
- Paste in the following code:
import { defineProperties } from "figma:react"; 'use client'; import { useEffect, useRef, useState } from 'react'; export type UnicornSceneProps = { projectId?: string; jsonFilePath?: string; width?: number | string; height?: number | string; scale?: number; dpi?: number; fps?: number; altText?: string; ariaLabel?: string; className?: string; lazyLoad?: boolean; }; export default function UnicornScene({ projectId, jsonFilePath, width = "100%", height = "100%", scale = 1, dpi = 1.5, fps = 60, altText = "Unicorn Scene", ariaLabel = altText, className = "", lazyLoad = false, }: UnicornSceneProps) { const elementRef = useRef<HTMLDivElement>(null); const sceneRef = useRef<{ destroy: () => void } | null>(null); const [error, setError] = useState<string | null>(null); const scriptId = useRef(`us-data-${Math.random().toString(36).slice(2)}`); useEffect(() => { if (typeof window === 'undefined') return; const initializeScript = (callback: () => void) => { const version = '1.4.26'; const existingScript = document.querySelector( 'script[src^="https://cdn.jsdelivr.net/gh/hiunicornstudio/unicornstudio.js"]' ); if (existingScript) { if ((window as Window & { UnicornStudio?: unknown }).UnicornStudio) { callback(); } else { existingScript.addEventListener('load', callback); } return; } const script = document.createElement('script'); script.src = `https://cdn.jsdelivr.net/gh/hiunicornstudio/unicornstudio.js@v${version}/dist/unicornStudio.umd.js`; script.async = true; script.onload = () => { callback(); }; script.onerror = () => setError('Failed to load UnicornStudio script'); document.body.appendChild(script); }; const initializeScene = async () => { if (!elementRef.current) return; if (jsonFilePath) { elementRef.current.setAttribute( "data-us-project-src", `${jsonFilePath}` ); } else if (projectId) { const [cleanProjectId, query] = projectId.split("?"); const production = query?.includes("production"); elementRef.current.setAttribute('data-us-project', cleanProjectId); if (production) { elementRef.current.setAttribute("data-us-production", "1"); } } else { throw new Error('No project ID or JSON file path provided'); } interface UnicornStudioType { init: (config: { scale: number; dpi: number }) => Promise<Array<{ element: HTMLElement; destroy: () => void; contains?: (element: HTMLElement | null) => boolean; }>>; } const UnicornStudio = (window as Window & { UnicornStudio?: UnicornStudioType }).UnicornStudio; if (!UnicornStudio) { throw new Error('UnicornStudio not found'); } if (sceneRef.current?.destroy) { sceneRef.current.destroy(); } await UnicornStudio?.init({ scale, dpi, }).then((scenes) => { const ourScene = scenes.find( (scene) => scene.element === elementRef.current || scene.element.contains(elementRef.current) ); if (ourScene) { sceneRef.current = ourScene; } }); }; initializeScript(() => { void initializeScene(); }); return () => { if (sceneRef.current?.destroy) { sceneRef.current.destroy(); sceneRef.current = null; } if (jsonFilePath) { const script = document.getElementById(scriptId.current); script?.remove(); } }; }, [projectId, jsonFilePath, scale, dpi]); return ( <div ref={elementRef} style={{ width: typeof width === 'number' ? `${width}px` : width, height: typeof height === 'number' ? `${height}px` : height }} className={`relative ${className}`} role="img" aria-label={ariaLabel} data-us-dpi={dpi} data-us-scale={scale} data-us-fps={fps} data-us-alttext={altText} data-us-arialabel={ariaLabel} data-us-lazyload={lazyLoad ? "true" : ""} > {error && <div className="text-red-500">{error}</div>} </div> ); } defineProperties(UnicornScene, { projectId: { label: "Project Id", type: "string", defaultValue: "Add your project Id", }, scale: { type: 'number', label: "Scale", defaultValue: 1 }, dpi: { type: 'number', label: "DPI", defaultValue: 1.5 }, fps: { type: 'number', label: "FPS", defaultValue: 60 } });
- Paste your Project ID into the field
- That's it!
SDK parameters
The SDK allows native integration with coded sites or Webflow. Configure using data-us-[param]
attributes:
Parameter | Description |
---|---|
data-us-project |
Points to your scene project id |
data-us-project-src |
Path to hosted project JSON |
data-us-scale |
Canvas rendering scale (0.25-1) |
data-us-dpi |
Scene resolution (default: 1.5) |
data-us-lazyload |
Defers resource creation until viewport entry |
data-us-production |
Enables CDN serving |
data-us-fps |
Sets render loop FPS |
data-us-disablemobile |
Disables mobile mouse/scroll interactions |
data-us-fixed |
Makes the scene behaved like a fixed element |
data-us-alttext |
SEO alt text |
data-us-arialabel |
Accessibility label |
Do not use both data-us-project
and data-us-project-src
. You must choose one or the other.
Example implementation:
<div
data-us-project="YOUR_PROJECT_EMBED_ID"
data-us-scale="1"
data-us-dpi="1.5"
data-us-lazyload="true"
data-us-production="true"
data-us-alttext="Welcome to Unicorn Studio"
data-us-arialabel="This is a canvas scene"
></div>
Native Code Implementation
For modern web apps:
// Import
import * as UnicornStudio from './path/to/unicornStudio.umd.js'
// Component mount
UnicornStudio.init().then(scenes => {
// Scenes are ready
}).catch((err) => {
console.error(err);
});
// Component unmount
UnicornStudio.destroy();
See the documentation on GitHub
React/Next.js example here.
Advanced Topics
Caching Behavior
Use the update
query parameter to bypass caching:
Production Mode
Enable production mode for optimal performance:
- Use data-us-production="true"
in HTML
- Add ?production=true
to project ID in Framer
- Enable "production mode" when publishing
Note: Updates take 1-2 minutes to propagate through the CDN.