Metastar Dashboard대시보드

Metastar AI NPC SDK

Add a talking AI character to your own Babylon.js or three.js web world with a few lines of script. Visitors can talk to it by voice or text; it answers aloud with lip sync. You don't need your own LLM, speech, or voice API keys — they stay on Metastar's servers.

내 Babylon.js 또는 three.js 웹 월드에 스크립트 몇 줄로 말하는 AI 캐릭터를 넣을 수 있습니다. 방문자가 음성이나 글로 말을 걸면 NPC 가 입 모양에 맞춰 소리로 답합니다. LLM·음성 인식·음성 합성 API 키를 직접 준비할 필요가 없습니다. 키는 모두 메타스타 서버에만 있습니다.

Free for site operators. You pay nothing to add Metastar AI NPCs to your site: no setup fee, no usage fee, no card required. Each account has a safety cap on usage; if you reach it, we can raise it at no cost. Just write to contact@metastar.world.
운영자에게는 무료입니다. 내 사이트에 메타스타 AI NPC 를 넣는 데 비용이 들지 않습니다. 설치비·사용료가 없고 카드 등록도 필요 없습니다. 계정마다 안전장치로 사용 한도가 있으며, 한도에 닿으면 비용 없이 올려 드립니다. contact@metastar.world 로 알려 주세요.

Quick start (about 5 minutes)빠른 시작 (약 5분)

  1. Open the dashboard, sign in with a Metastar (Google) account and press Register as operator — it is approved instantly. Then register your site: enter the domain(s) your world is served from (for example https://example.com, or http://localhost:8080 while developing). You get a public key (pk_live_…).
  2. Create an NPC: name, avatar, voice, a short persona, and one or more greeting lines.
  3. Copy the embed code from the dashboard and for your engine — Babylon.js or three.js — and paste it into your page after your scene is created.
  1. 대시보드를 열고 메타스타(구글) 계정으로 로그인한 뒤 운영자 등록을 누릅니다(바로 승인됩니다). 이어서 사이트를 등록합니다. 월드가 열리는 도메인을 입력하면(예: https://example.com, 개발 중에는 http://localhost:8080) 공개 키(pk_live_…)가 나옵니다.
  2. NPC 를 만듭니다: 이름, 아바타, 목소리, 짧은 페르소나, 인사말 한 줄 이상.
  3. 대시보드의 삽입 코드를 쓰는 엔진(Babylon.js 또는 three.js)에 맞게 복사해, 씬을 만든 다음 위치에 붙여 넣습니다.

Babylon.js

For a Babylon.js world use npc.js. Load Babylon.js and its glTF loader first, then the SDK.

Babylon.js 월드에서는 npc.js 를 씁니다. Babylon.js 와 glTF 로더를 먼저 불러온 다음 SDK 를 불러옵니다.

Embed code (Babylon.js)삽입 코드 (Babylon.js)

<script src="https://metastar.world/static/sdk/v0/npc.js"></script>
<script>
  MetastarNPC.init({
    publicKey: "pk_live_xxxxxxxx",          // from the dashboard
    scene: scene,                           // your BABYLON.Scene
    npcId: "npc_xxxxxxxx",                  // from the dashboard
    position: { x: 0, y: 0, z: 3 },         // where the NPC stands (feet)
    rotationY: Math.PI,                     // 0 faces +Z, Math.PI faces -Z
    getPlayerPosition: function () { return scene.activeCamera.position; }
  });
</script>

Complete minimal page (Babylon.js)전체 최소 예제 (Babylon.js)

Save this as index.html, replace the two IDs, and serve it from a domain you registered (for example python -m http.server 8080 → http://localhost:8080).

아래를 index.html 로 저장하고 두 ID 만 바꾼 뒤, 등록한 도메인에서 여세요(예: python -m http.server 8080 → http://localhost:8080).

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style>html, body, canvas { margin: 0; width: 100%; height: 100%; display: block; }</style>
  <script src="https://cdn.babylonjs.com/babylon.js"></script>
  <script src="https://cdn.babylonjs.com/loaders/babylonjs.loaders.min.js"></script>
  <script src="https://metastar.world/static/sdk/v0/npc.js"></script>
</head>
<body>
<canvas id="c"></canvas>
<script>
  var canvas = document.getElementById("c");
  var engine = new BABYLON.Engine(canvas, true);
  var scene = new BABYLON.Scene(engine);
  var camera = new BABYLON.UniversalCamera("cam", new BABYLON.Vector3(0, 1.6, -2), scene);
  camera.setTarget(new BABYLON.Vector3(0, 1.4, 3));
  camera.attachControl(canvas, true);
  new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
  BABYLON.MeshBuilder.CreateGround("ground", { width: 20, height: 20 }, scene);
  engine.runRenderLoop(function () { scene.render(); });
  window.addEventListener("resize", function () { engine.resize(); });

  MetastarNPC.init({
    publicKey: "pk_live_xxxxxxxx",
    scene: scene,
    npcId: "npc_xxxxxxxx",
    position: { x: 0, y: 0, z: 3 },
    rotationY: Math.PI,
    getPlayerPosition: function () { return camera.position; },
    onError: function (e) { console.error("NPC failed:", e.code, e.message); }
  });
</script>
</body>
</html>

three.js

For a three.js world use npc.three.js. It is an ES module, and you hand it the three you already use, so three is not loaded twice. Everything else — dashboard, API, events, limits, accounts — is the same as the Babylon.js version.

three.js 월드에서는 npc.three.js 를 씁니다. ES 모듈이며, 이미 쓰고 있는 three 를 넘겨받아 쓰므로 three 가 두 번 실리지 않습니다. 그 밖의 것(대시보드, API, 이벤트, 한도, 계정)은 Babylon.js 판과 같습니다.

Embed code (three.js)삽입 코드 (three.js)

<script type="module">
  import * as THREE from "three";
  import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
  import { MetastarNPC } from "https://metastar.world/static/sdk/v0/npc.three.js";

  MetastarNPC.init({
    publicKey: "pk_live_xxxxxxxx",          // from the dashboard
    npcId: "npc_xxxxxxxx",                  // from the dashboard
    THREE, GLTFLoader,                      // the same three your scene uses
    scene, camera, renderer,                // your THREE.Scene, camera, WebGLRenderer
    position: { x: 0, y: 0, z: 3 },         // where the NPC stands (feet)
    rotationY: Math.PI,                     // 0 faces +Z, Math.PI faces -Z
    getPlayerPosition: () => camera.position
  });
</script>
optionDescription (three.js only)설명 (three.js 전용)
THREE *The three module your scene uses (import * as THREE from "three"). r150 or later.씬에서 쓰는 three 모듈(import * as THREE from "three"). r150 이상.
GLTFLoader *The GLTFLoader class from three's addons. You can pass a ready loader instance as gltfLoader instead.three 애드온의 GLTFLoader 클래스. 대신 이미 만든 로더를 gltfLoader 로 넘겨도 됩니다.
scene *Your THREE.Scene.사용 중인 THREE.Scene.
cameraThe camera you render with. Needed for opening the chat by tapping the avatar, and used as the visitor position when getPlayerPosition is not given.렌더링에 쓰는 카메라. 아바타를 눌러 대화창을 여는 데 필요하고, getPlayerPosition 이 없으면 방문자 위치로 씁니다.
rendererYour WebGLRenderer (or pass its canvas as domElement). The SDK only listens for taps on the canvas; it never renders or resizes. Without it the Talk button still works.사용 중인 WebGLRenderer (또는 캔버스를 domElement 로). SDK 는 캔버스의 누름만 듣고, 렌더링이나 크기 변경은 하지 않습니다. 없어도 대화하기 버튼은 동작합니다.

Complete minimal page (three.js)전체 최소 예제 (three.js)

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style>html, body, canvas { margin: 0; width: 100%; height: 100%; display: block; }</style>
  <script type="importmap">
  { "imports": { "three": "https://cdn.jsdelivr.net/npm/three@0.187.0/build/three.module.js",
                 "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.187.0/examples/jsm/" } }
  </script>
</head>
<body>
<canvas id="c"></canvas>
<script type="module">
  import * as THREE from "three";
  import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
  import { MetastarNPC } from "https://metastar.world/static/sdk/v0/npc.three.js";

  const canvas = document.getElementById("c");
  const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
  const scene = new THREE.Scene();
  scene.background = new THREE.Color(0x9ebde0);
  const camera = new THREE.PerspectiveCamera(60, 1, 0.05, 200);
  camera.position.set(0, 1.6, -2);
  camera.lookAt(0, 1.4, 3);
  scene.add(new THREE.HemisphereLight(0xffffff, 0x556655, 2.5));
  const ground = new THREE.Mesh(new THREE.PlaneGeometry(20, 20), new THREE.MeshStandardMaterial({ color: 0x73806f }));
  ground.rotation.x = -Math.PI / 2;
  scene.add(ground);
  function resize() {
    renderer.setSize(innerWidth, innerHeight, false);
    camera.aspect = innerWidth / innerHeight; camera.updateProjectionMatrix();
  }
  addEventListener("resize", resize); resize();
  renderer.setAnimationLoop(() => renderer.render(scene, camera));

  MetastarNPC.init({
    publicKey: "pk_live_xxxxxxxx",
    npcId: "npc_xxxxxxxx",
    THREE, GLTFLoader, scene, camera, renderer,
    position: { x: 0, y: 0, z: 3 },
    rotationY: Math.PI,
    getPlayerPosition: () => camera.position,
    onError: (e) => console.error("NPC failed:", e.code, e.message)
  });
</script>
</body>
</html>

What visitors see방문자에게 보이는 것

Options옵션 — MetastarNPC.init(options)

optionDescription설명
publicKey *Your site's public key. It only works on the domains you registered.사이트의 공개 키. 등록한 도메인에서만 동작합니다.
scene *Your BABYLON.Scene (with npc.three.js: your THREE.Scene). The SDK does not bundle the engine and does not touch your camera, lights, render loop or input.사용 중인 BABYLON.Scene (npc.three.js 에서는 THREE.Scene). SDK 는 엔진을 포함하지 않으며 카메라·조명·렌더 루프·입력을 바꾸지 않습니다.
npcId *The NPC to place.배치할 NPC.
position{x, y, z} of the feet. Default origin.발 위치 {x, y, z}. 기본값 원점.
rotationYFacing in radians. 0 faces +Z, Math.PI faces −Z. The NPC turns toward the visitor while talking.바라보는 방향(라디안). 0 은 +Z, Math.PI 는 −Z. 대화 중에는 방문자 쪽으로 돌아봅니다.
scaleAvatar scale (default 1 = about 1.75 m tall). Use it if your world's unit is not metres; distances scale with it.아바타 크기(기본 1 = 키 약 1.75m). 월드 단위가 미터가 아니면 조정하세요. 감지 거리도 같이 바뀝니다.
getPlayerPositionFunction returning the visitor's {x, y, z}. Used for the greeting and the Talk button. Without it the active camera (three.js: the camera you passed) is used and the Talk button is always shown.방문자 위치 {x, y, z} 를 돌려주는 함수. 인사와 대화하기 버튼에 씁니다. 없으면 활성 카메라(three.js 는 넘겨준 camera) 위치를 쓰고 대화하기 버튼이 항상 보입니다.
greetfalse turns off the proximity greeting.false 면 먼저 인사하지 않습니다.
uifalse hides the built-in panel so you can build your own UI with sendText() and events.false 면 기본 대화창을 만들지 않습니다. sendText() 와 이벤트로 직접 UI 를 만들 때 씁니다.
onErrorCalled with {code, message} if initialisation fails. init() never throws and never breaks your page.초기화에 실패하면 {code, message} 로 불립니다. init() 은 예외를 던지지 않으며 페이지를 멈추지 않습니다.

* required. You can call init() several times to place several NPCs; they share one session and only one speaks at a time.

* 필수. init() 을 여러 번 불러 NPC 를 여러 명 둘 수 있습니다. 세션은 하나를 같이 쓰고, 한 번에 한 명만 말합니다.

API

const npc = await MetastarNPC.init({ ... });
if (!npc.ready) return;                     // see onError

npc.on("reply", function (e) { console.log(e.text); });
npc.sendText("What are your opening hours?");   // ask as the visitor (LLM)
npc.say("We close at six today.");              // fixed line, no LLM
npc.openChat();  npc.closeChat();
npc.setPosition({ x: 2, y: 0, z: 5 });
npc.login();  npc.logout();  npc.user;          // Metastar account: { nickname, paid } or null
npc.destroy();                                  // removes everything the SDK added
Method메서드
sendText(text)Sends a visitor message (up to 300 characters). Resolves with {text} once the reply arrives; the voice then plays.방문자 메시지를 보냅니다(300자 이하). 답이 오면 {text} 로 완료되고 음성이 재생됩니다.
say(text)Speaks a fixed line (up to 120 characters) without the LLM. The voice is generated once and then cached; each NPC can hold up to 40 cached lines.정해 둔 대사(120자 이하)를 LLM 없이 말합니다. 음성은 한 번만 만들어 저장하며, NPC 한 명당 40개까지 저장됩니다.
openChat() / closeChat()Opens or closes the built-in panel.기본 대화창을 열거나 닫습니다.
setPosition({x,y,z})Moves the NPC.NPC 를 옮깁니다.
destroy()Removes the avatar, panel, observers and audio use. Everything the SDK adds to your scene is named metastar_….아바타·대화창·옵저버·오디오 사용을 모두 정리합니다. SDK 가 씬에 만드는 것은 전부 이름이 metastar_… 로 시작합니다.
login() / logout() / userOpens the Metastar sign-in window (call it from a click), signs out, or reads the signed-in visitor {nickname, paid}. The built-in panel already shows a sign-in button when it is needed, so you only need these with ui: false.메타스타 로그인 창을 열거나(클릭 안에서 호출), 로그아웃하거나, 로그인한 방문자 {nickname, paid} 를 읽습니다. 기본 대화창은 필요할 때 로그인 버튼을 스스로 보여 주므로 ui: false 일 때만 직접 쓰면 됩니다.
on(event, fn) / offSubscribe to events below.아래 이벤트를 받습니다.
Event이벤트
readyAvatar loaded.아바타 로딩 완료.
greetingThe NPC greeted a nearby visitor. {text}다가온 방문자에게 인사함. {text}
listeningMicrophone recording started.마이크 녹음 시작.
thinkingA message was sent; waiting for the reply.메시지를 보냈고 답을 기다리는 중.
reply{text, userText} — userText is what was heard, for voice input.{text, userText} — 음성 입력이면 userText 가 알아들은 문장.
speaking / speakendVoice playback started / ended.음성 재생 시작 / 끝.
quota_exceededYour usage limit is reached. The NPC says a "taking a break" line instead of answering; your page keeps working.사용 한도에 도달함. NPC 가 답 대신 "쉬는 중" 대사를 말하며, 페이지는 그대로 동작합니다.
login_requiredThe visitor has used the free turns, or tried voice chat without signing in. {reason: "text" | "voice"}방문자가 무료 턴을 다 썼거나, 로그인 없이 음성 대화를 시도함. {reason: "text" | "voice"}
login / logoutThe visitor signed in with a Metastar account {nickname, paid} / signed out.방문자가 메타스타 계정으로 로그인함 {nickname, paid} / 로그아웃함.
limitA signed-in visitor reached today's turns. {code: "text_limit" | "voice_limit", paid, upgradeUrl}로그인한 방문자가 오늘의 턴을 다 씀. {code: "text_limit" | "voice_limit", paid, upgradeUrl}
error{code, message} — see troubleshooting.{code, message} — 문제 해결 참고.

Requirements, limits and privacy요구 사항 · 한도 · 개인정보

Troubleshooting문제 해결

Open the browser console; SDK messages start with [MetastarNPC].

브라우저 콘솔을 여세요. SDK 메시지는 [MetastarNPC] 로 시작합니다.

codeMeaning and fix의미와 해결
origin_not_allowedThe page's address is not in the site's domain list. Add the exact origin in the dashboard — scheme and port included, no path (http://localhost:8080). https://example.com and https://www.example.com are different. Changes take up to a minute.페이지 주소가 사이트의 도메인 목록에 없습니다. 대시보드에서 정확한 주소를 추가하세요. 스킴과 포트 포함, 경로 없이(http://localhost:8080). https://example.com 과 https://www.example.com 은 서로 다릅니다. 반영까지 1분쯤 걸립니다.
invalid_keyWrong public key, or the site is disabled.공개 키가 틀렸거나 사이트가 중지 상태입니다.
npc_not_foundWrong npcId, the NPC is disabled, or it belongs to another operator.npcId 가 틀렸거나, NPC 가 중지 상태이거나, 다른 운영자의 NPC 입니다.
babylon_missing
gltf_loader_missing
babylon_unsupported
Load Babylon.js 6+ and babylonjs.loaders before npc.js.npc.js 보다 먼저 Babylon.js 6 이상과 babylonjs.loaders 를 불러오세요.
three_missing
three_unsupported
three.js only: pass THREE and GLTFLoader to init() (a missing loader is reported as gltf_loader_missing), and use three r150 or later.three.js 전용: init() 에 THREE 와 GLTFLoader 를 넘기고(로더가 없으면 gltf_loader_missing), three r150 이상을 쓰세요.
quota_exceededThe usage limit is reached and the NPC is "taking a break". The dashboard shows a notice; to raise the limit, email contact@metastar.world.이용 한도에 닿아 NPC 가 "쉬는 중"입니다. 대시보드에 안내가 표시되며, 한도를 올리려면 contact@metastar.world 로 문의해 주세요.
busy / rate_limitedToo many conversations at once. The NPC asks the visitor to try again shortly.동시에 대화가 너무 많습니다. NPC 가 잠시 후 다시 말을 걸어 달라고 합니다.
autoplay_blockedThe browser blocked sound before the visitor's first tap or click. The text is still shown; sound works after any interaction.방문자가 화면을 한 번 누르기 전이라 브라우저가 소리를 막았습니다. 글은 표시되며, 화면을 한 번 누른 뒤에는 소리가 납니다.
mic_denied / no_speechMicrophone permission was refused, or nothing was heard. Text input keeps working.마이크 권한이 거절됐거나 알아들은 말이 없습니다. 글 입력은 계속 됩니다.

The avatar is too big, too small, or underground: set scale and position.y. It faces the wrong way: set rotationY.

아바타가 너무 크거나 작거나 땅에 묻힘: scale 과 position.y 를 조정하세요. 방향이 반대: rotationY 를 바꾸세요.