@kubohiroya/turbowarp-teachable-machine 3.3.0 → 3.4.1
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 +24 -4
- package/dist/backend-wasm.js +1 -1
- package/dist/backend-webgpu.js +1 -1
- package/dist/composition.js +72 -4
- package/dist/posenet.js +2 -1
- package/dist/runtime.js +2 -2
- package/dist/tm.js +72 -4
- package/dist/types/extension.d.ts +27 -0
- package/package.json +2 -1
package/dist/tm.js
CHANGED
|
@@ -553,7 +553,7 @@
|
|
|
553
553
|
}
|
|
554
554
|
var package_default = {
|
|
555
555
|
name: "@kubohiroya/turbowarp-teachable-machine",
|
|
556
|
-
version: "3.
|
|
556
|
+
version: "3.4.1",
|
|
557
557
|
description: "A TurboWarp extension for recognition using Teachable Machine pose, image, and audio models.",
|
|
558
558
|
author: "Hiroya Kubo <hiroya@cuc.ac.jp>",
|
|
559
559
|
license: "MPL-2.0",
|
|
@@ -621,6 +621,7 @@
|
|
|
621
621
|
"prepack": "npm run build && npm run release:consistency:check"
|
|
622
622
|
},
|
|
623
623
|
devDependencies: {
|
|
624
|
+
"@kubohiroya/turbowarp-camera-source": "0.13.0",
|
|
624
625
|
"@kubohiroya/vite-plugin-turbowarp-extension": "0.4.0",
|
|
625
626
|
"@teachablemachine/image": "0.8.5",
|
|
626
627
|
"@teachablemachine/pose": "0.8.6",
|
|
@@ -647,6 +648,23 @@
|
|
|
647
648
|
};
|
|
648
649
|
//#endregion
|
|
649
650
|
//#region src/extension.ts
|
|
651
|
+
/**
|
|
652
|
+
* Where Camera Source puts itself on the VM runtime.
|
|
653
|
+
*
|
|
654
|
+
* Declared here rather than imported as a value, because this file is bundled into a single-file
|
|
655
|
+
* extension and no dependency's code has ever been inlined into it. The key and the member read
|
|
656
|
+
* below are pinned against Camera Source's own published constant and narrowing function in the
|
|
657
|
+
* tests, which import both and are not shipped, so a rename upstream fails here rather than
|
|
658
|
+
* silently reading an absent extension as "not loaded".
|
|
659
|
+
*/
|
|
660
|
+
var CAMERA_SOURCE_RUNTIME_KEY = "ext_kubohiroyacamerasource";
|
|
661
|
+
function readCameraSource(runtime) {
|
|
662
|
+
if (typeof runtime !== "object" || runtime === null) return void 0;
|
|
663
|
+
const candidate = runtime[CAMERA_SOURCE_RUNTIME_KEY];
|
|
664
|
+
if (typeof candidate !== "object" || candidate === null) return void 0;
|
|
665
|
+
const { acquireCamera } = candidate;
|
|
666
|
+
return typeof acquireCamera === "function" ? candidate : void 0;
|
|
667
|
+
}
|
|
650
668
|
var EXTENSION_ID = "kubohiroyatm";
|
|
651
669
|
var VERSION = `${package_default.version}-typescript`;
|
|
652
670
|
var DOCS_URI = "https://kubohiroya.github.io/turbowarp-teachable-machine/";
|
|
@@ -929,6 +947,7 @@
|
|
|
929
947
|
this.modelURL = "";
|
|
930
948
|
this.model = null;
|
|
931
949
|
this.webcam = null;
|
|
950
|
+
this.cameraLease = null;
|
|
932
951
|
this.cameraRunning = false;
|
|
933
952
|
this.cameraSelection = "default";
|
|
934
953
|
this.cameraSelectionIsDeviceId = false;
|
|
@@ -1150,8 +1169,11 @@
|
|
|
1150
1169
|
await this.ensureComputeBackend();
|
|
1151
1170
|
}
|
|
1152
1171
|
cleanupCameraResources() {
|
|
1172
|
+
const lease = this.cameraLease;
|
|
1173
|
+
this.cameraLease = null;
|
|
1153
1174
|
const video = this.webcam?.webcam;
|
|
1154
|
-
if (
|
|
1175
|
+
if (lease) lease.release();
|
|
1176
|
+
else if (video?.srcObject) {
|
|
1155
1177
|
video.srcObject.getTracks().forEach((track) => track.stop());
|
|
1156
1178
|
video.srcObject = null;
|
|
1157
1179
|
}
|
|
@@ -1184,11 +1206,17 @@
|
|
|
1184
1206
|
if (!runtime) throw new Error("Teachable Machine: Runtime is unavailable.");
|
|
1185
1207
|
if (!("Webcam" in runtime)) throw new Error("Teachable Machine: Camera runtime is unavailable in the current mode.");
|
|
1186
1208
|
this.webcam = new runtime.Webcam(320, 240, true);
|
|
1187
|
-
const
|
|
1209
|
+
const lease = await this.acquireSharedCamera();
|
|
1210
|
+
if (lease) {
|
|
1211
|
+
this.cameraLease = lease;
|
|
1212
|
+
this.webcam.webcam = lease.getFrameSource().element;
|
|
1213
|
+
}
|
|
1214
|
+
const constraints = lease ? void 0 : cameraConstraints(this.resolvedCameraSelection());
|
|
1188
1215
|
if (constraints) await this.webcam.setup(constraints);
|
|
1189
1216
|
else await this.webcam.setup();
|
|
1217
|
+
this.ensureCameraCanvas();
|
|
1190
1218
|
initializeCameraReadbackContext(this.webcam.canvas);
|
|
1191
|
-
await this.webcam.play();
|
|
1219
|
+
if (!lease) await this.webcam.play();
|
|
1192
1220
|
this.attachPreviewToStage();
|
|
1193
1221
|
this.cameraRunning = true;
|
|
1194
1222
|
try {
|
|
@@ -1203,6 +1231,46 @@
|
|
|
1203
1231
|
throw error;
|
|
1204
1232
|
}
|
|
1205
1233
|
}
|
|
1234
|
+
/**
|
|
1235
|
+
* Give the camera the readback canvas `setup()` did not build.
|
|
1236
|
+
*
|
|
1237
|
+
* Upstream creates that canvas inside the same branch that opens the camera, so an injected
|
|
1238
|
+
* element skips the canvas with the `getUserMedia` call. 3.4.0 shipped assuming the two were
|
|
1239
|
+
* separate, and every leased start then failed at the first context request with "Webcam canvas
|
|
1240
|
+
* does not provide a 2D context" -- which is to say pose recognition did not start at all
|
|
1241
|
+
* wherever Camera Source was present. The canvas built here is the one upstream would have
|
|
1242
|
+
* built, so the mirrored centre crop every downstream reader expects is unchanged.
|
|
1243
|
+
*/
|
|
1244
|
+
ensureCameraCanvas() {
|
|
1245
|
+
if (!this.webcam || this.webcam.canvas) return;
|
|
1246
|
+
const canvas = document.createElement("canvas");
|
|
1247
|
+
canvas.width = this.webcam.width ?? 320;
|
|
1248
|
+
canvas.height = this.webcam.height ?? 240;
|
|
1249
|
+
this.webcam.canvas = canvas;
|
|
1250
|
+
}
|
|
1251
|
+
/**
|
|
1252
|
+
* A lease on the shared camera, or null when Camera Source is not loaded.
|
|
1253
|
+
*
|
|
1254
|
+
* Camera Source owns the device and decides when a stream stops, which is what lets one camera
|
|
1255
|
+
* serve pose recognition and anything else reading frames at the same time. It is a separate
|
|
1256
|
+
* TurboWarp extension, and this one is also distributed for standalone URL loading, so its
|
|
1257
|
+
* absence is ordinary rather than a failure: the self-acquired path stays for it.
|
|
1258
|
+
*
|
|
1259
|
+
* One camera id for every visual recognition mode. Opening a second device for a work that
|
|
1260
|
+
* recognises both poses and images is not what sharing is for, and `pose` is the role name
|
|
1261
|
+
* Camera Source's own documentation uses for this consumer.
|
|
1262
|
+
*/
|
|
1263
|
+
async acquireSharedCamera() {
|
|
1264
|
+
const cameraSource = readCameraSource(Scratch.vm?.runtime);
|
|
1265
|
+
if (!cameraSource) return null;
|
|
1266
|
+
const selection = this.resolvedCameraSelection();
|
|
1267
|
+
const options = {
|
|
1268
|
+
owner: package_default.name,
|
|
1269
|
+
cameraId: "pose"
|
|
1270
|
+
};
|
|
1271
|
+
if (selection.kind === "device") options.deviceId = selection.value;
|
|
1272
|
+
return cameraSource.acquireCamera(options);
|
|
1273
|
+
}
|
|
1206
1274
|
stopCamera() {
|
|
1207
1275
|
try {
|
|
1208
1276
|
this.stopRecognition();
|
|
@@ -5,6 +5,9 @@ export declare const EXTENSION_ID = "kubohiroyatm";
|
|
|
5
5
|
export declare const VERSION: string;
|
|
6
6
|
export declare const DOCS_URI = "https://kubohiroya.github.io/turbowarp-teachable-machine/";
|
|
7
7
|
export declare const ACCUMULATED_POSE_CHANGED_EVENT = "TM_ACCUMULATED_POSE_CHANGED";
|
|
8
|
+
/** The readback canvas size every downstream frame reader is written against. */
|
|
9
|
+
export declare const CAMERA_FRAME_WIDTH = 320;
|
|
10
|
+
export declare const CAMERA_FRAME_HEIGHT = 240;
|
|
8
11
|
export declare const BLOCK_ICON_URI: string;
|
|
9
12
|
export type RecognitionMode = 'pose' | 'image' | 'audio';
|
|
10
13
|
export interface TeachableMachineRuntime {
|
|
@@ -152,6 +155,30 @@ export declare class TMExtension {
|
|
|
152
155
|
ensureLibrariesLoaded(): Promise<void>;
|
|
153
156
|
cleanupCameraResources(): void;
|
|
154
157
|
startCamera(): Promise<void>;
|
|
158
|
+
/**
|
|
159
|
+
* Give the camera the readback canvas `setup()` did not build.
|
|
160
|
+
*
|
|
161
|
+
* Upstream creates that canvas inside the same branch that opens the camera, so an injected
|
|
162
|
+
* element skips the canvas with the `getUserMedia` call. 3.4.0 shipped assuming the two were
|
|
163
|
+
* separate, and every leased start then failed at the first context request with "Webcam canvas
|
|
164
|
+
* does not provide a 2D context" -- which is to say pose recognition did not start at all
|
|
165
|
+
* wherever Camera Source was present. The canvas built here is the one upstream would have
|
|
166
|
+
* built, so the mirrored centre crop every downstream reader expects is unchanged.
|
|
167
|
+
*/
|
|
168
|
+
ensureCameraCanvas(): void;
|
|
169
|
+
/**
|
|
170
|
+
* A lease on the shared camera, or null when Camera Source is not loaded.
|
|
171
|
+
*
|
|
172
|
+
* Camera Source owns the device and decides when a stream stops, which is what lets one camera
|
|
173
|
+
* serve pose recognition and anything else reading frames at the same time. It is a separate
|
|
174
|
+
* TurboWarp extension, and this one is also distributed for standalone URL loading, so its
|
|
175
|
+
* absence is ordinary rather than a failure: the self-acquired path stays for it.
|
|
176
|
+
*
|
|
177
|
+
* One camera id for every visual recognition mode. Opening a second device for a work that
|
|
178
|
+
* recognises both poses and images is not what sharing is for, and `pose` is the role name
|
|
179
|
+
* Camera Source's own documentation uses for this consumer.
|
|
180
|
+
*/
|
|
181
|
+
private acquireSharedCamera;
|
|
155
182
|
stopCamera(): void;
|
|
156
183
|
isCameraRunning(): any;
|
|
157
184
|
getCameraMenuItems(): {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubohiroya/turbowarp-teachable-machine",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.1",
|
|
4
4
|
"description": "A TurboWarp extension for recognition using Teachable Machine pose, image, and audio models.",
|
|
5
5
|
"author": "Hiroya Kubo <hiroya@cuc.ac.jp>",
|
|
6
6
|
"license": "MPL-2.0",
|
|
@@ -72,6 +72,7 @@
|
|
|
72
72
|
"prepack": "npm run build && npm run release:consistency:check"
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|
|
75
|
+
"@kubohiroya/turbowarp-camera-source": "0.13.0",
|
|
75
76
|
"@kubohiroya/vite-plugin-turbowarp-extension": "0.4.0",
|
|
76
77
|
"@teachablemachine/image": "0.8.5",
|
|
77
78
|
"@teachablemachine/pose": "0.8.6",
|