콘텐츠로 이동

Home Spot 장면 임베드

@haneoka/embed-home-spot은 웹사이트의 컨테이너 안에 Three/Spine 장면을 마운트합니다. 직접 만든 장면이나 ID로 고른 현재 공개 Home Spot을 받습니다. 공개 장면 제공자가 카메라, 작성된 애니메이션, 레이어 합성, 히트 테스트, 디코딩된 에셋, WebGL 수명 주기를 맡습니다. 임베드는 이식 가능한 데이터 소스와 인코딩된 리소스 바이트를 그 제공자에 연결합니다.

첫 불러오기: 이 페이지의 예제 쓰기

섹션 제목: “첫 불러오기: 이 페이지의 예제 쓰기”
  1. 아래 완전한 장면 실행하고 편집하기까지 스크롤합니다.
  2. 직접 만든 장면을 고른 채 불러오기를 누릅니다. 장면 안에서 작은 파란 어태치먼트가 회전합니다.
  3. 표시된 캐릭터 버튼을 눌러 고르고, 선택 해제로 장면 전체로 돌아갑니다.
  4. 다시 재생, 이어서 PNG 내보내기를 누릅니다. PNG 내려받기로 512×288 이미지를 저장합니다.
  5. 다른 예제를 시작하기 전에 종료 후 해제로 장면을 닫습니다.

런타임은 클릭한 뒤에 불러옵니다. 이 방법은 공개 브라우저 모듈을 쓰며 패키지 설치가 필요 없습니다.

  1. 같은 예제에서 Haneoka ID를 누릅니다. JSON이 spotId: "40002"와 server: "intl"로 바뀝니다.
  2. 불러오기를 누르고 준비됨이 될 때까지 기다립니다. 캐릭터 버튼은 이제 이 장면의 실제 레이어에서 나옵니다.
  3. 그 버튼으로 선택하고, 다시 재생, PNG 내보내기, 종료 후 해제를 시험합니다.

직접 만든 애플리케이션에 넣으려면 컨테이너를 준비하고 호스팅된 ESM을 가져오세요.

<div id="spot"></div>
import { mountHaneokaHomeSpot } from "https://haneoka.org/embed/home-spot.js";
const spot = mountHaneokaHomeSpot(document.querySelector("#spot"), {
spotId: "40002",
server: "intl",
locale: "en",
ariaLabel: "Garage scene",
onEvent(event) {
if (event.type === "error") console.error(event.error);
},
});
await spot.ready;
const character = spot.document.layers.find(layer => layer.characterId > 0);
if (character) spot.update({ selectedCharacterId: character.characterId });
spot.replay();
const png = await spot.exportPng({ width: 512, height: 288 });
// Keep the handle while your scene is visible.
// Call await spot.dispose() when the page/component closes.

이것은 모듈 스크립트나 애플리케이션용 연동 조각입니다. 조작을 바로 시험하려면 위의 동작하는 페이지 예제를 쓰세요. 공개 어댑터는 현재 stories 문서를 읽고 homeSpots[spotId].spine을 고르며, 계정이나 릴리스 선택이 필요 없습니다. 공개 에셋은 referrerPolicy: "no-referrer"로 요청합니다. 사용자 정의 fetcher는 자격 증명과 신호가 유지된 Request를 받습니다. haneokaHomeSpotSource와 mountHomeSpot을 직접 조합할 때는 공개 에셋에 같은 리퍼러 정책을 쓰세요. locale은 server와 독립적으로 요청 언어를 정합니다.

로컬 장면 파일 전체 내려받아 불러오기

섹션 제목: “로컬 장면 파일 전체 내려받아 불러오기”
  1. 완전한 원본 예제를 내려받고 ZIP을 풉니다. home-spot 폴더와 하위 폴더 이름은 그대로 둡니다.
  2. 아래 예제에서 로컬 파일을 누릅니다.
  3. 로컬 장면 JSON에서 home-spot/scene.json을 고릅니다.
  4. 로컬 리소스 폴더에서 압축을 푼 home-spot 폴더 전체를 고르고, 브라우저의 폴더 선택 확인을 허용합니다.
  5. 불러오기를 누릅니다. 첫 예제와 같은 파란 어태치먼트가 보여야 합니다.
  6. 선택, 다시 재생, PNG 내보내기를 시험한 뒤 종료 후 해제로 장면을 닫습니다.
home-spot/
scene.json
pièce.glb
人物/
acteur.atlas
acteur.json
acteur.png

ZIP은 예제 파일 5개를 내려받기용으로 묶은 것입니다. 폴더를 고르기 전에 압축을 푸세요. 임베드가 받는 것은 JSON과 개별 파일입니다. scene.json은 pièce.glb와 人物/acteur.atlas를 참조하고, 그 atlas는 같은 디렉터리의 acteur.png를 참조합니다. 리소스 대응표가 맞도록 악센트 기호와 중국어 폴더 이름을 포함해 이름을 그대로 두세요. 위의 파일 입력으로 JSON과 폴더를 명시적으로 고를 수 있습니다. 브라우저에 폴더 선택이 없다면 HTTP JSON으로 같은 예제를 시험하고, 연동할 때 애플리케이션의 리소스 대응표로 로컬 파일을 넘기세요.

번들링하는 애플리케이션용 패키지 가져오기

섹션 제목: “번들링하는 애플리케이션용 패키지 가져오기”

아래 예제는 번들러 연동 참고용으로 패키지 가져오기와 애플리케이션이 가진 File 변수를 보여 줍니다. 브라우저 애플리케이션은 호스팅된 Home Spot ESM과 core ESM을 쓸 수 있습니다. npm 패키지는 따로 준비 중이며 아직 공개되지 않았습니다. 소스 빌드에는 맞는 임베드·제공자 리비전, Three 0.184.x, Spine 4.2.119가 필요합니다. Spine 런타임에는 자체 런타임 라이선스가 있으며, 장면 데이터와 아트워크는 작성자의 라이선스를 유지합니다.

공개 Home Spot 장면 제공자가 쓰는 기술자를 준비합니다. 장면 하나에는 GLB 배경, 배경 변환, atlas, Spine 레이어가 필요합니다. atlas 페이지와 스켈레톤은 각각 리소스 해석기로 제공합니다. 자체 완결형 GLB는 배경 이미지와 버퍼를 포함합니다.

import { mountHomeSpot } from "@haneoka/embed-home-spot";
import { fileResourceResolver } from "@haneoka/embed-core";
const identity = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
const scene = {
supported: true,
backgroundScene: "room.glb",
backgroundTransform: identity,
atlas: "actors/actor.atlas",
scale: 0.01,
camera: {
position: [0, 0, -5],
startPosition: [0, 0, -5],
target: [0, 0, 0],
fieldOfView: 20,
introDuration: 0,
},
layers: [
{
key: "actor",
runtime: { json: "actors/actor.json" },
animation: "idle",
sortingOrder: 0,
transform: identity,
},
],
};
const resources = new Map([
["room.glb", roomGlbFile],
["actors/actor.atlas", atlasFile],
["actors/actor.json", skeletonFile],
// The name written in actor.atlas is resolved in its own directory.
["actors/actor.png", textureFile],
]);
const spot = mountHomeSpot(document.querySelector("#spot"), {
document: scene,
resolveResource: fileResourceResolver(resources),
locale: "fr",
ariaLabel: "Une scène originale",
});
await spot.ready;

위 파일 변수는 애플리케이션이 얻은 File이나 Blob 객체입니다. 그 리소스 키 문자열에는 유니코드를 쓸 수 있습니다. 장면은 한 언어로 만들면 충분하며, Haneoka 페이지 틀, 카탈로그, 릴리스 매니페스트, 번역 묶음이 필요 없습니다. JSON 스켈레톤은 runtime.json, 바이너리 스켈레톤은 runtime.skel을 씁니다. 설치한 Spine 4.2 런타임과 호환되는 데이터와 그 스켈레톤에 있는 애니메이션을 쓰세요.

카메라 벡터와 레이어 변환은 제공자의 장면 규칙을 따릅니다. 벡터와 행 우선 레이어 행렬은 Unity 좌표계를 따르고, backgroundTransform은 변환된 GLB용 열 우선 행렬입니다. 원점 중심으로 만든 장면이라면 단위 행렬로 동작합니다. 포인터 선택을 위해 레이어에 characterId와 로컬 hitPolygon을 더할 수 있습니다. 서로 다른 레이어는 작성된 정렬 순서를 유지합니다. 이 필드가 있으면 제공자가 카메라 등장, 마우스 추적, 선택 시 투명도를 적용합니다.

HTTP 소스는 장면 문서의 디렉터리를 에셋 기준으로 씁니다. 예를 들어 https://gallery.example/의 페이지가 https://media.example/projects/cafe/scene.json의 장면을 읽을 수 있습니다.

import { mountHomeSpot } from "@haneoka/embed-home-spot";
import { httpDataSource } from "@haneoka/embed-core";
const spot = mountHomeSpot(document.querySelector("#spot"), {
source: httpDataSource({
url: "https://media.example/projects/cafe/scene.json",
}),
ariaLabel: "Cafe",
});
await spot.ready;

이 문서에서 room.glb는 https://media.example/projects/cafe/room.glb로 해석됩니다. actors/actor.atlas의 atlas는 페이지 actor.png를 projects/cafe/actors/에서 해석합니다. 루트 상대 /art/room.glb는 미디어 출처를 쓰고, 절대 URL은 자기 출처를 유지합니다. 리소스가 다른 곳에 있으면 assetsBase를 절대 HTTP(S) 디렉터리로 지정하세요. 사용자 정의 resolveResource로 키를 URL이나 Blob에 대응시킬 수 있고, fetcher(request)로 애플리케이션 전송을 연동할 수 있습니다. 모든 요청은 CORS 모드이며 기본으로 자격 증명을 보내지 않습니다.

데이터와 에셋 출처는 페이지 출처에서 오는 브라우저 요청을 허용해야 합니다. 공개 익명 에셋은 Access-Control-Allow-Origin: *를 보낼 수 있습니다. 자격 증명이 있는 리소스에는 명시적인 페이지 출처와 자격 증명 허가가 필요하며, 그 서비스가 요구할 때만 credentials를 설정하세요. 사용자 정의 요청 헤더에는 OPTIONS 사전 요청이 성공해야 할 수 있습니다. HTTP 실패, 쓸 수 없는 장면, 호환되지 않는 스켈레톤, 막힌 CORS 요청은 ready를 거부하고 오류를 알립니다. 임베드의 바이트 예산은 기본으로 문서나 리소스 하나당 64 MiB이며 maxBytes로 정할 수 있습니다.

로컬 JSON에는 fileDataSource(sceneFile)와 fileResourceResolver(resources)를 함께 씁니다. 그러면 상대 작성 키가 로컬 대응표와 그대로 맞습니다. 리소스 바이트는 문서 로더와 같은 해석기와 전송을 씁니다. 원래 장면 제공자가 텍스처와 모델 인스턴스를 만들고 장면과 함께 해제합니다.

mountHomeSpot은 동기적으로 반환합니다. ready에 거부 처리기를 붙이고, 네트워크가 불러오는 중에도 컴포넌트 정리에서 핸들을 쓸 수 있게 두세요.

const spot = mountHomeSpot(host, { source, signal: componentSignal });
spot.ready.catch(showLoadError);
// Component cleanup can run before ready settles.
await spot.dispose();

cancel()은 현재 불러오기 세대를 취소합니다. 취소한 뒤 다른 장면을 시작하려면 load({ document })나 load({ source })를 호출하세요. 불러오기가 끝난 장면은 cancel()을 호출해도 남습니다. load는 이전 장면과 소스를 해제하고, 대기 중인 불러오기를 거부한 뒤 새 세대를 마운트합니다. ready는 항상 최신 불러오기를 가리키고, load가 반환하는 Promise는 그 세대를 가리킵니다. dispose 메서드가 있는 소스는 불러오기 하나가 소유하는 것으로 다루고, 다시 불러올 때는 새 소스를 만드세요. dispose()는 멱등하며, 임베드 요소와 리스너를 없애고, 불러오기를 취소하고, 소스를 해제합니다. 해제된 핸들은 다시 쓸 수 없습니다. 정리 실패는 집계 오류로 dispose()를 거부하며, 취소된 ready는 정리가 끝나기를 기다리지 않고 바로 거부됩니다.

update({ selectedCharacterId })는 리소스를 다시 만들지 않고 선택한 캐릭터를 바꿉니다. update({ replay: true })는 작성된 등장과 애니메이션을 처음부터 다시 하며, ready 뒤라면 replay()도 같습니다. resize()는 제공자에게 뷰포트 갱신을 요청하며, 장면은 컨테이너 변화도 관찰합니다. 장면의 지오메트리, 에셋, 카메라 데이터를 바꿀 때는 load를 쓰세요.

이벤트에는 loading, ready, cancelled, error, selection, contextlost, contextrestored, disposed가 있습니다. 네트워크 이벤트는 { type: 'resource', event }로 오며 embed-core 작업 ID, 키, 바이트 진행률을 유지합니다. 진행률은 리소스별이며, 응답이 믿을 수 있는 디코딩 길이를 줄 때만 total을 포함합니다. subscribe(listener)는 구독 해제 함수를 반환합니다. 이벤트 관찰자는 불러오기 결과를 바꿀 수 없으며, 그 오류는 onListenerError로 받을 수 있습니다.

exportPng({ width, height })는 현재 장면 프레임의 PNG Blob을 반환합니다. 캡처는 장면 제공자가 GPU 한도 안에서 요청한 크기로 그린 뒤 조작용 뷰포트를 되돌립니다. 구도를 지키려면 요청 비율을 표시 중인 장면과 같게 두세요. 캡처에 실패하면 Promise가 거부됩니다. 내보내기는 영구 내려받기 URL을 만들지 않으니, 미리보기나 내려받기가 끝나면 애플리케이션이 만든 URL을 폐기하세요.

임베드는 마운트하는 순간부터 16:9 영역을 확보하므로 장면을 불러와도 페이지 레이아웃이 바뀌지 않습니다. 다른 비율을 확보하려면 aspectRatio를 덮어쓰세요. 캔버스는 렌더러가 지원하는 픽셀 비율로 그 영역을 채웁니다. 임베드는 자식 요소 하나만 소유하며 컨테이너의 다른 자식은 호스트에 맡깁니다. 모서리 링크는 원래 Haneoka 아이콘을 보여 주고 https://haneoka.org/를 엽니다. 게임 캔버스와 PNG 내보내기 밖에 있습니다.

다시 재생, 선택, 내보내기에는 기존 Material 컨트롤을 쓰세요. 임베드가 제공하는 것은 장면 캔버스와 수명 주기 이벤트이며, 라벨, 진행 표시, 도구 모음은 애플리케이션 몫입니다. MD3 호스트는 --md-sys-color-surface를 제공할 수 있으며, clearColor를 주지 않으면 장면 배경색은 그 토큰을 따릅니다. 버튼 글자와 ariaLabel은 작성자 언어로 현지화하세요. 캔버스의 포인터 히트 테스트와 함께, update를 호출하는 키보드 접근 가능한 호스트 버튼으로도 선택할 수 있습니다.

장면은 원본 PNG 리소스를 씁니다. 네이티브 압축 Spine 텍스처와 PMA는 장면 제공자와 그 에셋 데이터에서 명시적으로 지원해야 합니다. 임베드는 기존 기술자를 그대로 넘기며 모델별 렌더링 규칙을 만들지 않습니다.

완전한 장면 실행하고 편집하기

섹션 제목: “완전한 장면 실행하고 편집하기”

아래의 작은 원본 장면을 불러오세요. 처음 문서는 편집 가능한 JSON이며, 회전하는 Spine 어태치먼트 하나, 자체 완결형 GLB, 작은 atlas 이미지가 있습니다. HTTP는 실제 장면 JSON을 읽고, 파일 모드는 고른 JSON·에셋 폴더나 원본 예제를 로컬 Blob으로 읽습니다. Haneoka ID는 실제 공개용 간편 마운트를 호출합니다. 캐릭터 선택, 다시 재생, 세대 교체, 크기 변경, 512×288 PNG 내보내기를 시험하세요.

매개변수를 편집하고 불러오면 장면을 만듭니다. 작성된 샘플은 작은 장면 하나이며, 선택, 다시 재생, PNG 내보내기는 실제 장면 컨트롤러를 씁니다.

언어

예제를 준비하는 중…

예제 소스 보기

모듈과 렌더러는 클릭한 뒤에만 불러옵니다. 다른 장면을 마운트하기 전에 기존 인스턴스는 해제됩니다. input/url은 애플리케이션의 소스 선택 필드이고, options에는 실제 마운트 인수가 들어 있습니다. 내려받기 링크는 내보낸 Blob URL을 소유하며 교체나 종료 때 폐기합니다. 콜백·모듈 객체는 아래에서 설명하는 실행 가능한 연동이며 JSON 값이 아닙니다. UI 언어 선택지는 ja/en/zh-TW/zh-CN/ko 순서이며, 작성자 로캘은 편집 가능한 문자열로 남습니다.

import { mountHaneokaHomeSpot } from "https://haneoka.org/embed/home-spot.js";
const scene = mountHaneokaHomeSpot(element, { spotId: "40002", server: "intl", locale: "en" });
await scene.ready;
const character = scene.document.layers.find(layer => layer.characterId > 0);
if (character) scene.update({ selectedCharacterId: character.characterId });
scene.replay();
const png = await scene.exportPng({ width: 512, height: 288 });
await scene.dispose();

안정 별칭은 실제 배포된 SDK를 따릅니다. 검증된 릴리스는 manifest.modules로 고정하세요. 불변 r22는 자체 소스·레이아웃 동작을 유지한 채 계속 쓸 수 있습니다. 현재 공통 브랜딩은 뷰포트 전체 위에서 장면 모서리에 투명 배경과 불투명도 55% 아이콘을 씁니다. 캡처는 장면 캔버스만 내보냅니다. SDK 산출물은 배포할 때 소스에서 만들어지며, npm은 별도 공개 단계입니다.

mountHomeSpot과 공개 마운트 옵션 전체

섹션 제목: “mountHomeSpot과 공개 마운트 옵션 전체”

위치 인수 host는 ownerDocument가 있는 HTMLElement여야 합니다(아니면 TypeError). mountHomeSpot과 각 load 호출에서는 document나 source 중 정확히 하나만 고르세요. 둘 다 있거나 둘 다 없으면 TypeError를 던집니다. 호스트는 장면 자식과 안정된 비율 영역을 소유하고, 관계없는 호스트 자식은 그대로 둡니다.

필드타입·기본값의미, 제약, 실패
documentHomeSpotDocument, 필수 선택지 중 하나아래의 작성 기술자. 지원하지 않거나 불완전한 형태는 ready를 거부한다.
sourceDataSource<HomeSpotDocument>, 필수 선택지 중 하나memory/http/file/사용자 정의 소스, 같은 core 계약. 소스 실패는 ready를 거부한다.
server선택 문자열, 기본 undefined, 공개 마운트는 intllocale과 독립된 리소스 레지스트리.
locale선택 문자열, 기본 en작성자·요청 언어. UI의 다섯 가지 제안에 한정되지 않는다.
assetsBase선택 절대 HTTP(S) 디렉터리, 기본은 소스 기준쿼리·프래그먼트 없는 디렉터리로 덮어쓴다. 잘못되면 TypeError.
resolveResource선택 (key,DataContext)→URL/string/Blob/Promise, 기본은 키 그대로유니코드 키 문자열을 그대로 대응시킨다. atlas 이미지 이름은 그 atlas 기준으로 해석한다. 로컬 키가 없으면 Error.
fetcher선택 (Request)→Promise<Response>, 기본 fetch인코딩된 바이트 전송. 공개 간편 마운트는 신호·헤더·자격 증명을 유지한 채 no-referrer를 적용한다.
credentialsomit/same-origin/include, 기본 omitcore 요청. 서버에서 출처·자격 증명 허가가 필요하다.
headersHeadersInit, 기본 없음core 공유 헤더. 소스 요청 헤더가 같은 이름에서 우선한다.
maxBytes양의 안전한 정수, 기본 67108864JSON·바이트 응답 하나당 예산이며, 디코딩·GPU 메모리 합계가 아니다. 잘못되면 RangeError.
onListenerError선택 (unknown)→void관찰자나 분리된 정리의 오류를 받는 곳.
signal선택 AbortSignal중단하면 ready 뒤라도 마운트한 핸들을 해제한다. 장면 전체 내장 시간 제한이 없으니 호스트에서 기한을 둔다.
ariaLabel문자열, 기본 Home Spot작성자 언어로 된 캔버스 접근성 이름.
clearColor선택 CSS 색기본은 호스트 MD3 surface 계산값, 없으면 Canvas 시스템 색. 제공자 색 파싱 오류는 ready를 거부할 수 있고, 쓸 수 있는 계산값이 없으면 Error.
aspectRatio유한한 양수, 기본 16/9불러오기·준비 시 호스트 비율. 0 이하나 유한하지 않으면 RangeError. 기술자의 camera.aspect를 바꿔도 호스트 크기 조정을 덮어쓰지 않는다.
selectedCharacterId선택 숫자, 기본 선택 없음(제공자에서는 0)고른 레이어를 강조한다. 0이면 해제. 맞지 않는 캐릭터는 투명도 0.3, 맞거나 지정되지 않은 것은 1.
modules선택 HaneokaHomeSpotRuntimeModules기본은 Three/GLTFLoader/Spine 지연 가져오기. 호환되는 모듈 생성자가 필요하며, 기능이 빠지면 TypeError. 전체 형태는 아래.
onEvent선택 (HomeSpotEvent)→void첫 세대 전에 등록된다.
spotIdmountHaneokaHomeSpot에서 필수 문자열·숫자문자열로 바꾼 비어 있지 않은 ID. 장면이 없으면 Error, 빈 ID는 TypeError. 작성 마운트 옵션에는 없다.
apiBase공개 마운트·소스에서 선택 문자열기본 https://haneoka.org/api/v1/. core 절대 디렉터리 검증을 받는다.

mountHaneokaHomeSpot(host,options)은 소스를 자동으로 마련하므로 document나 source를 더하지 마세요. 현재 stories 문서를 읽고 homeSpots[id].spine을 고릅니다. 소스 ID는 릴리스 ID가 아닙니다. 계정이나 릴리스 선택은 없습니다. haneokaHomeSpotSource({spotId,apiBase?})는 마운트를 직접 조합할 수 있도록 같은 DataSource를 제공합니다. 직접 조합할 때는 공개 에셋 전송에 no-referrer를 지정하세요. 직접 만든 소스 자체는 렌더러를 만들지 않습니다.

필드타입·기본값요건과 효과
supported타입에서는 선택 불리언, 런타임에서는 true 필수false거나 생략하면 이 Three/Spine 제공자가 거부한다.
atlas문자열, 런타임에서 필수레이어의 기본 atlas 키. 비었거나 없으면 ready를 거부한다.
backgroundScene문자열, 런타임에서 필수GLB 리소스. 자체 완결형 GLB는 자기 버퍼·이미지를 가진다. 없거나 잘못된 GLB는 불러오기를 거부한다.
backgroundTransformnumber[], 16개 필수변환된 GLB의 열 우선 변환. 길이가 틀리면 제공자 생성을 거부한다. 유한한 값을 쓴다.
animation선택 문자열, 기본 빈 값레이어의 대체 애니메이션. 의도한 움직임에는 작성된 사용 가능한 애니메이션이 필요하다.
scale선택 숫자, 제공자 대체값 0.01Spine 단위 기본 배율. runtime.scale이 덮어쓴다. 0은 숨김이 아니라 대체값이 된다.
fadeInDuration선택 숫자, 기본 0캐릭터 등장 불투명도 초. 음수는 0으로.
camera선택 카메라 객체, 기본은 아래Unity 좌표계 카메라 등장과 포인터 추적 설정.
layers읽기 전용 layer[], 비어 있지 않아야 함순서 있는 스켈레톤·atlas 항목. 비면 제공자가 거부한다.

공개 형태는 소스 확장 필드를 허용합니다. 제공자는 알려진 필드만 쓰며, 임의의 필드를 모두 마운트 설정으로 다루지 않습니다.

필드기본값의미
position[0,0,-1]Unity 좌표계 기본 카메라 벡터.
startPosition[0,0,-2]Unity 등장 시작 위치.
target[0,0,0]카메라 대상.
fieldOfView20도. 180 미만의 유한한 양수를 쓴다. 0은 대체값을 쓴다.
aspect16/9처음 카메라 비율. 크기 조정 시 실제 뷰포트 비율로 바뀐다.
orbitRatio0장면 단위의 카메라 전방 축 오프셋.
introDuration0등장 초. 음수는 0으로.
introEase09는 cubic-out, 그 밖의 값은 선형 진행.
mouseFollowundefined아래의 선택 포인터 각도 설정.
mouseFollow.sensitivityundefined보존되는 원본 메타데이터. 현재 포인터 계산은 이 필드가 아니라 최댓값·임계값을 바로 쓴다.
mouseFollow.threshold0각도 불감대. 0 이상으로 제한.
mouseFollow.maxLeft0왼쪽 포인터 요 범위(도).
mouseFollow.maxRight0오른쪽 포인터 요 범위.
mouseFollow.maxUp0위쪽 피치 범위.
mouseFollow.maxDown0아래쪽 피치 범위.
mouseFollow.smoothTime0.1초. 최소 0.001.

카메라 벡터는 숫자 3개입니다. 레이어 행렬은 Unity 행 우선, backgroundTransform은 GLB 열 우선입니다. 없거나 잘못된 벡터 성분은 제공자의 숫자 대체값을 따릅니다. 원점 중심 장면에는 단위 행렬을, 실제 게임 데이터에는 작성된 원본 변환을 쓰세요.

필드타입·기본값의미와 선택
keylayer 타입에서 필수 문자열작성 레이어 식별자. 문자 그대로이며 유니코드를 쓸 수 있다.
characterId선택 숫자, 기본 0선택용 ID.
sortingOrder선택 숫자, 기본 0오름차순 그리기 순서. 같은 값은 입력 순서를 유지한다.
animation선택 문자열, 기본 descriptor.animationruntime 애니메이션이 우선한다.
skeleton선택 문자열제공자 정규화 입력. 새 장면에서는 runtime.json/skel을 명시한다.
transform선택 number[]Unity 행 우선 레이어 변환. 보통 유한한 값 16개.
hitPolygon선택 읽기 전용 [x,y,z][]포인터 선택용 로컬 다각형.
format선택 알 수 없는 메타데이터Spine 진입 어댑터가 정규화한다.
runtime선택 Readonly<Record<string,unknown>>지원하는 리소스 키는 아래와 같다.
runtime.json선택 문자열첫 번째 스켈레톤 소스 후보. JSON 스켈레톤 데이터.
runtime.skel선택 문자열바이너리 스켈레톤 소스. 바이너리 파싱도 고른다.
runtime.model선택 문자열대체 스켈레톤 소스.
runtime.atlas선택 문자열, 기본은 기술자 atlas레이어 atlas를 덮어쓴다.
runtime.format선택 문자열spine-binary면 바이너리를 고른다. URL 확장자 .skel도 바이너리가 된다.
runtime.scale선택 숫자, 기본 descriptor.scale, 다음 0.01Spine 파서 배율.
runtime.animation선택 문자열, 기본 layer, 다음 기술자애니메이션 이름.

정규화된 스켈레톤이 없으면 TypeError를 던집니다. 스켈레톤 버전은 설치한 Spine 4.2와 맞아야 하고, atlas는 참조하는 영역·페이지를 포함해야 하며, 애니메이션을 재생하려면 지정한 이름의 애니메이션이 있어야 합니다. HTTP, 파싱, 텍스처, 모듈 오류는 ready를 거부합니다. 네이티브 압축·PMA 처리는 제공자 데이터를 따르며, 이 임베드가 새 렌더러나 형식을 고르지 않습니다.

modules는 three: 객체, GLTFLoader: 생성자, spine: 객체를 가집니다. spine은 TextureAtlas, ThreeJsTexture, AtlasAttachmentLoader, SkeletonBinary, SkeletonJson, SkeletonMesh 생성자를 제공해야 합니다. Three 네임스페이스는 제공자가 쓰는 WebGLRenderer, Color, Scene, PerspectiveCamera, Vector2, Vector3, Euler, Matrix4, MeshBasicMaterial을 제공해야 합니다. 공개 패키지 타입은 일부러 이들을 불투명하게 두고, 런타임에 쓰는 생성자를 확인합니다. 호환되는 Three 인스턴스 하나와 Spine 4.2.119를 쓰세요. 임베드를 가져오기만 해서는 WebGL이 초기화되지 않습니다. 라이선스가 필요한 런타임 배포는 애플리케이션 몫입니다.

핸들, update, 내보내기 필드 전체

섹션 제목: “핸들, update, 내보내기 필드 전체”
멤버인수·결과동작·오류
ready최신 Promise<void>load와 함께 바뀐다. load가 반환하는 각 Promise는 그 세대에 묶인다.
stateloading/ready/cancelled/error/disposed현재 단계.
elementHTMLElement소유한 장면·브랜딩 래퍼.
canvasHTMLElement/undefined제공자가 준비되면 쓸 수 있다.
documentHomeSpotDocument/undefined마지막으로 불러오기에 성공한 기술자. 카탈로그 사본이 아니다.
update{selectedCharacterId?:number,replay?:boolean}→void다시 만들지 않고 선택·다시 재생을 적용한다. 선택에 undefined를 주면 해제한다. 해제 후에는 Error.
load{document} 또는 {source}→Promise<void>입력은 정확히 하나, 아니면 TypeError. 이전 장면·소스를 해제하고 그 세대를 취소한다. 새 소스가 자기 정리를 소유한다.
replay()=>voidready가 필요하다. 준비 전·해제 후에는 Error.
resize()=>voidready가 필요하다. ResizeObserver로도 자동 실행된다.
exportPng{width?:number,height?:number}→Promise<Blob>ready와 온전한 컨텍스트가 필요하다. 기본은 그리기 버퍼 크기. 한쪽 크기를 빼면 현재 비율을 유지한다.
subscribelistener→구독 해제이후 이벤트. 해제 후에는 Error.
cancel()=>void현재 불러오기 세대만 취소한다. 준비된 장면은 남는다. 취소 뒤에는 새 소스로 다시 불러온다.
dispose공유 Promise<void>멱등. 즉시 분리·중단하고 소스 정리를 기다린다. 실패는 AggregateError.

PNG 너비·높이는 양의 안전한 정수여야 하며 min(maxTextureSize, MAX_RENDERBUFFER_SIZE) 이내, 총 픽셀은 16777216 이하여야 합니다(아니면 RangeError). 시간을 진행하지 않고 현재 프레임을 그리고, 잠시 렌더 대상 크기를 바꾼 뒤 조작용 크기·픽셀 비율·비율을 되돌립니다. 2D 복사 컨텍스트나 인코딩을 쓸 수 없거나 WebGL 컨텍스트가 사라졌으면 Error로 거부합니다. Blob은 영구 URL을 만들지 않으니 미리보기·내려받기 URL은 호출자가 소유합니다. PNG에는 장면 픽셀만 들어가며 호스트 오버레이는 들어가지 않습니다.

이벤트는 resource{event:EmbedEvent}, loading/ready/cancelled{generation:number}, error{generation,error}, selection{characterId:number}, contextlost, contextrestored, disposed입니다. resource 이벤트는 불러오는 세대에 속하며, core operation/key/progress 필드는 같은 의미를 유지합니다. 리스너 오류는 격리됩니다. 취소는 AbortError, 외부 신호는 해제를 하며, 디코딩·HTTP·제공자 오류는 실제 원인을 유지합니다. 리소스를 해제한 해제된 핸들·소스는 다시 쓰지 마세요.

애플리케이션 전용 sdkBase 필드는 호환되는 직접 호스팅 core.js/home-spot.js 배포물이 있는 절대 HTTP(S) 디렉터리를 고릅니다. 기본은 공식 /embed/ 디렉터리이며 mountHomeSpot 옵션이 아닙니다. 생성 설정이나 리소스 대응 변경을 적용하려면 불러오기를, 기존 핸들에 document나 source만 넘기려면 교체를 쓰세요.