@ai-game-assets/phaser 0.5.5 → 0.6.0
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/dist/animations.d.ts +12 -2
- package/dist/animations.d.ts.map +1 -1
- package/dist/animations.js +35 -1
- package/dist/animations.js.map +1 -1
- package/dist/derive-dialog.d.ts +1 -1
- package/dist/derive-dialog.d.ts.map +1 -1
- package/dist/derive-dialog.js +0 -13
- package/dist/derive-dialog.js.map +1 -1
- package/dist/designer-support.d.ts +6 -2
- package/dist/designer-support.d.ts.map +1 -1
- package/dist/designer-support.js +194 -54
- package/dist/designer-support.js.map +1 -1
- package/dist/designer.d.ts.map +1 -1
- package/dist/designer.js +204 -66
- package/dist/designer.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/phaser-types.d.ts +1 -0
- package/dist/phaser-types.d.ts.map +1 -1
- package/dist/runtime.d.ts +33 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +75 -0
- package/dist/runtime.js.map +1 -1
- package/package.json +2 -2
package/dist/designer-support.js
CHANGED
|
@@ -126,7 +126,12 @@ export function createDesignerElements(options, manifest, selectedAssetId) {
|
|
|
126
126
|
currentTouchUpButton.className = "ai-game-assets-designer__animate-button";
|
|
127
127
|
currentTouchUpButton.textContent = "Touch up...";
|
|
128
128
|
currentTouchUpButton.hidden = true;
|
|
129
|
-
|
|
129
|
+
const currentRevertButton = document.createElement("button");
|
|
130
|
+
currentRevertButton.type = "button";
|
|
131
|
+
currentRevertButton.className = "ai-game-assets-designer__animate-button";
|
|
132
|
+
currentRevertButton.textContent = "Revert preview";
|
|
133
|
+
currentRevertButton.hidden = true;
|
|
134
|
+
currentPreview.append(currentImage, currentAudio, currentAnimation, currentAnimationButton, currentTouchUpButton, currentRevertButton);
|
|
130
135
|
const regenerateButton = document.createElement("button");
|
|
131
136
|
regenerateButton.type = "button";
|
|
132
137
|
regenerateButton.textContent = "Regenerate";
|
|
@@ -161,6 +166,7 @@ export function createDesignerElements(options, manifest, selectedAssetId) {
|
|
|
161
166
|
root,
|
|
162
167
|
toggle,
|
|
163
168
|
panel,
|
|
169
|
+
title,
|
|
164
170
|
styleButton,
|
|
165
171
|
assetSelect,
|
|
166
172
|
assetBrowser,
|
|
@@ -189,6 +195,7 @@ export function createDesignerElements(options, manifest, selectedAssetId) {
|
|
|
189
195
|
currentAudio,
|
|
190
196
|
currentAnimation,
|
|
191
197
|
currentAnimationButton,
|
|
198
|
+
currentRevertButton,
|
|
192
199
|
currentTouchUpButton,
|
|
193
200
|
currentPreview,
|
|
194
201
|
uploadButton,
|
|
@@ -214,7 +221,7 @@ export function renderAssetFolderBrowser(options) {
|
|
|
214
221
|
const storedPathValue = options.container.getAttribute("data-path");
|
|
215
222
|
const storedPath = storedPathValue !== null
|
|
216
223
|
? storedPathValue.split("/").filter(Boolean)
|
|
217
|
-
:
|
|
224
|
+
: [];
|
|
218
225
|
const currentPath = pathHasAnyAsset(storedPath, assetPathEntries)
|
|
219
226
|
? storedPath
|
|
220
227
|
: selectedPath;
|
|
@@ -390,7 +397,7 @@ export function renderOptions(options) {
|
|
|
390
397
|
element: animationStage,
|
|
391
398
|
src: option.dataUrl,
|
|
392
399
|
asset: optionAsset,
|
|
393
|
-
displaySize:
|
|
400
|
+
displaySize: { width: 68, height: 68 },
|
|
394
401
|
applyFrameTransforms: false
|
|
395
402
|
});
|
|
396
403
|
});
|
|
@@ -473,7 +480,6 @@ export async function uploadedOptionFromFile(options) {
|
|
|
473
480
|
model: "uploaded",
|
|
474
481
|
dimensions: geometry.dimensions,
|
|
475
482
|
frameGrid: geometry.frameGrid,
|
|
476
|
-
animations: options.asset.animations,
|
|
477
483
|
settings: {
|
|
478
484
|
...options.asset.settings,
|
|
479
485
|
format: normalizeAssetFormatFromMimeType(mimeType, options.file.name)
|
|
@@ -575,6 +581,13 @@ export async function spriteSheetFrameToDataUrl(options) {
|
|
|
575
581
|
export function isSvgSource(src) {
|
|
576
582
|
return src.startsWith("data:image/svg+xml") || /\.svg(?:$|\?)/i.test(src);
|
|
577
583
|
}
|
|
584
|
+
const frameTouchUpPreferences = {
|
|
585
|
+
alpha: 255,
|
|
586
|
+
antiAlias: true,
|
|
587
|
+
brushSize: 4,
|
|
588
|
+
color: "#f8fafc",
|
|
589
|
+
tool: "brush"
|
|
590
|
+
};
|
|
578
591
|
export async function openFrameTouchUpEditor(options) {
|
|
579
592
|
const sourceImage = await loadImageElement(options.frameSrc);
|
|
580
593
|
const dialog = document.createElement("div");
|
|
@@ -616,7 +629,7 @@ export async function openFrameTouchUpEditor(options) {
|
|
|
616
629
|
brushSizeInput.min = "1";
|
|
617
630
|
brushSizeInput.max = "32";
|
|
618
631
|
brushSizeInput.step = "1";
|
|
619
|
-
brushSizeInput.value =
|
|
632
|
+
brushSizeInput.value = String(frameTouchUpPreferences.brushSize);
|
|
620
633
|
const brushSizeValue = document.createElement("span");
|
|
621
634
|
brushSizeValue.textContent = brushSizeInput.value;
|
|
622
635
|
const brushSizeField = document.createElement("label");
|
|
@@ -624,7 +637,7 @@ export async function openFrameTouchUpEditor(options) {
|
|
|
624
637
|
brushSizeField.append("Size", brushSizeInput, brushSizeValue);
|
|
625
638
|
const antiAliasInput = document.createElement("input");
|
|
626
639
|
antiAliasInput.type = "checkbox";
|
|
627
|
-
antiAliasInput.checked =
|
|
640
|
+
antiAliasInput.checked = frameTouchUpPreferences.antiAlias;
|
|
628
641
|
const antiAliasField = document.createElement("label");
|
|
629
642
|
antiAliasField.className = "ai-game-assets-designer__inline-checkbox";
|
|
630
643
|
antiAliasField.append(antiAliasInput, "Anti-aliased round tip");
|
|
@@ -640,14 +653,14 @@ export async function openFrameTouchUpEditor(options) {
|
|
|
640
653
|
saveButton.classList.add("is-primary");
|
|
641
654
|
const colorInput = document.createElement("input");
|
|
642
655
|
colorInput.type = "color";
|
|
643
|
-
colorInput.value =
|
|
656
|
+
colorInput.value = frameTouchUpPreferences.color;
|
|
644
657
|
colorInput.setAttribute("aria-label", "Brush color");
|
|
645
658
|
const alphaInput = document.createElement("input");
|
|
646
659
|
alphaInput.type = "number";
|
|
647
660
|
alphaInput.min = "0";
|
|
648
661
|
alphaInput.max = "255";
|
|
649
662
|
alphaInput.step = "1";
|
|
650
|
-
alphaInput.value =
|
|
663
|
+
alphaInput.value = String(frameTouchUpPreferences.alpha);
|
|
651
664
|
alphaInput.setAttribute("aria-label", "Alpha");
|
|
652
665
|
const rgbaLabel = document.createElement("label");
|
|
653
666
|
rgbaLabel.className = "ai-game-assets-designer__touchup-color";
|
|
@@ -699,9 +712,10 @@ export async function openFrameTouchUpEditor(options) {
|
|
|
699
712
|
context.clearRect(0, 0, canvas.width, canvas.height);
|
|
700
713
|
context.drawImage(sourceImage, 0, 0, canvas.width, canvas.height);
|
|
701
714
|
let zoom = Math.max(1, Math.floor(Math.min(8, 480 / Math.max(canvas.width, canvas.height))));
|
|
702
|
-
let tool =
|
|
715
|
+
let tool = frameTouchUpPreferences.tool;
|
|
703
716
|
let dirty = false;
|
|
704
717
|
let drawing = false;
|
|
718
|
+
let drawingPointerId;
|
|
705
719
|
let selectionStart;
|
|
706
720
|
let selection;
|
|
707
721
|
let animationTimeout;
|
|
@@ -751,6 +765,11 @@ export async function openFrameTouchUpEditor(options) {
|
|
|
751
765
|
}[tool];
|
|
752
766
|
activeButton.classList.add("is-active");
|
|
753
767
|
};
|
|
768
|
+
const selectTool = (nextTool) => {
|
|
769
|
+
tool = nextTool;
|
|
770
|
+
frameTouchUpPreferences.tool = nextTool;
|
|
771
|
+
updateToolButtons();
|
|
772
|
+
};
|
|
754
773
|
const updateUndoRedo = () => {
|
|
755
774
|
undoButton.disabled = undoStack.length === 0;
|
|
756
775
|
redoButton.disabled = redoStack.length === 0;
|
|
@@ -769,6 +788,22 @@ export async function openFrameTouchUpEditor(options) {
|
|
|
769
788
|
redrawEditor();
|
|
770
789
|
setDirty(true);
|
|
771
790
|
};
|
|
791
|
+
const undo = () => {
|
|
792
|
+
const previous = undoStack.pop();
|
|
793
|
+
if (!previous)
|
|
794
|
+
return;
|
|
795
|
+
redoStack.push(snapshot());
|
|
796
|
+
restore(previous);
|
|
797
|
+
updateUndoRedo();
|
|
798
|
+
};
|
|
799
|
+
const redo = () => {
|
|
800
|
+
const next = redoStack.pop();
|
|
801
|
+
if (!next)
|
|
802
|
+
return;
|
|
803
|
+
undoStack.push(snapshot());
|
|
804
|
+
restore(next);
|
|
805
|
+
updateUndoRedo();
|
|
806
|
+
};
|
|
772
807
|
const syncSelectionBox = () => {
|
|
773
808
|
if (!selection) {
|
|
774
809
|
selectionBox.hidden = true;
|
|
@@ -913,6 +948,8 @@ export async function openFrameTouchUpEditor(options) {
|
|
|
913
948
|
const data = context.getImageData(point.x, point.y, 1, 1).data;
|
|
914
949
|
colorInput.value = `#${hexByte(data[0])}${hexByte(data[1])}${hexByte(data[2])}`;
|
|
915
950
|
alphaInput.value = String(data[3]);
|
|
951
|
+
frameTouchUpPreferences.color = colorInput.value;
|
|
952
|
+
frameTouchUpPreferences.alpha = data[3];
|
|
916
953
|
};
|
|
917
954
|
const fillAt = (point) => {
|
|
918
955
|
const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
|
|
@@ -1020,7 +1057,10 @@ export async function openFrameTouchUpEditor(options) {
|
|
|
1020
1057
|
disposed = true;
|
|
1021
1058
|
if (animationTimeout !== undefined)
|
|
1022
1059
|
window.clearTimeout(animationTimeout);
|
|
1023
|
-
window.removeEventListener("keydown", keyHandler);
|
|
1060
|
+
window.removeEventListener("keydown", keyHandler, true);
|
|
1061
|
+
window.removeEventListener("pointerup", finishPointer, true);
|
|
1062
|
+
window.removeEventListener("pointercancel", finishPointer, true);
|
|
1063
|
+
window.removeEventListener("blur", cancelDrawing);
|
|
1024
1064
|
document.removeEventListener("pointerdown", closeBrushMenuOnOutsidePointer);
|
|
1025
1065
|
dialog.remove();
|
|
1026
1066
|
};
|
|
@@ -1032,33 +1072,55 @@ export async function openFrameTouchUpEditor(options) {
|
|
|
1032
1072
|
const keyHandler = (event) => {
|
|
1033
1073
|
if (!dialog.isConnected)
|
|
1034
1074
|
return;
|
|
1075
|
+
const key = event.key.toLowerCase();
|
|
1076
|
+
const commandModifier = event.metaKey || event.ctrlKey;
|
|
1077
|
+
if (commandModifier && !event.altKey && (key === "z" || key === "y")) {
|
|
1078
|
+
event.preventDefault();
|
|
1079
|
+
event.stopPropagation();
|
|
1080
|
+
if (key === "y" || event.shiftKey) {
|
|
1081
|
+
redo();
|
|
1082
|
+
}
|
|
1083
|
+
else {
|
|
1084
|
+
undo();
|
|
1085
|
+
}
|
|
1086
|
+
return;
|
|
1087
|
+
}
|
|
1035
1088
|
if (event.key === "Escape") {
|
|
1089
|
+
event.preventDefault();
|
|
1090
|
+
event.stopPropagation();
|
|
1036
1091
|
requestClose();
|
|
1037
1092
|
return;
|
|
1038
1093
|
}
|
|
1039
1094
|
if (event.key === "Backspace" || event.key === "Delete") {
|
|
1040
1095
|
event.preventDefault();
|
|
1096
|
+
event.stopPropagation();
|
|
1041
1097
|
deleteSelection();
|
|
1042
1098
|
return;
|
|
1043
1099
|
}
|
|
1044
1100
|
if (event.key === "ArrowLeft") {
|
|
1045
1101
|
event.preventDefault();
|
|
1102
|
+
event.stopPropagation();
|
|
1046
1103
|
moveSelection(-1, 0);
|
|
1047
1104
|
}
|
|
1048
1105
|
else if (event.key === "ArrowRight") {
|
|
1049
1106
|
event.preventDefault();
|
|
1107
|
+
event.stopPropagation();
|
|
1050
1108
|
moveSelection(1, 0);
|
|
1051
1109
|
}
|
|
1052
1110
|
else if (event.key === "ArrowUp") {
|
|
1053
1111
|
event.preventDefault();
|
|
1112
|
+
event.stopPropagation();
|
|
1054
1113
|
moveSelection(0, -1);
|
|
1055
1114
|
}
|
|
1056
1115
|
else if (event.key === "ArrowDown") {
|
|
1057
1116
|
event.preventDefault();
|
|
1117
|
+
event.stopPropagation();
|
|
1058
1118
|
moveSelection(0, 1);
|
|
1059
1119
|
}
|
|
1060
1120
|
};
|
|
1061
1121
|
canvas.addEventListener("pointerdown", (event) => {
|
|
1122
|
+
if (event.pointerType !== "touch" && event.button !== 0)
|
|
1123
|
+
return;
|
|
1062
1124
|
if (event.pointerType === "touch") {
|
|
1063
1125
|
activeTouchPointers.set(event.pointerId, {
|
|
1064
1126
|
x: event.clientX,
|
|
@@ -1066,6 +1128,7 @@ export async function openFrameTouchUpEditor(options) {
|
|
|
1066
1128
|
});
|
|
1067
1129
|
if (activeTouchPointers.size >= 2) {
|
|
1068
1130
|
drawing = false;
|
|
1131
|
+
drawingPointerId = undefined;
|
|
1069
1132
|
selectionStart = undefined;
|
|
1070
1133
|
pinchStartDistance = touchPointerDistance();
|
|
1071
1134
|
pinchStartZoom = zoom;
|
|
@@ -1080,6 +1143,7 @@ export async function openFrameTouchUpEditor(options) {
|
|
|
1080
1143
|
}
|
|
1081
1144
|
pushUndo();
|
|
1082
1145
|
drawing = true;
|
|
1146
|
+
drawingPointerId = event.pointerId;
|
|
1083
1147
|
canvas.setPointerCapture(event.pointerId);
|
|
1084
1148
|
if (tool === "select") {
|
|
1085
1149
|
selectionStart = point;
|
|
@@ -1090,6 +1154,7 @@ export async function openFrameTouchUpEditor(options) {
|
|
|
1090
1154
|
if (tool === "fill") {
|
|
1091
1155
|
fillAt(point);
|
|
1092
1156
|
drawing = false;
|
|
1157
|
+
drawingPointerId = undefined;
|
|
1093
1158
|
setDirty(true);
|
|
1094
1159
|
redrawEditor();
|
|
1095
1160
|
return;
|
|
@@ -1112,8 +1177,12 @@ export async function openFrameTouchUpEditor(options) {
|
|
|
1112
1177
|
return;
|
|
1113
1178
|
}
|
|
1114
1179
|
}
|
|
1115
|
-
if (!drawing)
|
|
1180
|
+
if (!drawing || drawingPointerId !== event.pointerId)
|
|
1181
|
+
return;
|
|
1182
|
+
if (event.pointerType !== "touch" && (event.buttons & 1) === 0) {
|
|
1183
|
+
finishPointer(event);
|
|
1116
1184
|
return;
|
|
1185
|
+
}
|
|
1117
1186
|
const point = canvasPoint(event);
|
|
1118
1187
|
if (tool === "select" && selectionStart) {
|
|
1119
1188
|
const x = Math.min(selectionStart.x, point.x);
|
|
@@ -1133,7 +1202,7 @@ export async function openFrameTouchUpEditor(options) {
|
|
|
1133
1202
|
redrawEditor();
|
|
1134
1203
|
}
|
|
1135
1204
|
});
|
|
1136
|
-
|
|
1205
|
+
function finishPointer(event) {
|
|
1137
1206
|
if (event.pointerType === "touch") {
|
|
1138
1207
|
activeTouchPointers.delete(event.pointerId);
|
|
1139
1208
|
if (activeTouchPointers.size < 2) {
|
|
@@ -1144,15 +1213,29 @@ export async function openFrameTouchUpEditor(options) {
|
|
|
1144
1213
|
pinchStartZoom = zoom;
|
|
1145
1214
|
}
|
|
1146
1215
|
}
|
|
1147
|
-
|
|
1148
|
-
|
|
1216
|
+
if (drawingPointerId === event.pointerId) {
|
|
1217
|
+
drawing = false;
|
|
1218
|
+
drawingPointerId = undefined;
|
|
1219
|
+
selectionStart = undefined;
|
|
1220
|
+
}
|
|
1149
1221
|
if (canvas.hasPointerCapture(event.pointerId)) {
|
|
1150
1222
|
canvas.releasePointerCapture(event.pointerId);
|
|
1151
1223
|
}
|
|
1152
1224
|
redrawEditor();
|
|
1153
|
-
}
|
|
1225
|
+
}
|
|
1226
|
+
function cancelDrawing() {
|
|
1227
|
+
drawing = false;
|
|
1228
|
+
drawingPointerId = undefined;
|
|
1229
|
+
selectionStart = undefined;
|
|
1230
|
+
activeTouchPointers.clear();
|
|
1231
|
+
pinchStartDistance = undefined;
|
|
1232
|
+
}
|
|
1154
1233
|
canvas.addEventListener("pointerup", finishPointer);
|
|
1155
1234
|
canvas.addEventListener("pointercancel", finishPointer);
|
|
1235
|
+
canvas.addEventListener("lostpointercapture", finishPointer);
|
|
1236
|
+
window.addEventListener("pointerup", finishPointer, true);
|
|
1237
|
+
window.addEventListener("pointercancel", finishPointer, true);
|
|
1238
|
+
window.addEventListener("blur", cancelDrawing);
|
|
1156
1239
|
canvasWrap.addEventListener("wheel", (event) => {
|
|
1157
1240
|
if (!event.ctrlKey && !event.metaKey)
|
|
1158
1241
|
return;
|
|
@@ -1171,54 +1254,45 @@ export async function openFrameTouchUpEditor(options) {
|
|
|
1171
1254
|
setZoom(zoom + 1);
|
|
1172
1255
|
});
|
|
1173
1256
|
brushButton.addEventListener("click", () => {
|
|
1174
|
-
|
|
1175
|
-
updateToolButtons();
|
|
1257
|
+
selectTool("brush");
|
|
1176
1258
|
});
|
|
1177
1259
|
brushMenuButton.addEventListener("click", () => {
|
|
1178
1260
|
brushMenu.hidden = !brushMenu.hidden;
|
|
1179
1261
|
});
|
|
1180
1262
|
brushSizeInput.addEventListener("input", () => {
|
|
1181
1263
|
brushSizeValue.textContent = brushSizeInput.value;
|
|
1264
|
+
frameTouchUpPreferences.brushSize = brushSize();
|
|
1265
|
+
});
|
|
1266
|
+
antiAliasInput.addEventListener("change", () => {
|
|
1267
|
+
frameTouchUpPreferences.antiAlias = antiAliasInput.checked;
|
|
1268
|
+
});
|
|
1269
|
+
colorInput.addEventListener("input", () => {
|
|
1270
|
+
frameTouchUpPreferences.color = colorInput.value;
|
|
1271
|
+
});
|
|
1272
|
+
alphaInput.addEventListener("input", () => {
|
|
1273
|
+
frameTouchUpPreferences.alpha = clamp(Math.round(Number(alphaInput.value)), 0, 255);
|
|
1182
1274
|
});
|
|
1183
1275
|
document.addEventListener("pointerdown", closeBrushMenuOnOutsidePointer);
|
|
1184
1276
|
eraserButton.addEventListener("click", () => {
|
|
1185
|
-
|
|
1186
|
-
updateToolButtons();
|
|
1277
|
+
selectTool("eraser");
|
|
1187
1278
|
});
|
|
1188
1279
|
pickerButton.addEventListener("click", () => {
|
|
1189
|
-
|
|
1190
|
-
updateToolButtons();
|
|
1280
|
+
selectTool("picker");
|
|
1191
1281
|
});
|
|
1192
1282
|
selectButton.addEventListener("click", () => {
|
|
1193
|
-
|
|
1194
|
-
updateToolButtons();
|
|
1283
|
+
selectTool("select");
|
|
1195
1284
|
});
|
|
1196
1285
|
fillButton.addEventListener("click", () => {
|
|
1197
|
-
|
|
1198
|
-
updateToolButtons();
|
|
1199
|
-
});
|
|
1200
|
-
undoButton.addEventListener("click", () => {
|
|
1201
|
-
const previous = undoStack.pop();
|
|
1202
|
-
if (!previous)
|
|
1203
|
-
return;
|
|
1204
|
-
redoStack.push(snapshot());
|
|
1205
|
-
restore(previous);
|
|
1206
|
-
updateUndoRedo();
|
|
1207
|
-
});
|
|
1208
|
-
redoButton.addEventListener("click", () => {
|
|
1209
|
-
const next = redoStack.pop();
|
|
1210
|
-
if (!next)
|
|
1211
|
-
return;
|
|
1212
|
-
undoStack.push(snapshot());
|
|
1213
|
-
restore(next);
|
|
1214
|
-
updateUndoRedo();
|
|
1286
|
+
selectTool("fill");
|
|
1215
1287
|
});
|
|
1288
|
+
undoButton.addEventListener("click", undo);
|
|
1289
|
+
redoButton.addEventListener("click", redo);
|
|
1216
1290
|
saveButton.addEventListener("click", async () => {
|
|
1217
1291
|
await options.onSave(canvas.toDataURL("image/png"));
|
|
1218
1292
|
setDirty(false);
|
|
1219
1293
|
close();
|
|
1220
1294
|
});
|
|
1221
|
-
window.addEventListener("keydown", keyHandler);
|
|
1295
|
+
window.addEventListener("keydown", keyHandler, true);
|
|
1222
1296
|
updateZoom();
|
|
1223
1297
|
updateToolButtons();
|
|
1224
1298
|
updateUndoRedo();
|
|
@@ -1359,6 +1433,14 @@ export function renderAudioPlayer(options) {
|
|
|
1359
1433
|
state.frame = window.requestAnimationFrame(tick);
|
|
1360
1434
|
}
|
|
1361
1435
|
};
|
|
1436
|
+
const handleEnded = () => {
|
|
1437
|
+
if (!options.playback?.loop || state.disposed) {
|
|
1438
|
+
sync();
|
|
1439
|
+
return;
|
|
1440
|
+
}
|
|
1441
|
+
audio.currentTime = state.trimStart;
|
|
1442
|
+
void audio.play().then(() => tick()).catch(() => sync());
|
|
1443
|
+
};
|
|
1362
1444
|
playButton.addEventListener("click", async () => {
|
|
1363
1445
|
if (audio.paused) {
|
|
1364
1446
|
pauseSiblingAudioPlayers(options.container);
|
|
@@ -1393,12 +1475,15 @@ export function renderAudioPlayer(options) {
|
|
|
1393
1475
|
state.trimStart = clamp(options.playback?.trimStartSeconds ?? 0, 0, state.duration);
|
|
1394
1476
|
state.trimEnd = clamp(options.playback?.trimEndSeconds ?? state.duration, state.trimStart, state.duration);
|
|
1395
1477
|
trimLabel.hidden = state.trimStart === 0 && state.trimEnd === state.duration;
|
|
1396
|
-
trimLabel.textContent = `Trim ${formatAudioTime(state.trimStart)} – ${formatAudioTime(state.trimEnd)}`;
|
|
1478
|
+
trimLabel.textContent = `Trim ${formatAudioTime(state.trimStart, true)} – ${formatAudioTime(state.trimEnd, true)}`;
|
|
1479
|
+
audio.loop = Boolean(options.playback?.loop) &&
|
|
1480
|
+
state.trimStart === 0 &&
|
|
1481
|
+
state.trimEnd >= state.duration - 0.05;
|
|
1397
1482
|
audio.currentTime = state.trimStart;
|
|
1398
1483
|
sync();
|
|
1399
1484
|
});
|
|
1400
1485
|
audio.addEventListener("timeupdate", sync);
|
|
1401
|
-
audio.addEventListener("ended",
|
|
1486
|
+
audio.addEventListener("ended", handleEnded);
|
|
1402
1487
|
draw();
|
|
1403
1488
|
void audioWaveformPeaks(options.src).then((peaks) => {
|
|
1404
1489
|
if (state.disposed)
|
|
@@ -1516,13 +1601,17 @@ export function progressForAudio(audio) {
|
|
|
1516
1601
|
export function clamp(value, min, max) {
|
|
1517
1602
|
return Math.min(max, Math.max(min, value));
|
|
1518
1603
|
}
|
|
1519
|
-
export function formatAudioTime(value) {
|
|
1604
|
+
export function formatAudioTime(value, fractional = false) {
|
|
1520
1605
|
if (!Number.isFinite(value) || value < 0) {
|
|
1521
1606
|
return "0:00";
|
|
1522
1607
|
}
|
|
1523
|
-
const
|
|
1524
|
-
const
|
|
1525
|
-
|
|
1608
|
+
const precision = fractional ? 2 : 0;
|
|
1609
|
+
const multiplier = 10 ** precision;
|
|
1610
|
+
const roundedValue = Math.round(value * multiplier) / multiplier;
|
|
1611
|
+
const minutes = Math.floor(roundedValue / 60);
|
|
1612
|
+
const seconds = roundedValue % 60;
|
|
1613
|
+
const formattedSeconds = seconds.toFixed(precision).padStart(fractional ? 5 : 2, "0");
|
|
1614
|
+
return `${minutes}:${formattedSeconds}`;
|
|
1526
1615
|
}
|
|
1527
1616
|
export function startSpritesheetPreview(options) {
|
|
1528
1617
|
const frameGrid = options.asset.frameGrid;
|
|
@@ -2365,11 +2454,33 @@ export function setFrameBackground(element, options) {
|
|
|
2365
2454
|
export function setFrameElementBackground(frameElement, options) {
|
|
2366
2455
|
const column = options.frame % options.frameGrid.columns;
|
|
2367
2456
|
const row = Math.floor(options.frame / options.frameGrid.columns);
|
|
2457
|
+
const margin = options.frameGrid.margin ?? 0;
|
|
2458
|
+
const spacing = options.frameGrid.spacing ?? 0;
|
|
2459
|
+
const frameWidth = options.frameGrid.frameWidth;
|
|
2460
|
+
const frameHeight = options.frameGrid.frameHeight;
|
|
2461
|
+
const scale = Math.min(options.displaySize.width / frameWidth, options.displaySize.height / frameHeight);
|
|
2462
|
+
const sheetWidth = (margin * 2) +
|
|
2463
|
+
(options.frameGrid.columns * frameWidth) +
|
|
2464
|
+
(Math.max(0, options.frameGrid.columns - 1) * spacing);
|
|
2465
|
+
const sheetHeight = (margin * 2) +
|
|
2466
|
+
(options.frameGrid.rows * frameHeight) +
|
|
2467
|
+
(Math.max(0, options.frameGrid.rows - 1) * spacing);
|
|
2468
|
+
const sourceX = margin + (column * (frameWidth + spacing));
|
|
2469
|
+
const sourceY = margin + (row * (frameHeight + spacing));
|
|
2470
|
+
const displayFrameWidth = frameWidth * scale;
|
|
2471
|
+
const displayFrameHeight = frameHeight * scale;
|
|
2472
|
+
const frameOffsetX = (options.displaySize.width - displayFrameWidth) / 2;
|
|
2473
|
+
const frameOffsetY = (options.displaySize.height - displayFrameHeight) / 2;
|
|
2474
|
+
frameElement.style.inset = "auto";
|
|
2475
|
+
frameElement.style.left = `${frameOffsetX}px`;
|
|
2476
|
+
frameElement.style.top = `${frameOffsetY}px`;
|
|
2477
|
+
frameElement.style.width = `${displayFrameWidth}px`;
|
|
2478
|
+
frameElement.style.height = `${displayFrameHeight}px`;
|
|
2368
2479
|
frameElement.style.backgroundImage = `url("${cssUrl(options.src)}")`;
|
|
2369
2480
|
frameElement.style.backgroundSize =
|
|
2370
|
-
`${
|
|
2481
|
+
`${sheetWidth * scale}px ${sheetHeight * scale}px`;
|
|
2371
2482
|
frameElement.style.backgroundPosition =
|
|
2372
|
-
`${-(
|
|
2483
|
+
`${-(sourceX * scale)}px ${-(sourceY * scale)}px`;
|
|
2373
2484
|
}
|
|
2374
2485
|
export function ensureFramePreviewElement(element) {
|
|
2375
2486
|
const existing = element.querySelector(":scope > .ai-game-assets-designer__frame-image");
|
|
@@ -2456,16 +2567,28 @@ export function isAudioAsset(asset) {
|
|
|
2456
2567
|
export function isVoiceAsset(asset) {
|
|
2457
2568
|
return asset?.kind === "voice" || asset?.kind === "voice-line";
|
|
2458
2569
|
}
|
|
2459
|
-
export function assetWithGeneratedGeometry(asset, option) {
|
|
2570
|
+
export function assetWithGeneratedGeometry(asset, option, options = {}) {
|
|
2460
2571
|
return {
|
|
2461
2572
|
...asset,
|
|
2462
2573
|
dimensions: option.dimensions ?? asset.dimensions,
|
|
2463
2574
|
frameGrid: option.frameGrid ?? asset.frameGrid,
|
|
2464
|
-
animations: option.animations ??
|
|
2575
|
+
animations: option.animations ??
|
|
2576
|
+
(options.inheritAnimations
|
|
2577
|
+
? asset.animations
|
|
2578
|
+
: candidateAnimationDefinitions(asset, option.frameGrid ?? asset.frameGrid)),
|
|
2465
2579
|
audioPlayback: option.audioPlayback ?? asset.audioPlayback,
|
|
2466
2580
|
voiceSettings: option.voiceSettings ?? asset.voiceSettings
|
|
2467
2581
|
};
|
|
2468
2582
|
}
|
|
2583
|
+
function candidateAnimationDefinitions(asset, frameGrid) {
|
|
2584
|
+
if (!frameGrid || !asset.animations?.length)
|
|
2585
|
+
return undefined;
|
|
2586
|
+
const frameCount = frameGrid.frameCount ?? frameGrid.columns * frameGrid.rows;
|
|
2587
|
+
const frames = Array.from({ length: frameCount }, (_, index) => index);
|
|
2588
|
+
// This is runtime-only playback structure, derived from the candidate's grid.
|
|
2589
|
+
// It deliberately does not copy prompt, timings, tags, or transforms.
|
|
2590
|
+
return asset.animations.map(({ key, frameRate, repeat }) => ({ key, frameRate, repeat, frames }));
|
|
2591
|
+
}
|
|
2469
2592
|
export function positiveIntegerInput(input, fallback) {
|
|
2470
2593
|
const value = Number(input.value);
|
|
2471
2594
|
if (!Number.isFinite(value))
|
|
@@ -3074,6 +3197,7 @@ export function ensureDesignerStyles() {
|
|
|
3074
3197
|
background: transparent;
|
|
3075
3198
|
display: grid;
|
|
3076
3199
|
place-items: center;
|
|
3200
|
+
overflow: hidden;
|
|
3077
3201
|
cursor: pointer;
|
|
3078
3202
|
color: #dbeafe;
|
|
3079
3203
|
font: inherit;
|
|
@@ -3094,12 +3218,18 @@ export function ensureDesignerStyles() {
|
|
|
3094
3218
|
object-fit: contain;
|
|
3095
3219
|
image-rendering: pixelated;
|
|
3096
3220
|
}
|
|
3221
|
+
.ai-game-assets-designer__option-animation {
|
|
3222
|
+
width: 68px;
|
|
3223
|
+
height: 68px;
|
|
3224
|
+
max-width: 100%;
|
|
3225
|
+
}
|
|
3097
3226
|
.ai-game-assets-designer__option .ai-game-assets-designer__animate-button {
|
|
3098
3227
|
width: 100%;
|
|
3099
3228
|
}
|
|
3100
3229
|
.ai-game-assets-designer__modal {
|
|
3101
3230
|
position: fixed;
|
|
3102
3231
|
inset: 0;
|
|
3232
|
+
z-index: 2147483647;
|
|
3103
3233
|
display: grid;
|
|
3104
3234
|
place-items: center;
|
|
3105
3235
|
padding: 18px;
|
|
@@ -3231,14 +3361,24 @@ export function ensureDesignerStyles() {
|
|
|
3231
3361
|
}
|
|
3232
3362
|
.ai-game-assets-designer__frame-thumb {
|
|
3233
3363
|
flex: 0 0 auto;
|
|
3234
|
-
border:
|
|
3364
|
+
border: 0;
|
|
3235
3365
|
border-radius: 6px;
|
|
3236
3366
|
background-color: #0f1218;
|
|
3237
3367
|
position: relative;
|
|
3238
3368
|
overflow: hidden;
|
|
3239
3369
|
cursor: pointer;
|
|
3240
3370
|
}
|
|
3241
|
-
.ai-game-assets-designer__frame-thumb
|
|
3371
|
+
.ai-game-assets-designer__frame-thumb::after {
|
|
3372
|
+
content: "";
|
|
3373
|
+
position: absolute;
|
|
3374
|
+
inset: 0;
|
|
3375
|
+
z-index: 2;
|
|
3376
|
+
border: 2px solid #384251;
|
|
3377
|
+
border-radius: inherit;
|
|
3378
|
+
pointer-events: none;
|
|
3379
|
+
box-sizing: border-box;
|
|
3380
|
+
}
|
|
3381
|
+
.ai-game-assets-designer__frame-thumb.is-selected::after {
|
|
3242
3382
|
border-color: #6ed3ff;
|
|
3243
3383
|
}
|
|
3244
3384
|
.ai-game-assets-designer__frame-fields {
|