@kokoa/clotho-editor 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,15 +1,12 @@
1
1
  # @kokoa/clotho-editor
2
2
 
3
- [clotho](../clotho) 애니메이션 문서를 위한 비주얼 에디터.
3
+ [clotho](../clotho) 애니메이션 문서를 작성하고 미리 볼 수 있는 시각 편집기다.
4
4
 
5
5
  ## 상태
6
6
 
7
- 두 블로그 저장소 안에 있던 Studio(약 8,900 LOC)를 clotho
8
- 기반 독립 패키지로 옮겼다. typecheck 0 errors, 빌드·테스트 통과.
7
+ 두 블로그 저장소에서 사용하던 Studio 약 8,900줄을 clotho 기반의 독립 패키지로 옮겼다. 타입 검사, 빌드, 테스트를 모두 통과한다.
9
8
 
10
- 이식에서 가장 의미 있는 변화는 **미리보기가 clotho를 쓴다**는 점이다. Studio는 자체
11
- 캔버스 렌더를 갖고 있어 에디터에서 맞게 보이는 것이 사이트에서 다르게 보일 수 있었다.
12
- 이제 `buildScene` + `patchScene`을 지나므로 에디터와 배포본이 갈라질 수 없다.
9
+ 가장 변화는 **미리보기에도 clotho를 사용한다**는 점이다. 이전 Studio는 자체 canvas renderer를 사용했기 때문에 편집 화면과 실제 사이트의 화면이 다를 수 있었다. 이제 두 화면 모두 `buildScene`과 `patchScene`을 거치므로 같은 문서는 같은 결과로 표시된다.
13
10
 
14
11
  자세한 내용과 남은 정리 항목은 [`docs/PORTING.md`](./docs/PORTING.md).
15
12
 
@@ -31,10 +28,61 @@ configureHost({ placeholderImageUrl: "/uploads/placeholder.png" });
31
28
  <Studio initial={doc} onSave={handleSave} />;
32
29
  ```
33
30
 
34
- `Studio`는 저장 방식을 호스트가 소유하는 삽입형 컴포넌트다. 기존 API 경로를 그대로 쓰는
35
- 완성형 화면이 필요하면 `<StudioMount initialId="document-id" />`를 사용한다. 일반적인
36
- Vite/Next.js/React SPA에 삽입할 수 있고, 브라우저 전용 코드는 mount 이후에
37
- 초기화된다.
31
+ `Studio`는 문서를 저장하는 방법을 사용하는 application에서 정할 수 있는 내장형 컴포넌트다. 기존 API 경로를 그대로 사용하는 완성된 화면이 필요하면 `<StudioMount initialId="document-id" />`를 사용한다. 두 컴포넌트 모두 Vite, Next.js, React SPA에 넣을 수 있으며 브라우저에서만 필요한 코드는 컴포넌트가 화면에 연결된 뒤 초기화된다.
32
+
33
+ `StudioMount`의 저장 방식은 `AnimationRepository`로 교체할있다. 서버에서 관리하는 application은 `configureApi`로 기존 HTTP API를 연결할 수 있고, 독립 실행형 편집기는 `createLocalStorageRepository`를 주입할 수 있다. 별도 데이터베이스나 Git 기반 저장소를 사용하려면 `list`, `load`, `create`, `save`, `delete`를 구현한 repository를 전달하면 된다.
34
+
35
+ ```tsx
36
+ const repository = createLocalStorageRepository({
37
+ storageKey: "my-editor.animations",
38
+ examples,
39
+ });
40
+
41
+ <StudioMount repository={repository} />;
42
+ ```
43
+
44
+ 상단 제목과 이미지 저장 방식도 사용하는 환경에서 정할 수 있다. `editorTitle`의 기본값은 `Clotho Editor`이며, `resolveImage`는 업로드한 파일을 외부 URL 또는 `data:` URL로 바꾸는 hook이다. hook을 전달하지 않으면 파일을 base64 data URL로 변환해 문서의 `assets`에 저장한다. 같은 이미지는 하나의 asset을 공유하고 각 image 요소는 `assetId`만 참조한다.
45
+
46
+ ```tsx
47
+ <StudioMount
48
+ editorTitle="블로그 애니메이션 편집기"
49
+ resolveImage={async (file) => uploadToMediaServer(file)}
50
+ />
51
+ ```
52
+
53
+ 미리보기의 `무한 재생` 설정은 문서의 `settings.loop`에 저장된다. `타임라인 분리` 버튼을 누르면 기존 타임라인 컴포넌트가 이벤트와 상태를 유지한 채 별도 브라우저 창으로 이동한다. 분리된 창에서도 재생, Chapter와 keyframe 편집, drag, 확대와 스크롤을 같은 방식으로 사용할 수 있다. `편집기에 다시 합치기` 버튼을 누르거나 창을 닫으면 컴포넌트가 원래 위치로 돌아온다.
54
+
55
+ `실제 미리보기`는 편집용 canvas가 아니라 `@kokoa/clotho/dom`의 `mountPlayer`로 완성된 애니메이션 컴포넌트를 별도 창에 표시한다. 편집 중 문서가 바뀌면 미리보기 창도 최신 문서로 다시 렌더링한다. 사용하는 application에서는 editor stylesheet와 함께 Clotho player stylesheet도 불러와야 한다.
56
+
57
+ ```ts
58
+ import "@kokoa/clotho-editor/styles.css";
59
+ import "@kokoa/clotho/styles.css";
60
+ ```
61
+
62
+ 왼쪽 도구는 먼저 활성화한 뒤 canvas에서 사용한다. 기존 요소를 누르면 자동으로 `선택 · 이동 · 크기` 도구로 돌아간다. `V`, `R`, `O`, `L`, `A`, `T`, `I`, `B`, `Y`로 선택, 사각형, 원, 선, 화살표, 텍스트, 이미지, Path, 다각형 도구를 활성화할 수 있으며 input, textarea, contenteditable에 입력하는 동안에는 단축키가 동작하지 않는다. 텍스트는 canvas에서 더블클릭해 바로 편집한다. Path는 점을 차례대로 누르고 더블클릭하거나 Enter를 눌러 완성하며 Esc를 누르면 작성을 취소한다.
63
+
64
+ 사각형, 원과 다각형 도구는 pointer를 놓을 때 요소를 확정한다. 짧게 누르면 기본 크기로 만들고 drag하면 화면에 표시되는 임시 윤곽의 크기로 만든다. 임시 윤곽은 animation frame마다 최대 한 번만 갱신하므로 빠른 pointer 이벤트가 문서 변경이나 렌더를 반복해서 발생시키지 않는다. 색상 입력은 picker를 조작하는 동안 현재 input을 유지하고 선택을 확정했을 때 문서에 반영한다.
65
+
66
+ Shift, Command 또는 Ctrl을 누른 채 canvas나 요소 목록을 누르면 여러 요소를 선택하거나 선택에서 제외할 수 있다. 그룹의 자식은 요소 목록과 timeline에서 들여쓰기되어 표시된다. 그룹 timeline은 여러 자식에 적용되는 transform과 visibility animation을 작성할 때 사용한다.
67
+
68
+ JSON을 내보낼 때는 어떤 image 요소에서도 참조하지 않는 `assets` 항목을 자동으로 제거한다. 이미지를 삭제한 뒤 별도의 정리 작업을 실행할 필요가 없다.
69
+
70
+ Cloudflare demo의 `열기` 화면에는 Clotho gallery의 JSON 문서 9개가 모두 들어 있다. JSON은 Clotho 저장소의 gallery source에서 생성하며 다음 명령으로 다시 동기화한다.
71
+
72
+ ```bash
73
+ cd ../clotho
74
+ bun examples/gallery/build.ts ../clotho-editor/app/gallery --documents-only
75
+ ```
76
+
77
+ 두 에디터의 `JSON 내보내기` 버튼은 현재 문서를 검증한 뒤 `{문서 ID}.json` 파일로 내려받는다. 화면을 직접 만들 때는 `animationDocumentToJson`, `animationDocumentFileName`, `downloadAnimationJson`을 사용할 수 있다.
78
+
79
+ 재생 설정 화면에서는 현재 단계 설명과 전체 단계 목록을 표시할지 선택할 수 있다. 단계 목록의 위치도 `좌측 | 우측 | 상단 | 하단` 중에서 고를 수 있다. 네 가지 배치를 한 화면에서 확인하려면 다음 명령을 실행한다.
80
+
81
+ ```bash
82
+ bun run visual-check
83
+ ```
84
+
85
+ npm 배포는 `vX.Y.Z` GitHub Release와 `.github/workflows/publish.yml`을 통해 진행한다. 먼저 npm Trusted Publisher와 GitHub의 `npm-production` 승인 environment를 설정해야 한다. 같은 버전의 `@kokoa/clotho`를 먼저 공개한 뒤 editor의 GitHub Release를 공개한다.
38
86
 
39
87
  ## 개발
40
88
 
@@ -45,9 +93,21 @@ bun test
45
93
  bun run build
46
94
  ```
47
95
 
48
- 개발 시에는 devDependency 이웃 `../clotho`를 가리킨다. 배포물에는 이 경로가 포함되지
49
- 않고 `^0.1.0` peer 계약만 노출된다. 배포 순서와 검증은
50
- [`../clotho/docs/RELEASING.md`](../clotho/docs/RELEASING.md)를 따른다.
96
+ 개발 환경의 devDependency 이웃한 `../clotho`를 가리킨다. 배포 패키지에는 로컬 경로가 들어가지 않으며 `^0.1.0` peer dependency만 공개된다. 배포 순서와 검증 방법은 [`../clotho/docs/RELEASING.md`](../clotho/docs/RELEASING.md)에 정리되어 있다.
97
+
98
+ ## Cloudflare Workers 배포
99
+
100
+ 독립 에디터는 `app`에서 시작하며 Cloudflare Workers Static Assets용 설정은 [`wrangler.jsonc`](./wrangler.jsonc)에 들어 있다. 로컬에서 실제 화면을 확인하거나 배포 파일을 만들려면 다음 명령을 사용한다.
101
+
102
+ ```bash
103
+ bun run app:dev
104
+ bun run build:app
105
+ bun run dev:cloudflare
106
+ ```
107
+
108
+ Cloudflare Dashboard의 Build command에는 `bun run build:app`, Deploy command에는 `npx wrangler deploy`를 지정한다. 로컬에서 직접 배포할 때만 `bun run deploy:cloudflare`를 실행한다. npm 패키지를 만드는 `bun run build`와 Cloudflare 앱을 만드는 `bun run build:app`은 서로 독립적이다.
109
+
110
+ 이 저장소의 설정에는 custom domain을 넣지 않았으므로 Cloudflare Dashboard의 해당 Worker에서 `clotho-editor.shinkeonkim.com`을 Custom Domain으로 연결하면 된다. Dashboard에서 관리한 설정이 이후 CLI 배포로 덮어써지지 않도록 `routes` 항목도 두지 않았다.
51
111
 
52
112
  ## 라이선스
53
113
 
@@ -1,6 +1,163 @@
1
- import { computeSnapshot, encodeImageAsset, inlineAssetFromDataUri, animationDocumentSchema } from '@kokoa/clotho';
1
+ import { animationDocumentSchema, computeSnapshot, encodeImageAsset, inlineAssetFromDataUri } from '@kokoa/clotho';
2
2
 
3
- // src/legacy/state/internals.ts
3
+ // src/export-json.ts
4
+ function animationDocumentToJson(def) {
5
+ const parsed = garbageCollectAnimationAssets(def);
6
+ return `${JSON.stringify(parsed, null, 2)}
7
+ `;
8
+ }
9
+ function garbageCollectAnimationAssets(def) {
10
+ const parsed = animationDocumentSchema.parse(def);
11
+ const used = new Set(
12
+ parsed.elements.filter((element) => element.type === "image").map((element) => element.assetId)
13
+ );
14
+ return animationDocumentSchema.parse({
15
+ ...parsed,
16
+ assets: Object.fromEntries(
17
+ Object.entries(parsed.assets).filter(([id]) => used.has(id))
18
+ )
19
+ });
20
+ }
21
+ function animationDocumentFileName(def) {
22
+ const id = def.id.trim().replace(/[^a-zA-Z0-9._-]+/g, "-");
23
+ return `${id || "animation"}.json`;
24
+ }
25
+ function downloadAnimationJson(def) {
26
+ if (typeof document === "undefined" || typeof URL.createObjectURL !== "function") {
27
+ throw new Error("JSON \uD30C\uC77C\uC740 \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C\uB9CC \uB0B4\uB824\uBC1B\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4.");
28
+ }
29
+ const url = URL.createObjectURL(
30
+ new Blob([animationDocumentToJson(def)], {
31
+ type: "application/json;charset=utf-8"
32
+ })
33
+ );
34
+ const link = document.createElement("a");
35
+ link.href = url;
36
+ link.download = animationDocumentFileName(def);
37
+ link.hidden = true;
38
+ document.body.append(link);
39
+ link.click();
40
+ link.remove();
41
+ URL.revokeObjectURL(url);
42
+ }
43
+ var DEFAULT_BASE = "/api/admin/animations";
44
+ var BASE = DEFAULT_BASE;
45
+ function configureApi(options) {
46
+ if (options.baseUrl) BASE = options.baseUrl.replace(/\/+$/, "");
47
+ repository = httpRepository;
48
+ }
49
+ function apiBaseUrl() {
50
+ return BASE;
51
+ }
52
+ var revisions = /* @__PURE__ */ new Map();
53
+ var MissingAnimationRevisionError = class extends Error {
54
+ };
55
+ var AnimationStudioApiError = class extends Error {
56
+ };
57
+ function isRecord(value) {
58
+ return typeof value === "object" && value !== null;
59
+ }
60
+ async function readJson(res) {
61
+ if (!res.ok) {
62
+ const text = await res.text();
63
+ throw new AnimationStudioApiError(`HTTP ${res.status}: ${text}`);
64
+ }
65
+ return res.json();
66
+ }
67
+ function parseRevision(value) {
68
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1) {
69
+ throw new TypeError("Animation revision is malformed");
70
+ }
71
+ return value;
72
+ }
73
+ function parseAnimationEnvelope(value) {
74
+ if (!isRecord(value)) throw new TypeError("Animation response is malformed");
75
+ return {
76
+ def: animationDocumentSchema.parse(value.def),
77
+ revision: parseRevision(value.revision)
78
+ };
79
+ }
80
+ var httpRepository = {
81
+ list: async () => {
82
+ const res = await fetch(BASE);
83
+ const data = await readJson(res);
84
+ if (!isRecord(data) || !Array.isArray(data.items))
85
+ throw new TypeError("Animation list response is malformed");
86
+ return data.items.map((item) => {
87
+ if (!isRecord(item) || typeof item.id !== "string" || typeof item.title !== "string" || typeof item.description !== "string") {
88
+ throw new TypeError("Animation summary is malformed");
89
+ }
90
+ return {
91
+ id: item.id,
92
+ title: item.title,
93
+ description: item.description,
94
+ ...typeof item.updatedAt === "string" ? { updatedAt: item.updatedAt } : {}
95
+ };
96
+ });
97
+ },
98
+ load: async (id) => {
99
+ const res = await fetch(`${BASE}/${encodeURIComponent(id)}`);
100
+ const data = parseAnimationEnvelope(await readJson(res));
101
+ revisions.set(data.def.id, data.revision);
102
+ return data.def;
103
+ },
104
+ save: async (def) => {
105
+ const revision = revisions.get(def.id);
106
+ if (revision === void 0)
107
+ throw new MissingAnimationRevisionError(
108
+ `Animation '${def.id}' has no loaded revision`
109
+ );
110
+ const res = await fetch(`${BASE}/${encodeURIComponent(def.id)}`, {
111
+ method: "PUT",
112
+ headers: { "Content-Type": "application/json" },
113
+ body: JSON.stringify({ def, revision })
114
+ });
115
+ const data = parseAnimationEnvelope(await readJson(res));
116
+ revisions.set(data.def.id, data.revision);
117
+ return data.def;
118
+ },
119
+ create: async (id, title) => {
120
+ const res = await fetch(BASE, {
121
+ method: "POST",
122
+ headers: { "Content-Type": "application/json" },
123
+ body: JSON.stringify({ id, title })
124
+ });
125
+ const data = parseAnimationEnvelope(await readJson(res));
126
+ revisions.set(data.def.id, data.revision);
127
+ return data.def;
128
+ },
129
+ delete: async (id) => {
130
+ const res = await fetch(`${BASE}/${encodeURIComponent(id)}`, {
131
+ method: "DELETE"
132
+ });
133
+ await readJson(res);
134
+ revisions.delete(id);
135
+ }
136
+ };
137
+ var repository = httpRepository;
138
+ function configureAnimationRepository(next) {
139
+ repository = next;
140
+ }
141
+ var listAnimations = () => repository.list();
142
+ var loadAnimation = (id) => repository.load(id);
143
+ var saveAnimation = (def) => repository.save(def);
144
+ var createAnimation = (id, title) => repository.create(id, title);
145
+ var deleteAnimation = (id) => repository.delete(id);
146
+ async function importAnimation(def) {
147
+ const parsed = animationDocumentSchema.parse(def);
148
+ try {
149
+ await repository.load(parsed.id);
150
+ } catch {
151
+ await repository.create(parsed.id, parsed.title || parsed.id);
152
+ }
153
+ return repository.save(parsed);
154
+ }
155
+ async function duplicateAnimation(sourceId, newId, newTitle) {
156
+ const source = await loadAnimation(sourceId);
157
+ const cloned = { ...source, id: newId, title: newTitle };
158
+ await createAnimation(newId, newTitle);
159
+ return await saveAnimation(cloned);
160
+ }
4
161
  var listeners = /* @__PURE__ */ new Set();
5
162
  var state = {
6
163
  def: null,
@@ -608,6 +765,13 @@ function registerExternalAsset(url) {
608
765
  }
609
766
  function registerInlineAsset(bytes, mime) {
610
767
  const { asset } = encodeImageAsset(bytes, mime);
768
+ const def = getDef();
769
+ if (def) {
770
+ for (const [id2, existing] of Object.entries(def.assets)) {
771
+ if (existing.kind === "inline" && existing.mime === asset.mime && existing.data === asset.data)
772
+ return id2;
773
+ }
774
+ }
611
775
  const id = uniqueAssetId();
612
776
  mutateDef(
613
777
  (draft) => {
@@ -628,6 +792,13 @@ function uniqueAssetId() {
628
792
  function registerDataUriAsset(dataUri) {
629
793
  const inline = inlineAssetFromDataUri(dataUri);
630
794
  if (!inline) return registerExternalAsset(dataUri);
795
+ const def = getDef();
796
+ if (def) {
797
+ for (const [id2, existing] of Object.entries(def.assets)) {
798
+ if (existing.kind === "inline" && existing.mime === inline.mime && existing.data === inline.data)
799
+ return id2;
800
+ }
801
+ }
631
802
  const id = uniqueAssetId();
632
803
  mutateDef(
633
804
  (draft) => {
@@ -840,104 +1011,7 @@ function configureHost(options) {
840
1011
  function placeholderImageUrl() {
841
1012
  return placeholderUrl;
842
1013
  }
843
- var DEFAULT_BASE = "/api/admin/animations";
844
- var BASE = DEFAULT_BASE;
845
- function configureApi(options) {
846
- if (options.baseUrl) BASE = options.baseUrl.replace(/\/+$/, "");
847
- }
848
- function apiBaseUrl() {
849
- return BASE;
850
- }
851
- var revisions = /* @__PURE__ */ new Map();
852
- var MissingAnimationRevisionError = class extends Error {
853
- };
854
- var AnimationStudioApiError = class extends Error {
855
- };
856
- function isRecord(value) {
857
- return typeof value === "object" && value !== null;
858
- }
859
- async function readJson(res) {
860
- if (!res.ok) {
861
- const text = await res.text();
862
- throw new AnimationStudioApiError(`HTTP ${res.status}: ${text}`);
863
- }
864
- return res.json();
865
- }
866
- function parseRevision(value) {
867
- if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1) {
868
- throw new TypeError("Animation revision is malformed");
869
- }
870
- return value;
871
- }
872
- function parseAnimationEnvelope(value) {
873
- if (!isRecord(value)) throw new TypeError("Animation response is malformed");
874
- return {
875
- def: animationDocumentSchema.parse(value.def),
876
- revision: parseRevision(value.revision)
877
- };
878
- }
879
- async function listAnimations() {
880
- const res = await fetch(BASE);
881
- const data = await readJson(res);
882
- if (!isRecord(data) || !Array.isArray(data.items))
883
- throw new TypeError("Animation list response is malformed");
884
- return data.items.map((item) => {
885
- if (!isRecord(item) || typeof item.id !== "string" || typeof item.title !== "string" || typeof item.description !== "string") {
886
- throw new TypeError("Animation summary is malformed");
887
- }
888
- return {
889
- id: item.id,
890
- title: item.title,
891
- description: item.description,
892
- ...typeof item.updatedAt === "string" ? { updatedAt: item.updatedAt } : {}
893
- };
894
- });
895
- }
896
- async function loadAnimation(id) {
897
- const res = await fetch(`${BASE}/${encodeURIComponent(id)}`);
898
- const data = parseAnimationEnvelope(await readJson(res));
899
- revisions.set(data.def.id, data.revision);
900
- return data.def;
901
- }
902
- async function saveAnimation(def) {
903
- const revision = revisions.get(def.id);
904
- if (revision === void 0)
905
- throw new MissingAnimationRevisionError(
906
- `Animation '${def.id}' has no loaded revision`
907
- );
908
- const res = await fetch(`${BASE}/${encodeURIComponent(def.id)}`, {
909
- method: "PUT",
910
- headers: { "Content-Type": "application/json" },
911
- body: JSON.stringify({ def, revision })
912
- });
913
- const data = parseAnimationEnvelope(await readJson(res));
914
- revisions.set(data.def.id, data.revision);
915
- return data.def;
916
- }
917
- async function createAnimation(id, title) {
918
- const res = await fetch(BASE, {
919
- method: "POST",
920
- headers: { "Content-Type": "application/json" },
921
- body: JSON.stringify({ id, title })
922
- });
923
- const data = parseAnimationEnvelope(await readJson(res));
924
- revisions.set(data.def.id, data.revision);
925
- return data.def;
926
- }
927
- async function deleteAnimation(id) {
928
- const res = await fetch(`${BASE}/${encodeURIComponent(id)}`, {
929
- method: "DELETE"
930
- });
931
- await readJson(res);
932
- revisions.delete(id);
933
- }
934
- async function duplicateAnimation(sourceId, newId, newTitle) {
935
- const source = await loadAnimation(sourceId);
936
- const cloned = { ...source, id: newId, title: newTitle };
937
- await createAnimation(newId, newTitle);
938
- return await saveAnimation(cloned);
939
- }
940
1014
 
941
- export { addAppearance, addChapter, addEffect, addElement, apiBaseUrl, beginTransient, canRedo, canUndo, childIdsOf, configureApi, configureHost, createAnimation, deleteAnimation, deleteChapter, deleteEffect, deleteElement, duplicateAnimation, endTransient, findContainingGroup, getCurrentSnapshot, getCurrentTime, getDef, getHistory, getSelectedElementIds, getSelection, groupBbox, groupElements, isDirty, isDraft, isElementSelected, isGroup, jumpBack, jumpForward, listAnimations, loadAnimation, markClean, moveElementToEnd, moveElementToFront, moveGroupBy, placeholderImageUrl, promoteDraftToSaved, redo, registerDataUriAsset, registerExternalAsset, registerInlineAsset, removeAppearance, removeTrack, removeTrackKeyframe, reorderElement, resetHistory, saveAnimation, setCurrentTime, setDef, setDraft, setElementValueAtTime, setSelection, setTrackKeyframe, subscribe, toggleSelectionFor, undo, ungroupElement, uniqueChapterId, uniqueEffectId, uniqueElementId, updateAppearance, updateCanvas, updateChapter, updateDuration, updateEffect, updateElementBase, updateMeta, updateSettings };
942
- //# sourceMappingURL=chunk-UE32Q6U5.js.map
943
- //# sourceMappingURL=chunk-UE32Q6U5.js.map
1015
+ export { addAppearance, addChapter, addEffect, addElement, animationDocumentFileName, animationDocumentToJson, apiBaseUrl, beginTransient, canRedo, canUndo, childIdsOf, configureAnimationRepository, configureApi, configureHost, createAnimation, deleteAnimation, deleteChapter, deleteEffect, deleteElement, downloadAnimationJson, duplicateAnimation, endTransient, findContainingGroup, garbageCollectAnimationAssets, getCurrentSnapshot, getCurrentTime, getDef, getHistory, getSelectedElementIds, getSelection, groupBbox, groupElements, importAnimation, isDirty, isDraft, isElementSelected, isGroup, jumpBack, jumpForward, listAnimations, loadAnimation, markClean, moveElementToEnd, moveElementToFront, moveGroupBy, placeholderImageUrl, promoteDraftToSaved, redo, registerDataUriAsset, registerExternalAsset, registerInlineAsset, removeAppearance, removeTrack, removeTrackKeyframe, reorderElement, resetHistory, saveAnimation, setCurrentTime, setDef, setDraft, setElementValueAtTime, setSelection, setTrackKeyframe, subscribe, toggleSelectionFor, undo, ungroupElement, uniqueChapterId, uniqueEffectId, uniqueElementId, updateAppearance, updateCanvas, updateChapter, updateDuration, updateEffect, updateElementBase, updateMeta, updateSettings };
1016
+ //# sourceMappingURL=chunk-Z2K5HFHI.js.map
1017
+ //# sourceMappingURL=chunk-Z2K5HFHI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/export-json.ts","../src/legacy/api.ts","../src/legacy/state/internals.ts","../src/legacy/state/core.ts","../src/legacy/state/history.ts","../src/legacy/state/elements.ts","../src/legacy/state/timeline.ts","../src/legacy/state/meta.ts","../src/legacy/studio-groups.ts","../src/legacy/host.ts"],"names":["animationDocumentSchema","next","id"],"mappings":"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","file":"chunk-Z2K5HFHI.js","sourcesContent":["import { animationDocumentSchema, type AnimationDocument } from \"@kokoa/clotho\";\n\n/** 검증된 애니메이션 문서를 읽기 쉬운 JSON으로 변환한다. */\nexport function animationDocumentToJson(def: AnimationDocument): string {\n const parsed = garbageCollectAnimationAssets(def);\n return `${JSON.stringify(parsed, null, 2)}\\n`;\n}\n\n/** 어떤 image 요소에서도 참조하지 않는 asset을 제거한 새 문서를 반환한다. */\nexport function garbageCollectAnimationAssets(\n def: AnimationDocument,\n): AnimationDocument {\n const parsed = animationDocumentSchema.parse(def);\n const used = new Set(\n parsed.elements\n .filter((element) => element.type === \"image\")\n .map((element) => element.assetId),\n );\n return animationDocumentSchema.parse({\n ...parsed,\n assets: Object.fromEntries(\n Object.entries(parsed.assets).filter(([id]) => used.has(id)),\n ),\n });\n}\n\n/** 문서 ID를 운영체제에서 안전하게 사용할 수 있는 파일 이름으로 바꾼다. */\nexport function animationDocumentFileName(def: AnimationDocument): string {\n const id = def.id.trim().replace(/[^a-zA-Z0-9._-]+/g, \"-\");\n return `${id || \"animation\"}.json`;\n}\n\n/** 현재 문서를 브라우저에서 JSON 파일로 내려받는다. */\nexport function downloadAnimationJson(def: AnimationDocument): void {\n if (\n typeof document === \"undefined\" ||\n typeof URL.createObjectURL !== \"function\"\n ) {\n throw new Error(\"JSON 파일은 브라우저에서만 내려받을 수 있습니다.\");\n }\n\n const url = URL.createObjectURL(\n new Blob([animationDocumentToJson(def)], {\n type: \"application/json;charset=utf-8\",\n }),\n );\n const link = document.createElement(\"a\");\n link.href = url;\n link.download = animationDocumentFileName(def);\n link.hidden = true;\n document.body.append(link);\n link.click();\n link.remove();\n URL.revokeObjectURL(url);\n}\n","import { animationDocumentSchema, type AnimationDocument } from \"@kokoa/clotho\";\nimport type { AnimationRepository, AnimationSummary } from \"../repository\";\nexport type { AnimationRepository, AnimationSummary } from \"../repository\";\n\n// Where documents live is the host's business, not the editor's.\n//\n// This was hardcoded to one blog's admin route. A standalone editor cannot assume any\n// particular backend, so the base is configurable and defaults to the previous value —\n// existing hosts keep working without a change.\nconst DEFAULT_BASE = \"/api/admin/animations\";\nlet BASE = DEFAULT_BASE;\n\n/** Point the editor at the host's animation endpoints. Call once at startup. */\nexport function configureApi(options: { baseUrl?: string }): void {\n if (options.baseUrl) BASE = options.baseUrl.replace(/\\/+$/, \"\");\n repository = httpRepository;\n}\n\n/** The base currently in use, for hosts that need to build matching links. */\nexport function apiBaseUrl(): string {\n return BASE;\n}\n\nconst revisions = new Map<string, number>();\n\nexport class MissingAnimationRevisionError extends Error {}\nexport class AnimationStudioApiError extends Error {}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nasync function readJson(res: Response): Promise<unknown> {\n if (!res.ok) {\n const text = await res.text();\n throw new AnimationStudioApiError(`HTTP ${res.status}: ${text}`);\n }\n return res.json();\n}\n\nfunction parseRevision(value: unknown): number {\n if (typeof value !== \"number\" || !Number.isSafeInteger(value) || value < 1) {\n throw new TypeError(\"Animation revision is malformed\");\n }\n return value;\n}\n\nfunction parseAnimationEnvelope(value: unknown): {\n readonly def: AnimationDocument;\n readonly revision: number;\n} {\n if (!isRecord(value)) throw new TypeError(\"Animation response is malformed\");\n return {\n def: animationDocumentSchema.parse(value.def),\n revision: parseRevision(value.revision),\n };\n}\n\nconst httpRepository: AnimationRepository = {\n list: async (): Promise<AnimationSummary[]> => {\n const res = await fetch(BASE);\n const data = await readJson(res);\n if (!isRecord(data) || !Array.isArray(data.items))\n throw new TypeError(\"Animation list response is malformed\");\n return data.items.map((item) => {\n if (\n !isRecord(item) ||\n typeof item.id !== \"string\" ||\n typeof item.title !== \"string\" ||\n typeof item.description !== \"string\"\n ) {\n throw new TypeError(\"Animation summary is malformed\");\n }\n return {\n id: item.id,\n title: item.title,\n description: item.description,\n ...(typeof item.updatedAt === \"string\"\n ? { updatedAt: item.updatedAt }\n : {}),\n };\n });\n },\n\n load: async (id: string): Promise<AnimationDocument> => {\n const res = await fetch(`${BASE}/${encodeURIComponent(id)}`);\n const data = parseAnimationEnvelope(await readJson(res));\n revisions.set(data.def.id, data.revision);\n return data.def;\n },\n\n save: async (def: AnimationDocument): Promise<AnimationDocument> => {\n const revision = revisions.get(def.id);\n if (revision === undefined)\n throw new MissingAnimationRevisionError(\n `Animation '${def.id}' has no loaded revision`,\n );\n const res = await fetch(`${BASE}/${encodeURIComponent(def.id)}`, {\n method: \"PUT\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ def, revision }),\n });\n const data = parseAnimationEnvelope(await readJson(res));\n revisions.set(data.def.id, data.revision);\n return data.def;\n },\n\n create: async (id: string, title: string): Promise<AnimationDocument> => {\n const res = await fetch(BASE, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ id, title }),\n });\n const data = parseAnimationEnvelope(await readJson(res));\n revisions.set(data.def.id, data.revision);\n return data.def;\n },\n\n delete: async (id: string): Promise<void> => {\n const res = await fetch(`${BASE}/${encodeURIComponent(id)}`, {\n method: \"DELETE\",\n });\n await readJson(res);\n revisions.delete(id);\n },\n};\n\nlet repository: AnimationRepository = httpRepository;\n\nexport function configureAnimationRepository(next: AnimationRepository): void {\n repository = next;\n}\n\nexport const listAnimations = (): Promise<AnimationSummary[]> =>\n repository.list();\nexport const loadAnimation = (id: string): Promise<AnimationDocument> =>\n repository.load(id);\nexport const saveAnimation = (\n def: AnimationDocument,\n): Promise<AnimationDocument> => repository.save(def);\nexport const createAnimation = (\n id: string,\n title: string,\n): Promise<AnimationDocument> => repository.create(id, title);\nexport const deleteAnimation = (id: string): Promise<void> =>\n repository.delete(id);\n\nexport async function importAnimation(\n def: AnimationDocument,\n): Promise<AnimationDocument> {\n const parsed = animationDocumentSchema.parse(def);\n try {\n await repository.load(parsed.id);\n } catch {\n await repository.create(parsed.id, parsed.title || parsed.id);\n }\n return repository.save(parsed);\n}\n\nexport async function duplicateAnimation(\n sourceId: string,\n newId: string,\n newTitle: string,\n): Promise<AnimationDocument> {\n const source = await loadAnimation(sourceId);\n const cloned: AnimationDocument = { ...source, id: newId, title: newTitle };\n await createAnimation(newId, newTitle);\n return await saveAnimation(cloned);\n}\n","import type { AnimationDocument } from \"@kokoa/clotho\";\nimport { animationDocumentSchema } from \"@kokoa/clotho\";\nimport type {\n HistoryEntry,\n HistoryKind,\n InternalState,\n Listener,\n} from \"./types\";\n\nconst listeners = new Set<Listener>();\n\nexport const state: InternalState = {\n def: null,\n dirty: false,\n selection: { kind: \"none\" },\n currentTime: 0,\n isDraft: false,\n};\n\nconst HISTORY_LIMIT = 60;\n\nexport const past: HistoryEntry[] = [];\nexport const future: HistoryEntry[] = [];\n\nlet inTransient = false;\n\nexport function snapshotJson(): string | null {\n return state.def ? JSON.stringify(state.def) : null;\n}\n\nexport function pushHistory(label: string, kind: HistoryKind): void {\n const snap = snapshotJson();\n if (snap === null) return;\n past.push({ snap, label, kind, timestamp: Date.now() });\n if (past.length > HISTORY_LIMIT) past.shift();\n future.length = 0;\n}\n\nexport function setInTransient(value: boolean): void {\n inTransient = value;\n}\n\nexport function subscribe(fn: Listener): () => void {\n listeners.add(fn);\n return () => listeners.delete(fn);\n}\n\nexport function emit(): void {\n for (const fn of listeners) fn();\n}\n\nexport function mutateDef(\n fn: (def: AnimationDocument) => void,\n label = \"edit\",\n kind: HistoryKind = \"other\",\n): void {\n if (!state.def) return;\n if (!inTransient) pushHistory(label, kind);\n const cloned = JSON.parse(JSON.stringify(state.def));\n fn(cloned);\n const parsed = animationDocumentSchema.safeParse(cloned);\n if (!parsed.success) {\n past.pop();\n console.warn(\"[studio.state] invalid mutation\", parsed.error.issues);\n return;\n }\n state.def = parsed.data;\n state.dirty = true;\n emit();\n}\n","import type { AnimationDocument, SnapshotMap } from \"@kokoa/clotho\";\nimport { computeSnapshot } from \"@kokoa/clotho\";\nimport type { Selection } from \"./types\";\nimport { emit, state, past, future } from \"./internals\";\n\nexport function isDraft(): boolean {\n return state.isDraft;\n}\n\nexport function setDraft(def: AnimationDocument): void {\n state.def = def;\n state.dirty = false;\n state.isDraft = true;\n state.selection = { kind: \"none\" };\n state.currentTime = 0;\n past.length = 0;\n future.length = 0;\n emit();\n}\n\nexport function promoteDraftToSaved(): void {\n state.isDraft = false;\n emit();\n}\n\nexport function getDef(): AnimationDocument | null {\n return state.def;\n}\n\nexport function getSelection(): Selection {\n return state.selection;\n}\n\nexport function isDirty(): boolean {\n return state.dirty;\n}\n\nexport function getCurrentTime(): number {\n return state.currentTime;\n}\n\nexport function setCurrentTime(time: number): void {\n state.currentTime = Math.max(0, Math.round(time));\n emit();\n}\n\nexport function setDef(def: AnimationDocument | null, markDirty = false): void {\n state.def = def;\n state.dirty = markDirty;\n state.isDraft = false;\n state.selection = { kind: \"none\" };\n state.currentTime = 0;\n past.length = 0;\n future.length = 0;\n emit();\n}\n\nexport function markClean(): void {\n state.dirty = false;\n emit();\n}\n\nexport function setSelection(sel: Selection): void {\n state.selection = sel;\n emit();\n}\n\nexport function getSelectedElementIds(sel: Selection): string[] {\n if (sel.kind === \"element\") return [sel.elementId];\n if (sel.kind === \"elements\") return sel.elementIds;\n return [];\n}\n\nexport function isElementSelected(sel: Selection, id: string): boolean {\n if (sel.kind === \"element\") return sel.elementId === id;\n if (sel.kind === \"elements\") return sel.elementIds.includes(id);\n return false;\n}\n\nexport function toggleSelectionFor(sel: Selection, id: string): Selection {\n const cur = getSelectedElementIds(sel);\n if (cur.includes(id)) {\n const next = cur.filter((x) => x !== id);\n if (next.length === 0) return { kind: \"none\" };\n if (next.length === 1) return { kind: \"element\", elementId: next[0] };\n return { kind: \"elements\", elementIds: next };\n }\n const next = [...cur, id];\n if (next.length === 1) return { kind: \"element\", elementId: next[0] };\n return { kind: \"elements\", elementIds: next };\n}\n\nexport function getCurrentSnapshot(): SnapshotMap {\n if (!state.def) return new Map();\n return computeSnapshot(state.def, state.currentTime);\n}\n","import type { HistoryEntry, HistoryKind } from \"./types\";\nimport {\n emit,\n future,\n past,\n pushHistory,\n setInTransient,\n snapshotJson,\n state,\n} from \"./internals\";\n\nexport function beginTransient(\n label = \"edit\",\n kind: HistoryKind = \"other\",\n): void {\n if (!state.def) return;\n pushHistory(label, kind);\n setInTransient(true);\n}\n\nexport function endTransient(): void {\n setInTransient(false);\n}\n\nexport function canUndo(): boolean {\n return past.length > 0;\n}\n\nexport function canRedo(): boolean {\n return future.length > 0;\n}\n\nexport function undo(): void {\n if (past.length === 0) return;\n const prev = past[past.length - 1]!;\n const cur = snapshotJson();\n if (cur !== null) {\n future.push({\n snap: cur,\n label: prev.label,\n kind: prev.kind,\n timestamp: prev.timestamp,\n });\n }\n past.pop();\n state.def = JSON.parse(prev.snap);\n state.dirty = true;\n emit();\n}\n\nexport function redo(): void {\n if (future.length === 0) return;\n const next = future[future.length - 1]!;\n const cur = snapshotJson();\n if (cur !== null) {\n past.push({\n snap: cur,\n label: next.label,\n kind: next.kind,\n timestamp: next.timestamp,\n });\n }\n future.pop();\n state.def = JSON.parse(next.snap);\n state.dirty = true;\n emit();\n}\n\nexport function resetHistory(): void {\n past.length = 0;\n future.length = 0;\n}\n\nexport function getHistory(): {\n past: readonly HistoryEntry[];\n future: readonly HistoryEntry[];\n} {\n return { past, future };\n}\n\nexport function jumpBack(steps: number): void {\n if (steps <= 0 || past.length === 0) return;\n const n = Math.min(steps, past.length);\n for (let i = 0; i < n; i += 1) undo();\n}\n\nexport function jumpForward(steps: number): void {\n if (steps <= 0 || future.length === 0) return;\n const n = Math.min(steps, future.length);\n for (let i = 0; i < n; i += 1) redo();\n}\n","import type {\n AnimationDocument,\n AnimationElement,\n Appearance,\n PropertyTrack,\n TrackKeyframe,\n} from \"@kokoa/clotho\";\nimport type { HistoryKind } from \"./types\";\nimport { emit, mutateDef, state } from \"./internals\";\n\nfunction ensureAppearance(el: AnimationElement, def: AnimationDocument): void {\n if (!el.appearances || el.appearances.length === 0) {\n el.appearances = [\n { start: 0, end: def.duration, entryDuration: 300, exitDuration: 300 },\n ];\n }\n}\n\nexport function addElement(el: AnimationElement): void {\n const kind: HistoryKind = el.type === \"group\" ? \"group\" : \"add\";\n const label = el.type === \"group\" ? \"그룹 생성\" : `요소 추가: ${el.type}`;\n mutateDef(\n (def) => {\n const cloned = JSON.parse(JSON.stringify(el)) as AnimationElement;\n ensureAppearance(cloned, def);\n if (!cloned.tracks) cloned.tracks = [];\n def.elements.push(cloned);\n },\n label,\n kind,\n );\n state.selection = { kind: \"element\", elementId: el.id };\n emit();\n}\n\nexport function deleteElement(id: string): void {\n const targetEl = state.def?.elements.find((e) => e.id === id);\n const isGroupKind = targetEl?.type === \"group\";\n mutateDef(\n (def) => {\n def.elements = def.elements.filter((e) => e.id !== id);\n def.effects = def.effects.filter((e) => e.elementId !== id);\n // Anything that pointed at the deleted element is re-rooted. A dangling parentId\n // would make the tree builder report a missing parent on every render.\n for (const el of def.elements) {\n if (el.parentId === id) delete el.parentId;\n }\n },\n isGroupKind ? `그룹 해제` : `요소 삭제: ${id}`,\n isGroupKind ? \"group\" : \"delete\",\n );\n if (state.selection.kind === \"element\" && state.selection.elementId === id) {\n state.selection = { kind: \"none\" };\n } else if (state.selection.kind === \"elements\") {\n const remaining = state.selection.elementIds.filter((x) => x !== id);\n if (remaining.length === 0) state.selection = { kind: \"none\" };\n else if (remaining.length === 1)\n state.selection = { kind: \"element\", elementId: remaining[0] };\n else state.selection = { kind: \"elements\", elementIds: remaining };\n }\n emit();\n}\n\nfunction labelForPatch(\n id: string,\n patch: Record<string, unknown>,\n): { label: string; kind: HistoryKind } {\n const keys = Object.keys(patch);\n if (keys.length === 0) return { label: `요소 수정: ${id}`, kind: \"other\" };\n const posKeys = [\"x\", \"y\", \"cx\", \"cy\", \"x1\", \"y1\", \"x2\", \"y2\", \"points\"];\n const sizeKeys = [\"width\", \"height\", \"r\", \"fontSize\", \"cellWidth\"];\n const styleKeys = [\n \"fill\",\n \"stroke\",\n \"strokeWidth\",\n \"color\",\n \"opacity\",\n \"cornerRadius\",\n \"labelColor\",\n \"labelSize\",\n ];\n if (keys.some((k) => posKeys.includes(k)))\n return { label: `이동: ${id}`, kind: \"move\" };\n if (keys.some((k) => sizeKeys.includes(k)))\n return { label: `크기 변경: ${id}`, kind: \"resize\" };\n if (keys.includes(\"rotation\"))\n return { label: `회전: ${id}`, kind: \"rotate\" };\n if (keys.some((k) => styleKeys.includes(k)))\n return { label: `스타일: ${id} (${keys.join(\", \")})`, kind: \"style\" };\n if (keys.includes(\"name\")) return { label: `이름 변경: ${id}`, kind: \"meta\" };\n return { label: `요소 수정: ${id} (${keys.join(\", \")})`, kind: \"other\" };\n}\n\nexport function updateElementBase(\n id: string,\n patch: Record<string, unknown>,\n): void {\n const { label, kind } = labelForPatch(id, patch);\n mutateDef(\n (def) => {\n const idx = def.elements.findIndex((e) => e.id === id);\n if (idx < 0) return;\n const baseEl = def.elements[idx];\n const merged: Record<string, unknown> = {\n ...(baseEl as unknown as Record<string, unknown>),\n };\n for (const [k, v] of Object.entries(patch)) {\n if (v === null || v === undefined) delete merged[k];\n else merged[k] = v;\n }\n def.elements[idx] = merged as unknown as AnimationElement;\n },\n label,\n kind,\n );\n}\n\nexport function reorderElement(\n sourceId: string,\n targetId: string,\n position: \"before\" | \"after\",\n): void {\n mutateDef(\n (def) => {\n const srcIdx = def.elements.findIndex((e) => e.id === sourceId);\n if (srcIdx < 0) return;\n const [moved] = def.elements.splice(srcIdx, 1);\n let targetIdx = def.elements.findIndex((e) => e.id === targetId);\n if (targetIdx < 0) {\n def.elements.push(moved);\n return;\n }\n if (position === \"after\") targetIdx += 1;\n def.elements.splice(targetIdx, 0, moved);\n },\n `순서 변경: ${sourceId}`,\n \"reorder\",\n );\n}\n\nexport function moveElementToEnd(id: string): void {\n mutateDef(\n (def) => {\n const idx = def.elements.findIndex((e) => e.id === id);\n if (idx < 0) return;\n const [moved] = def.elements.splice(idx, 1);\n def.elements.push(moved);\n },\n `맨 앞으로: ${id}`,\n \"reorder\",\n );\n}\n\nexport function moveElementToFront(id: string): void {\n mutateDef(\n (def) => {\n const idx = def.elements.findIndex((e) => e.id === id);\n if (idx < 0) return;\n const [moved] = def.elements.splice(idx, 1);\n def.elements.unshift(moved);\n },\n `맨 뒤로: ${id}`,\n \"reorder\",\n );\n}\n\nexport function addAppearance(id: string, ap: Appearance): void {\n mutateDef(\n (def) => {\n const el = def.elements.find((e) => e.id === id);\n if (!el) return;\n el.appearances.push(ap);\n el.appearances.sort((a, b) => a.start - b.start);\n },\n `출현 추가: ${id}`,\n \"appearance\",\n );\n}\n\nexport function updateAppearance(\n id: string,\n apIdx: number,\n patch: Partial<Appearance>,\n): void {\n mutateDef(\n (def) => {\n const el = def.elements.find((e) => e.id === id);\n if (!el || !el.appearances[apIdx]) return;\n el.appearances[apIdx] = { ...el.appearances[apIdx], ...patch };\n el.appearances.sort((a, b) => a.start - b.start);\n },\n `출현 조정: ${id}`,\n \"appearance\",\n );\n}\n\nexport function removeAppearance(id: string, apIdx: number): void {\n mutateDef(\n (def) => {\n const el = def.elements.find((e) => e.id === id);\n if (!el) return;\n el.appearances.splice(apIdx, 1);\n if (el.appearances.length === 0) ensureAppearance(el, def);\n },\n `출현 삭제: ${id}`,\n \"appearance\",\n );\n}\n\nfunction findTrack(\n el: AnimationElement,\n property: string,\n): PropertyTrack | undefined {\n return el.tracks.find((t) => t.property === property);\n}\n\nexport function setTrackKeyframe(\n elementId: string,\n property: string,\n time: number,\n value: TrackKeyframe[\"value\"],\n): void {\n mutateDef(\n (def) => {\n const el = def.elements.find((e) => e.id === elementId);\n if (!el) return;\n let track = findTrack(el, property);\n if (!track) {\n track = { property, keyframes: [] };\n el.tracks.push(track);\n }\n const existing = track.keyframes.find((k) => k.time === time);\n if (existing) {\n existing.value = value;\n } else {\n track.keyframes.push({ time, value });\n track.keyframes.sort((a, b) => a.time - b.time);\n }\n },\n `keyframe ${property} @ ${time}ms`,\n \"track\",\n );\n}\n\nexport function removeTrackKeyframe(\n elementId: string,\n property: string,\n time: number,\n): void {\n mutateDef(\n (def) => {\n const el = def.elements.find((e) => e.id === elementId);\n if (!el) return;\n const track = findTrack(el, property);\n if (!track) return;\n track.keyframes = track.keyframes.filter((k) => k.time !== time);\n if (track.keyframes.length === 0) {\n el.tracks = el.tracks.filter((t) => t.property !== property);\n }\n },\n `keyframe 삭제 ${property} @ ${time}ms`,\n \"track\",\n );\n}\n\nexport function setElementValueAtTime(\n elementId: string,\n patch: Record<string, unknown>,\n): void {\n const time = state.currentTime;\n if (time <= 0) {\n updateElementBase(elementId, patch);\n return;\n }\n if (!state.def) return;\n const el = state.def.elements.find((e) => e.id === elementId);\n if (!el) return;\n for (const [prop, value] of Object.entries(patch)) {\n if (value === null || value === undefined) continue;\n if (\n typeof value !== \"string\" &&\n typeof value !== \"number\" &&\n typeof value !== \"boolean\"\n )\n continue;\n const hasTrack = el.tracks.some((t) => t.property === prop);\n if (!hasTrack) {\n const baseVal = (el as unknown as Record<string, unknown>)[prop];\n if (\n typeof baseVal === \"string\" ||\n typeof baseVal === \"number\" ||\n typeof baseVal === \"boolean\"\n ) {\n setTrackKeyframe(elementId, prop, 0, baseVal);\n }\n }\n setTrackKeyframe(elementId, prop, time, value);\n }\n}\n\nexport function removeTrack(elementId: string, property: string): void {\n mutateDef(\n (def) => {\n const el = def.elements.find((e) => e.id === elementId);\n if (!el) return;\n el.tracks = el.tracks.filter((t) => t.property !== property);\n },\n `트랙 삭제: ${property}`,\n \"track\",\n );\n}\n","import type { AnimationEffect, Chapter } from \"@kokoa/clotho\";\nimport { emit, mutateDef, state } from \"./internals\";\n\nexport function addChapter(c: Chapter): void {\n mutateDef(\n (def) => {\n def.chapters.push(c);\n def.chapters.sort((a, b) => a.time - b.time);\n },\n `Chapter 추가: ${c.label || c.id}`,\n \"chapter\",\n );\n state.selection = { kind: \"chapter\", chapterId: c.id };\n emit();\n}\n\nexport function updateChapter(id: string, patch: Partial<Chapter>): void {\n const keys = Object.keys(patch).join(\", \");\n mutateDef(\n (def) => {\n const idx = def.chapters.findIndex((c) => c.id === id);\n if (idx < 0) return;\n def.chapters[idx] = { ...def.chapters[idx], ...patch };\n def.chapters.sort((a, b) => a.time - b.time);\n },\n `Chapter 수정: ${id} (${keys})`,\n \"chapter\",\n );\n}\n\nexport function deleteChapter(id: string): void {\n mutateDef(\n (def) => {\n def.chapters = def.chapters.filter((c) => c.id !== id);\n },\n `Chapter 삭제: ${id}`,\n \"chapter\",\n );\n if (state.selection.kind === \"chapter\" && state.selection.chapterId === id) {\n state.selection = { kind: \"none\" };\n }\n emit();\n}\n\nexport function addEffect(eff: AnimationEffect): void {\n mutateDef(\n (def) => {\n def.effects.push(eff);\n def.effects.sort((a, b) => a.time - b.time);\n },\n `효과 추가: ${eff.type}`,\n \"effect\",\n );\n}\n\nexport function updateEffect(\n id: string,\n patch: Partial<AnimationEffect>,\n): void {\n mutateDef(\n (def) => {\n const idx = def.effects.findIndex((e) => e.id === id);\n if (idx < 0) return;\n def.effects[idx] = { ...def.effects[idx], ...patch } as AnimationEffect;\n def.effects.sort((a, b) => a.time - b.time);\n },\n `효과 수정: ${id}`,\n \"effect\",\n );\n}\n\nexport function deleteEffect(id: string): void {\n mutateDef(\n (def) => {\n def.effects = def.effects.filter((e) => e.id !== id);\n },\n `효과 삭제: ${id}`,\n \"effect\",\n );\n if (state.selection.kind === \"effect\" && state.selection.effectId === id) {\n state.selection = { kind: \"none\" };\n }\n emit();\n}\n\nexport function updateDuration(ms: number): void {\n mutateDef(\n (def) => {\n def.duration = Math.max(0, Math.round(ms));\n for (const el of def.elements) {\n for (const ap of el.appearances) {\n if (ap.end > def.duration) ap.end = def.duration;\n if (ap.start > def.duration) ap.start = def.duration;\n }\n }\n for (const ch of def.chapters) {\n if (ch.time > def.duration) ch.time = def.duration;\n }\n for (const eff of def.effects) {\n if (eff.time > def.duration) eff.time = def.duration;\n }\n },\n `duration: ${ms} ms`,\n \"meta\",\n );\n if (state.currentTime > ms) state.currentTime = ms;\n}\n","import type { AnimationDocument } from \"@kokoa/clotho\";\nimport { encodeImageAsset, inlineAssetFromDataUri } from \"@kokoa/clotho\";\nimport { mutateDef, state } from \"./internals\";\nimport { getDef } from \"./core\";\n\nexport function updateMeta(\n patch: Partial<Pick<AnimationDocument, \"title\" | \"description\">>,\n): void {\n const keys = Object.keys(patch).join(\", \");\n mutateDef(\n (def) => {\n Object.assign(def, patch);\n },\n `메타 수정: ${keys}`,\n \"meta\",\n );\n}\n\nexport function updateCanvas(\n patch: Partial<AnimationDocument[\"canvas\"]>,\n): void {\n const keys = Object.keys(patch).join(\", \");\n mutateDef(\n (def) => {\n def.canvas = { ...def.canvas, ...patch };\n },\n `캔버스: ${keys}`,\n \"canvas\",\n );\n}\n\nexport function updateSettings(\n patch: Partial<AnimationDocument[\"settings\"]>,\n): void {\n const keys = Object.keys(patch).join(\", \");\n mutateDef(\n (def) => {\n def.settings = { ...def.settings, ...patch };\n },\n `설정: ${keys}`,\n \"settings\",\n );\n}\n\nexport function uniqueElementId(type: string): string {\n if (!state.def) return type + \"-1\";\n const used = new Set(state.def.elements.map((e) => e.id));\n let i = 1;\n while (used.has(`${type}-${i}`)) i += 1;\n return `${type}-${i}`;\n}\n\nexport function uniqueChapterId(): string {\n if (!state.def) return \"chapter-1\";\n const used = new Set(state.def.chapters.map((c) => c.id));\n let i = 1;\n while (used.has(`chapter-${i}`)) i += 1;\n return `chapter-${i}`;\n}\n\nexport function uniqueEffectId(): string {\n if (!state.def) return \"effect-1\";\n const used = new Set(state.def.effects.map((e) => e.id));\n let i = 1;\n while (used.has(`effect-${i}`)) i += 1;\n return `effect-${i}`;\n}\n\n/**\n * Register an external image URL as a document asset and return its id.\n *\n * clotho v1 keeps image sources in a document-level `assets` registry rather than on the\n * element, so a document can be self-contained or host-resolved rather than tied to one\n * site's paths. An identical URL reuses its entry, so dropping the same image twice does\n * not grow the document.\n */\nexport function registerExternalAsset(url: string): string {\n const def = getDef();\n if (def) {\n for (const [id, asset] of Object.entries(def.assets)) {\n if (asset.kind === \"external\" && asset.url === url) return id;\n }\n }\n const id = uniqueAssetId();\n mutateDef(\n (draft) => {\n draft.assets[id] = { kind: \"external\", url };\n },\n `에셋 등록: ${id}`,\n \"asset\",\n );\n return id;\n}\n\n/** Register raw image bytes as an inline (base64) asset and return its id. */\nexport function registerInlineAsset(bytes: Uint8Array, mime: string): string {\n const { asset } = encodeImageAsset(bytes, mime);\n const def = getDef();\n if (def) {\n for (const [id, existing] of Object.entries(def.assets)) {\n if (\n existing.kind === \"inline\" &&\n existing.mime === asset.mime &&\n existing.data === asset.data\n )\n return id;\n }\n }\n const id = uniqueAssetId();\n mutateDef(\n (draft) => {\n draft.assets[id] = asset;\n },\n `에셋 등록: ${id}`,\n \"asset\",\n );\n return id;\n}\n\nfunction uniqueAssetId(): string {\n const def = getDef();\n const existing = def ? new Set(Object.keys(def.assets)) : new Set<string>();\n let n = 1;\n while (existing.has(`asset-${n}`)) n += 1;\n return `asset-${n}`;\n}\n\n/**\n * Register a `data:` URI as an inline asset and return its id.\n *\n * What a dropped or pasted file becomes. Storing it inline keeps the document\n * self-contained; a non-image or non-base64 URI falls back to an external reference so\n * the element still points at something.\n */\nexport function registerDataUriAsset(dataUri: string): string {\n const inline = inlineAssetFromDataUri(dataUri);\n if (!inline) return registerExternalAsset(dataUri);\n const def = getDef();\n if (def) {\n for (const [id, existing] of Object.entries(def.assets)) {\n if (\n existing.kind === \"inline\" &&\n existing.mime === inline.mime &&\n existing.data === inline.data\n )\n return id;\n }\n }\n const id = uniqueAssetId();\n mutateDef(\n (draft) => {\n draft.assets[id] = inline;\n },\n `에셋 등록: ${id}`,\n \"asset\",\n );\n return id;\n}\n","import type { AnimationElement, GroupElement } from \"@kokoa/clotho\";\nimport {\n addElement,\n deleteElement,\n getDef,\n setSelection,\n uniqueElementId,\n updateElementBase,\n} from \"./state\";\n\nexport function isGroup(el: AnimationElement): el is GroupElement {\n return el.type === \"group\";\n}\n\n/** Direct children of a group, in document order (which is also paint order). */\nexport function childIdsOf(groupId: string): string[] {\n const def = getDef();\n if (!def) return [];\n return def.elements\n .filter((el) => el.parentId === groupId)\n .map((el) => el.id);\n}\n\n/**\n * The outermost group containing `elementId`, or null when it is at the root.\n *\n * clotho v1 groups by `parentId` on the child rather than `group.childIds`. The old\n * model could not work: a reference list produces no nested `<g>`, so a group's\n * transform never reached its children — and the legacy renderer had no `group` branch\n * at all. Grouping does something for the first time here.\n */\nexport function findContainingGroup(elementId: string): GroupElement | null {\n const def = getDef();\n if (!def) return null;\n const element = def.elements.find((el) => el.id === elementId);\n const parentId = element?.parentId;\n if (parentId === undefined) return null;\n const parent = def.elements.find((el) => el.id === parentId);\n if (!parent || !isGroup(parent)) return null;\n return findContainingGroup(parent.id) ?? parent;\n}\n\nexport function expandToLeafIds(ids: string[]): string[] {\n const def = getDef();\n if (!def) return ids;\n const seen = new Set<string>();\n const stack = [...ids];\n while (stack.length) {\n const id = stack.pop()!;\n if (seen.has(id)) continue;\n seen.add(id);\n const el = def.elements.find((e) => e.id === id);\n if (el && isGroup(el)) {\n for (const childId of childIdsOf(el.id)) stack.push(childId);\n }\n }\n const out: string[] = [];\n for (const id of seen) {\n const el = def.elements.find((e) => e.id === id);\n if (el && !isGroup(el)) out.push(id);\n }\n return out;\n}\n\nexport function groupBbox(\n groupId: string,\n): { x: number; y: number; w: number; h: number } | null {\n const def = getDef();\n if (!def) return null;\n const leafIds = expandToLeafIds([groupId]);\n let minX = Infinity,\n minY = Infinity,\n maxX = -Infinity,\n maxY = -Infinity;\n let any = false;\n for (const id of leafIds) {\n const el = def.elements.find((e) => e.id === id);\n if (!el) continue;\n const b = elementBbox(el);\n if (!b) continue;\n any = true;\n if (b.x < minX) minX = b.x;\n if (b.y < minY) minY = b.y;\n if (b.x + b.w > maxX) maxX = b.x + b.w;\n if (b.y + b.h > maxY) maxY = b.y + b.h;\n }\n return any ? { x: minX, y: minY, w: maxX - minX, h: maxY - minY } : null;\n}\n\nfunction elementBbox(\n el: AnimationElement,\n): { x: number; y: number; w: number; h: number } | null {\n if (el.type === \"rect\" || el.type === \"image\")\n return { x: el.x, y: el.y, w: el.width, h: el.height };\n if (el.type === \"circle\")\n return { x: el.cx - el.r, y: el.cy - el.r, w: el.r * 2, h: el.r * 2 };\n if (el.type === \"text\")\n return {\n x: el.x - 40,\n y: el.y - (el.fontSize ?? 16),\n w: 80,\n h: el.fontSize ?? 16,\n };\n if (el.type === \"line\" || el.type === \"arrow\") {\n if (\n typeof el.x1 !== \"number\" ||\n typeof el.x2 !== \"number\" ||\n typeof el.y1 !== \"number\" ||\n typeof el.y2 !== \"number\"\n )\n return null;\n return {\n x: Math.min(el.x1, el.x2),\n y: Math.min(el.y1, el.y2),\n w: Math.abs(el.x2 - el.x1),\n h: Math.abs(el.y2 - el.y1),\n };\n }\n if (el.type === \"polygon\") {\n let minX = Infinity,\n minY = Infinity,\n maxX = -Infinity,\n maxY = -Infinity;\n let any = false;\n for (const pair of el.points.trim().split(/\\s+/)) {\n const [x, y] = pair.split(\",\").map(Number);\n if (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n any = true;\n if (x < minX) minX = x;\n if (y < minY) minY = y;\n if (x > maxX) maxX = x;\n if (y > maxY) maxY = y;\n }\n return any ? { x: minX, y: minY, w: maxX - minX, h: maxY - minY } : null;\n }\n if (el.type === \"path\") return { x: el.x ?? 0, y: el.y ?? 0, w: 60, h: 60 };\n return null;\n}\n\nfunction shiftLeafBy(el: AnimationElement, dx: number, dy: number): void {\n if (dx === 0 && dy === 0) return;\n if (el.type === \"rect\" || el.type === \"image\" || el.type === \"text\") {\n updateElementBase(el.id, { x: el.x + dx, y: el.y + dy });\n } else if (el.type === \"circle\") {\n updateElementBase(el.id, { cx: el.cx + dx, cy: el.cy + dy });\n } else if (el.type === \"line\" || el.type === \"arrow\") {\n const patch: Record<string, unknown> = {};\n if (typeof el.x1 === \"number\") patch.x1 = el.x1 + dx;\n if (typeof el.y1 === \"number\") patch.y1 = el.y1 + dy;\n if (typeof el.x2 === \"number\") patch.x2 = el.x2 + dx;\n if (typeof el.y2 === \"number\") patch.y2 = el.y2 + dy;\n updateElementBase(el.id, patch);\n } else if (el.type === \"path\") {\n updateElementBase(el.id, { x: (el.x ?? 0) + dx, y: (el.y ?? 0) + dy });\n } else if (el.type === \"polygon\") {\n const shifted = el.points\n .trim()\n .split(/\\s+/)\n .map((pair) => {\n const [x, y] = pair.split(\",\").map(Number);\n if (Number.isFinite(x) && Number.isFinite(y))\n return `${(x + dx).toFixed(1)},${(y + dy).toFixed(1)}`;\n return pair;\n })\n .join(\" \");\n updateElementBase(el.id, { points: shifted });\n }\n}\n\nexport function moveGroupBy(groupId: string, dx: number, dy: number): void {\n const def = getDef();\n if (!def) return;\n const leafIds = expandToLeafIds([groupId]);\n for (const id of leafIds) {\n const el = def.elements.find((e) => e.id === id);\n if (el) shiftLeafBy(el, dx, dy);\n }\n const group = def.elements.find((e) => e.id === groupId);\n if (group && isGroup(group)) {\n updateElementBase(groupId, { x: group.x + dx, y: group.y + dy });\n }\n}\n\nexport function groupElements(ids: string[]): string | null {\n if (ids.length < 2) return null;\n const def = getDef();\n if (!def) return null;\n const valid = ids.filter((id) => def.elements.some((e) => e.id === id));\n if (valid.length < 2) return null;\n const newId = uniqueElementId(\"group\");\n const bbox = (() => {\n let minX = Infinity,\n minY = Infinity;\n for (const id of valid) {\n const el = def.elements.find((e) => e.id === id);\n if (!el) continue;\n const b = elementBbox(el);\n if (!b) continue;\n if (b.x < minX) minX = b.x;\n if (b.y < minY) minY = b.y;\n }\n return {\n x: Number.isFinite(minX) ? minX : 0,\n y: Number.isFinite(minY) ? minY : 0,\n };\n })();\n const group: GroupElement = {\n type: \"group\",\n id: newId,\n name: `Group ${newId.split(\"-\")[1] ?? \"\"}`.trim(),\n rotation: 0,\n appearances: [],\n tracks: [],\n // Children keep their absolute coordinates, so the group's own transform starts at\n // the identity. Setting x/y here would shift every member on the next render.\n x: 0,\n y: 0,\n };\n addElement(group);\n for (const id of valid) updateElementBase(id, { parentId: newId });\n setSelection({ kind: \"element\", elementId: newId });\n return newId;\n}\n\nexport function ungroupElement(groupId: string): string[] {\n const def = getDef();\n if (!def) return [];\n const group = def.elements.find((e) => e.id === groupId);\n if (!group || !isGroup(group)) return [];\n const childIds = childIdsOf(groupId);\n // Clear the pointers before removing the group, or the children would be re-rooted\n // by the tree builder and reported as having a missing parent.\n for (const id of childIds) updateElementBase(id, { parentId: undefined });\n deleteElement(groupId);\n if (childIds.length === 1) {\n setSelection({ kind: \"element\", elementId: childIds[0] });\n } else if (childIds.length > 1) {\n setSelection({ kind: \"elements\", elementIds: childIds });\n } else {\n setSelection({ kind: \"none\" });\n }\n return childIds;\n}\n","// Host-supplied resources.\n//\n// The Studio grew inside a blog, so a few of its paths were that blog's: the admin API\n// route, the uploads directory. A package cannot assume any of them. Each is now a\n// setting with the original value as the default, so an existing host keeps working\n// without changing anything and a new one is not stuck with someone else's layout.\n\nlet placeholderUrl = \"/uploads/placeholder.png\";\n\nexport interface HostOptions {\n /** Image used when inserting a placeholder image element. */\n readonly placeholderImageUrl?: string;\n}\n\nexport function configureHost(options: HostOptions): void {\n if (options.placeholderImageUrl) placeholderUrl = options.placeholderImageUrl;\n}\n\nexport function placeholderImageUrl(): string {\n return placeholderUrl;\n}\n"]}