この記事の概要
unicorn.studioというツールがあります。
ノーコードでWebGLを扱えて、インタラクティブなエフェクトやモーションを簡単に作ることができます。
適当に触っていても面白い表現が作れて、非常に魅力的なツールです。
ただ、作ったものを実際にサイト上に載せるのにはやや苦労しました(特にReactでは)。
というわけでコピー&ペーストにて動かせるように記事にします。
unicorn.studioの特徴
いきなり実装の仕方から入るのも不親切なので、少しだけunicorn.studioの特徴を記載します。
エフェクトが豊富
- 標準エフェクト
- ディストーション、ブラー、ライトなど、様々な種類のエフェクトが搭載されている
- 公式サイトでは「35+ effects」という表記ながら、実際に数えたら50あった
- 徐々に増えているのかもしれない
- 自分で書くカスタムエフェクト
- シェーダーが書ける場合、自分で書くことも可能
モーションやインタラクションをつけるのが簡単
- 登場、スクロール、マウスオーバーをトリガーにしたモーション
- マウスの動きに追従した変化
この手のライブラリの中では軽い
- gzipped時で36kB
- 役割や機能の豊富さが違うので単純比較すべきではないものの、参考程度にthree.jsは167.9kB、p5.jsは244.6kB
FramerとWebflowなどでの利用が簡単
- ノーコードな技術スタック(?)に焦点を当てていそう
- それもあってか自前で実装するサイトへのサポートはやや手薄な印象
画像や動画としての書き出しも可能
- サイズや拡張子、フレームレートなどが選択できる
- インタラクティブ性はなくなってしまうものの、手軽に使えるという意味では嬉しい機能
下準備
エディタ画面右上のExport
からEmbed
を開くとProject ID
があります。
コードの中でこれを使うのでコピーしておきます。
実装
素のHTML上で使用する場合と、Reactで使用する場合の両方を記載します。
HTML
最低限ならこの3ファイルで良いです。
(main.js
の中身も1行しかないので直接HTMLに書いても良いですが、さすがにそうはしないだろう、ということで3ファイル用意しています。)
.
├── index.html
├── main.js
└── style.css
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="style.css" />
<script
src="https://cdn.unicorn.studio/v1.3.2/unicornStudio.umd.js"
defer
></script>
<script src="main.js" defer></script>
</head>
<body>
<div
data-us-project="YOUR_PROJECT_ID"
style="width: 100%; height: 100%"
></div>
<!-- お好きな内容 -->
</body>
</html>
UnicornStudio.init();
CSSはお好きに書いてもらえれば大丈夫です。
重要なのは以下の3点です。
- CDNにあるunicron.studioのコードを使う
-
data-us-project
にProject IDを記載する -
init()
する
React
Viteのcreate-vite
でReactプロジェクトを作ったという前提での記載です。
.
├── README.md
├── index.html
├── package-lock.json
├── package.json
├── public
├── src
│ ├── App.css
│ ├── App.tsx
│ ├── components
│ │ └── UnicornEmbed.tsx
│ ├── hooks
│ │ └── useUnicornStudio.ts
│ ├── index.css
│ ├── main.tsx
│ └── vite-env.d.ts
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
projectId
を渡して描画できるコンポーネントを作成します。
import { useRef } from "react";
interface UnicornEmbedProps {
projectId: string;
}
export const UnicornEmbed: React.FC<UnicornEmbedProps> = ({ projectId }) => {
const containerRef = useRef<HTMLDivElement>(null);
return (
<div
ref={containerRef}
data-us-project={projectId}
style={{ width: "100%", height: "100%" }}
/>
);
};
1ページで複数回UnicornEmbed
を使うかもしれないと考えて、hookを作成します。
import { useEffect } from "react";
declare global {
interface Window {
UnicornStudio: {
init(): Promise<void>;
destroy(): void;
};
}
}
let isInitialized = false;
export const useUnicornStudio = () => {
useEffect(() => {
if (isInitialized) return;
if (!window.UnicornStudio) {
window.UnicornStudio = {
init: () => Promise.resolve(),
destroy: () => {},
};
const script = document.createElement("script");
script.src = "https://cdn.unicorn.studio/v1.3.2/unicornStudio.umd.js";
script.onload = () => {
window.UnicornStudio.init();
isInitialized = true;
};
document.head.appendChild(script);
}
return () => {
if (isInitialized) {
window.UnicornStudio.destroy();
isInitialized = false;
}
};
}, []);
};
あとは、今作った2つの機構を使えば大丈夫です。
import "./App.css";
import { UnicornEmbed } from "./components/UnicornEmbed";
import { useUnicornStudio } from "./hooks/useUnicornStudio";
function App() {
useUnicornStudio();
return (
<>
<UnicornEmbed projectId="YOUR_PROJECT_ID" />
{/* お好きな内容 */}
</>
);
}
export default App;