@kubohiroya/turbowarp-teachable-machine 3.5.0 → 3.5.2
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 +17 -6
- package/dist/backend-wasm.js +1 -1
- package/dist/backend-webgpu.js +1 -1
- package/dist/composition.js +666 -8
- package/dist/posenet.js +15 -6
- package/dist/runtime.js +3 -3
- package/dist/tm.js +2723 -2028
- package/dist/types/extension.d.ts +7 -0
- package/dist/types/fixed-input-editors.d.ts +7 -0
- package/dist/types/fixed-input-schema.d.ts +142 -0
- package/docs/fixed-input-editors.ja.md +36 -0
- package/package.json +15 -6
- package/schemas/block-editor-fixed-inputs.schema.json +193 -0
package/dist/composition.js
CHANGED
|
@@ -47,6 +47,644 @@ function requireComputeMode(value) {
|
|
|
47
47
|
if (!mode) throw new TypeError(`TM: Unknown compute mode: ${String(value)}`);
|
|
48
48
|
return mode;
|
|
49
49
|
}
|
|
50
|
+
//#endregion
|
|
51
|
+
//#region node_modules/.pnpm/@kubohiroya+turbowarp-extension-data-editor@0.2.1_react@18.3.1/node_modules/@kubohiroya/turbowarp-extension-data-editor/dist/fixed-input-schema.js
|
|
52
|
+
var numberToken = /^-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?$/u;
|
|
53
|
+
var invalidNumber = Object.freeze({
|
|
54
|
+
kind: "invalid",
|
|
55
|
+
code: "fixed-number-input-invalid"
|
|
56
|
+
});
|
|
57
|
+
/**
|
|
58
|
+
* Parse a NEW numeric draft according to NP-finite-new-input-v1.
|
|
59
|
+
* Never apply this to opening/no-op raw values or use it as an owner validator.
|
|
60
|
+
* Keep the validated token so negative zero, precision and exponent spelling survive.
|
|
61
|
+
*/
|
|
62
|
+
function parseFixedNumberInput(input) {
|
|
63
|
+
if (typeof input === "number") {
|
|
64
|
+
if (!Number.isFinite(input)) return invalidNumber;
|
|
65
|
+
return Object.freeze({
|
|
66
|
+
kind: "valid",
|
|
67
|
+
token: Object.is(input, -0) ? "-0" : String(input),
|
|
68
|
+
value: input
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
if (typeof input !== "string") return invalidNumber;
|
|
72
|
+
const token = input.trim();
|
|
73
|
+
if (!numberToken.test(token)) return invalidNumber;
|
|
74
|
+
const value = Number(token);
|
|
75
|
+
return Number.isFinite(value) ? Object.freeze({
|
|
76
|
+
kind: "valid",
|
|
77
|
+
token,
|
|
78
|
+
value
|
|
79
|
+
}) : invalidNumber;
|
|
80
|
+
}
|
|
81
|
+
var block_editor_fixed_inputs_schema_default = {
|
|
82
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
83
|
+
$id: "https://kubohiroya.github.io/turbowarp-teachable-machine/schemas/block-editor-fixed-inputs.schema.json",
|
|
84
|
+
title: "turbowarp-teachable-machine fixed input registration schema",
|
|
85
|
+
$defs: {
|
|
86
|
+
"setRecognitionMode": {
|
|
87
|
+
"type": "object",
|
|
88
|
+
"properties": { "MODE": {
|
|
89
|
+
"type": "string",
|
|
90
|
+
"enum": [
|
|
91
|
+
"pose",
|
|
92
|
+
"image",
|
|
93
|
+
"audio"
|
|
94
|
+
]
|
|
95
|
+
} }
|
|
96
|
+
},
|
|
97
|
+
"setComputeMode": {
|
|
98
|
+
"type": "object",
|
|
99
|
+
"properties": { "MODE": {
|
|
100
|
+
"type": "string",
|
|
101
|
+
"enum": [
|
|
102
|
+
"auto",
|
|
103
|
+
"webgpu",
|
|
104
|
+
"webgl",
|
|
105
|
+
"wasm",
|
|
106
|
+
"cpu"
|
|
107
|
+
]
|
|
108
|
+
} }
|
|
109
|
+
},
|
|
110
|
+
"setPreviewOpacity": {
|
|
111
|
+
"type": "object",
|
|
112
|
+
"properties": { "OPACITY": {
|
|
113
|
+
"type": "number",
|
|
114
|
+
"$comment": "New finite numeric input uses NP-finite-new-input-v1. Existing raw is preserved on no-op; runtime clamp/floor is not applied to stored raw."
|
|
115
|
+
} }
|
|
116
|
+
},
|
|
117
|
+
"setPreviewPosition": {
|
|
118
|
+
"type": "object",
|
|
119
|
+
"properties": { "POSITION": {
|
|
120
|
+
"type": "string",
|
|
121
|
+
"enum": [
|
|
122
|
+
"top-left",
|
|
123
|
+
"top-right",
|
|
124
|
+
"bottom-left",
|
|
125
|
+
"bottom-right",
|
|
126
|
+
"center",
|
|
127
|
+
"full-stage"
|
|
128
|
+
]
|
|
129
|
+
} }
|
|
130
|
+
},
|
|
131
|
+
"setPreviewMirroring": {
|
|
132
|
+
"type": "object",
|
|
133
|
+
"properties": { "MIRRORING": {
|
|
134
|
+
"type": "string",
|
|
135
|
+
"enum": ["mirrored", "unmirrored"]
|
|
136
|
+
} }
|
|
137
|
+
},
|
|
138
|
+
"setPoseOverlayVisibility": {
|
|
139
|
+
"type": "object",
|
|
140
|
+
"properties": { "VISIBILITY": {
|
|
141
|
+
"type": "string",
|
|
142
|
+
"enum": ["on", "off"]
|
|
143
|
+
} }
|
|
144
|
+
},
|
|
145
|
+
"setPoseJointStyle": {
|
|
146
|
+
"type": "object",
|
|
147
|
+
"properties": {
|
|
148
|
+
"PART": {
|
|
149
|
+
"type": "string",
|
|
150
|
+
"enum": [
|
|
151
|
+
"nose",
|
|
152
|
+
"leftEye",
|
|
153
|
+
"rightEye",
|
|
154
|
+
"leftEar",
|
|
155
|
+
"rightEar",
|
|
156
|
+
"leftShoulder",
|
|
157
|
+
"rightShoulder",
|
|
158
|
+
"leftElbow",
|
|
159
|
+
"rightElbow",
|
|
160
|
+
"leftWrist",
|
|
161
|
+
"rightWrist",
|
|
162
|
+
"leftHip",
|
|
163
|
+
"rightHip",
|
|
164
|
+
"leftKnee",
|
|
165
|
+
"rightKnee",
|
|
166
|
+
"leftAnkle",
|
|
167
|
+
"rightAnkle"
|
|
168
|
+
]
|
|
169
|
+
},
|
|
170
|
+
"OPACITY": {
|
|
171
|
+
"type": "number",
|
|
172
|
+
"$comment": "New finite numeric input uses NP-finite-new-input-v1. Existing raw is preserved on no-op; runtime clamp/floor is not applied to stored raw."
|
|
173
|
+
},
|
|
174
|
+
"RADIUS": {
|
|
175
|
+
"type": "number",
|
|
176
|
+
"$comment": "New finite numeric input uses NP-finite-new-input-v1. Existing raw is preserved on no-op; runtime clamp/floor is not applied to stored raw."
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
"setPoseBoneStyle": {
|
|
181
|
+
"type": "object",
|
|
182
|
+
"properties": {
|
|
183
|
+
"OPACITY": {
|
|
184
|
+
"type": "number",
|
|
185
|
+
"$comment": "New finite numeric input uses NP-finite-new-input-v1. Existing raw is preserved on no-op; runtime clamp/floor is not applied to stored raw."
|
|
186
|
+
},
|
|
187
|
+
"WIDTH": {
|
|
188
|
+
"type": "number",
|
|
189
|
+
"$comment": "New finite numeric input uses NP-finite-new-input-v1. Existing raw is preserved on no-op; runtime clamp/floor is not applied to stored raw."
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
"setPoseOverlayMinimumConfidence": {
|
|
194
|
+
"type": "object",
|
|
195
|
+
"properties": { "CONFIDENCE": {
|
|
196
|
+
"type": "number",
|
|
197
|
+
"$comment": "New finite numeric input uses NP-finite-new-input-v1. Existing raw is preserved on no-op; runtime clamp/floor is not applied to stored raw."
|
|
198
|
+
} }
|
|
199
|
+
},
|
|
200
|
+
"setPoseConfidenceScaling": {
|
|
201
|
+
"type": "object",
|
|
202
|
+
"properties": {
|
|
203
|
+
"PROPERTY": {
|
|
204
|
+
"type": "string",
|
|
205
|
+
"enum": [
|
|
206
|
+
"joint-opacity",
|
|
207
|
+
"joint-radius",
|
|
208
|
+
"bone-opacity",
|
|
209
|
+
"bone-width"
|
|
210
|
+
]
|
|
211
|
+
},
|
|
212
|
+
"STATE": {
|
|
213
|
+
"type": "string",
|
|
214
|
+
"enum": ["on", "off"]
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
"setAccumulatedPoseParameters": {
|
|
219
|
+
"type": "object",
|
|
220
|
+
"properties": {
|
|
221
|
+
"ACCUMULATION": {
|
|
222
|
+
"type": "number",
|
|
223
|
+
"$comment": "New finite numeric input uses NP-finite-new-input-v1. Existing raw is preserved on no-op; runtime clamp/floor is not applied to stored raw."
|
|
224
|
+
},
|
|
225
|
+
"DECAY": {
|
|
226
|
+
"type": "number",
|
|
227
|
+
"$comment": "New finite numeric input uses NP-finite-new-input-v1. Existing raw is preserved on no-op; runtime clamp/floor is not applied to stored raw."
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
"setAccumulatedPoseThreshold": {
|
|
232
|
+
"type": "object",
|
|
233
|
+
"properties": { "THRESHOLD": {
|
|
234
|
+
"type": "number",
|
|
235
|
+
"$comment": "New finite numeric input uses NP-finite-new-input-v1. Existing raw is preserved on no-op; runtime clamp/floor is not applied to stored raw."
|
|
236
|
+
} }
|
|
237
|
+
},
|
|
238
|
+
"isPoseWithThreshold": {
|
|
239
|
+
"type": "object",
|
|
240
|
+
"properties": { "THRESHOLD": {
|
|
241
|
+
"type": "number",
|
|
242
|
+
"$comment": "New finite numeric input uses NP-finite-new-input-v1. Existing raw is preserved on no-op; runtime clamp/floor is not applied to stored raw."
|
|
243
|
+
} }
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
//#endregion
|
|
248
|
+
//#region src/fixed-input-schema.ts
|
|
249
|
+
/** Owner canonical fragments, distinct from older SOURCE/editor schemas. */
|
|
250
|
+
function fixedInputBundle(opcode, argument) {
|
|
251
|
+
const source = {
|
|
252
|
+
repository: "turbowarp-teachable-machine",
|
|
253
|
+
path: "schemas/block-editor-fixed-inputs.schema.json",
|
|
254
|
+
symbol: `#/$defs/${opcode}/properties/${argument}`
|
|
255
|
+
};
|
|
256
|
+
const fragment = block_editor_fixed_inputs_schema_default.$defs[opcode].properties[argument];
|
|
257
|
+
return {
|
|
258
|
+
identity: {
|
|
259
|
+
ownerId: "turbowarp-teachable-machine",
|
|
260
|
+
contractId: "fixed-inputs",
|
|
261
|
+
revision: "1",
|
|
262
|
+
variantId: `${opcode}.${argument}`
|
|
263
|
+
},
|
|
264
|
+
dialect: "2020-12",
|
|
265
|
+
root: {
|
|
266
|
+
retrievalUri: block_editor_fixed_inputs_schema_default.$id,
|
|
267
|
+
document: fragment,
|
|
268
|
+
artifact: {
|
|
269
|
+
role: "canonical-schema",
|
|
270
|
+
source
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
resources: [],
|
|
274
|
+
provenance: {
|
|
275
|
+
canonicalSources: [source, {
|
|
276
|
+
repository: "turbowarp-teachable-machine",
|
|
277
|
+
path: "src/extension.ts",
|
|
278
|
+
symbol: opcode
|
|
279
|
+
}],
|
|
280
|
+
generatedFiles: [],
|
|
281
|
+
referenceSchemas: [],
|
|
282
|
+
generationSources: []
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
block_editor_fixed_inputs_schema_default.$defs;
|
|
287
|
+
//#endregion
|
|
288
|
+
//#region src/fixed-input-editors.ts
|
|
289
|
+
var existingNumber = (value) => {
|
|
290
|
+
if (typeof value !== "number" && typeof value !== "string" || typeof value === "string" && value.trim() === "") throw new TypeError("Expected a numeric literal.");
|
|
291
|
+
const number = Number(value);
|
|
292
|
+
if (!Number.isFinite(number)) throw new TypeError("Expected a finite number.");
|
|
293
|
+
return number;
|
|
294
|
+
};
|
|
295
|
+
var newNumber = (value) => {
|
|
296
|
+
const parsed = parseFixedNumberInput(value);
|
|
297
|
+
if (parsed.kind !== "valid") throw new TypeError("Invalid new numeric input.");
|
|
298
|
+
return parsed.token;
|
|
299
|
+
};
|
|
300
|
+
var aliases = {
|
|
301
|
+
"setRecognitionMode.MODE": {
|
|
302
|
+
"pose": "pose",
|
|
303
|
+
"poses": "pose",
|
|
304
|
+
"body": "pose",
|
|
305
|
+
"image": "image",
|
|
306
|
+
"images": "image",
|
|
307
|
+
"object": "image",
|
|
308
|
+
"card": "image",
|
|
309
|
+
"marker": "image",
|
|
310
|
+
"audio": "audio",
|
|
311
|
+
"sound": "audio",
|
|
312
|
+
"voice": "audio",
|
|
313
|
+
"microphone": "audio",
|
|
314
|
+
"mic": "audio",
|
|
315
|
+
"ポーズ": "pose",
|
|
316
|
+
"姿勢": "pose",
|
|
317
|
+
"画像": "image",
|
|
318
|
+
"物体": "image",
|
|
319
|
+
"カード": "image",
|
|
320
|
+
"記号": "image",
|
|
321
|
+
"音声": "audio",
|
|
322
|
+
"音": "audio",
|
|
323
|
+
"声": "audio",
|
|
324
|
+
"マイク": "audio"
|
|
325
|
+
},
|
|
326
|
+
"setPreviewPosition.POSITION": {
|
|
327
|
+
"左上": "top-left",
|
|
328
|
+
"右上": "top-right",
|
|
329
|
+
"左下": "bottom-left",
|
|
330
|
+
"右下": "bottom-right",
|
|
331
|
+
"中央": "center",
|
|
332
|
+
"ステージ全体": "full-stage",
|
|
333
|
+
"top-left": "top-left",
|
|
334
|
+
"top-right": "top-right",
|
|
335
|
+
"bottom-left": "bottom-left",
|
|
336
|
+
"bottom-right": "bottom-right",
|
|
337
|
+
"center": "center",
|
|
338
|
+
"full-stage": "full-stage"
|
|
339
|
+
},
|
|
340
|
+
"setPreviewMirroring.MIRRORING": {
|
|
341
|
+
"mirrored": "mirrored",
|
|
342
|
+
"unmirrored": "unmirrored",
|
|
343
|
+
"mirror": "mirrored",
|
|
344
|
+
"normal": "unmirrored",
|
|
345
|
+
"左右反転": "mirrored",
|
|
346
|
+
"そのまま": "unmirrored"
|
|
347
|
+
},
|
|
348
|
+
"setPoseOverlayVisibility.VISIBILITY": {
|
|
349
|
+
"on": "on",
|
|
350
|
+
"off": "off",
|
|
351
|
+
"show": "on",
|
|
352
|
+
"hide": "off",
|
|
353
|
+
"true": "on",
|
|
354
|
+
"false": "off",
|
|
355
|
+
"表示": "on",
|
|
356
|
+
"非表示": "off"
|
|
357
|
+
},
|
|
358
|
+
"setPoseConfidenceScaling.STATE": {
|
|
359
|
+
"on": "on",
|
|
360
|
+
"off": "off",
|
|
361
|
+
"show": "on",
|
|
362
|
+
"hide": "off",
|
|
363
|
+
"true": "on",
|
|
364
|
+
"false": "off",
|
|
365
|
+
"表示": "on",
|
|
366
|
+
"非表示": "off"
|
|
367
|
+
},
|
|
368
|
+
"setComputeMode.MODE": {
|
|
369
|
+
"auto": "auto",
|
|
370
|
+
"automatic": "auto",
|
|
371
|
+
"default": "auto",
|
|
372
|
+
"fastest": "auto",
|
|
373
|
+
"自動": "auto",
|
|
374
|
+
"おまかせ": "auto",
|
|
375
|
+
"webgpu": "webgpu",
|
|
376
|
+
"gpu": "webgpu",
|
|
377
|
+
"webgl": "webgl",
|
|
378
|
+
"wasm": "wasm",
|
|
379
|
+
"webassembly": "wasm",
|
|
380
|
+
"simd": "wasm",
|
|
381
|
+
"cpu": "cpu",
|
|
382
|
+
"javascript": "cpu"
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
function binding(opcode, argument, values) {
|
|
386
|
+
return {
|
|
387
|
+
argument,
|
|
388
|
+
schemaBundle: fixedInputBundle(opcode, argument),
|
|
389
|
+
control: values ? {
|
|
390
|
+
kind: "enum",
|
|
391
|
+
choices: values.map((value) => ({ value }))
|
|
392
|
+
} : { kind: "number" },
|
|
393
|
+
read(value) {
|
|
394
|
+
if (!values) return existingNumber(value);
|
|
395
|
+
if (typeof value !== "string") throw new TypeError("Expected a string.");
|
|
396
|
+
return projectEnum(opcode, argument, value);
|
|
397
|
+
},
|
|
398
|
+
encode(value) {
|
|
399
|
+
if (!values) return newNumber(value);
|
|
400
|
+
if (typeof value !== "string" || !values.includes(value)) throw new TypeError("Invalid selection.");
|
|
401
|
+
return value;
|
|
402
|
+
},
|
|
403
|
+
validateCandidate(value) {
|
|
404
|
+
try {
|
|
405
|
+
if (!values) existingNumber(value);
|
|
406
|
+
else if (typeof value !== "string" || !values.includes(value)) throw new TypeError("Invalid selection.");
|
|
407
|
+
return [];
|
|
408
|
+
} catch {
|
|
409
|
+
return [{ message: "Invalid fixed input." }];
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
function projectEnum(opcode, argument, value) {
|
|
415
|
+
const key = `${opcode}.${argument}`;
|
|
416
|
+
const token = argument === "POSITION" ? value : value.trim().toLowerCase();
|
|
417
|
+
return aliases[key]?.[token] ?? value;
|
|
418
|
+
}
|
|
419
|
+
var fixedInputEditors = [
|
|
420
|
+
{
|
|
421
|
+
apiVersion: 1,
|
|
422
|
+
extensionId: "kubohiroyatm",
|
|
423
|
+
editorId: "fixed-setRecognitionMode",
|
|
424
|
+
opcodes: ["kubohiroyatm_setRecognitionMode"],
|
|
425
|
+
contractId: "turbowarp-teachable-machine/setRecognitionMode",
|
|
426
|
+
contractRevision: "1",
|
|
427
|
+
validationContext: () => ({
|
|
428
|
+
consumerId: "turbowarp-teachable-machine",
|
|
429
|
+
nowMs: 0,
|
|
430
|
+
settings: null
|
|
431
|
+
}),
|
|
432
|
+
bindings: [binding("setRecognitionMode", "MODE", [
|
|
433
|
+
"pose",
|
|
434
|
+
"image",
|
|
435
|
+
"audio"
|
|
436
|
+
])]
|
|
437
|
+
},
|
|
438
|
+
{
|
|
439
|
+
apiVersion: 1,
|
|
440
|
+
extensionId: "kubohiroyatm",
|
|
441
|
+
editorId: "fixed-setComputeMode",
|
|
442
|
+
opcodes: ["kubohiroyatm_setComputeMode"],
|
|
443
|
+
contractId: "turbowarp-teachable-machine/setComputeMode",
|
|
444
|
+
contractRevision: "1",
|
|
445
|
+
validationContext: () => ({
|
|
446
|
+
consumerId: "turbowarp-teachable-machine",
|
|
447
|
+
nowMs: 0,
|
|
448
|
+
settings: null
|
|
449
|
+
}),
|
|
450
|
+
bindings: [binding("setComputeMode", "MODE", [
|
|
451
|
+
"auto",
|
|
452
|
+
"webgpu",
|
|
453
|
+
"webgl",
|
|
454
|
+
"wasm",
|
|
455
|
+
"cpu"
|
|
456
|
+
])]
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
apiVersion: 1,
|
|
460
|
+
extensionId: "kubohiroyatm",
|
|
461
|
+
editorId: "fixed-setPreviewOpacity",
|
|
462
|
+
opcodes: ["kubohiroyatm_setPreviewOpacity"],
|
|
463
|
+
contractId: "turbowarp-teachable-machine/setPreviewOpacity",
|
|
464
|
+
contractRevision: "1",
|
|
465
|
+
validationContext: () => ({
|
|
466
|
+
consumerId: "turbowarp-teachable-machine",
|
|
467
|
+
nowMs: 0,
|
|
468
|
+
settings: null
|
|
469
|
+
}),
|
|
470
|
+
bindings: [binding("setPreviewOpacity", "OPACITY")]
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
apiVersion: 1,
|
|
474
|
+
extensionId: "kubohiroyatm",
|
|
475
|
+
editorId: "fixed-setPreviewPosition",
|
|
476
|
+
opcodes: ["kubohiroyatm_setPreviewPosition"],
|
|
477
|
+
contractId: "turbowarp-teachable-machine/setPreviewPosition",
|
|
478
|
+
contractRevision: "1",
|
|
479
|
+
validationContext: () => ({
|
|
480
|
+
consumerId: "turbowarp-teachable-machine",
|
|
481
|
+
nowMs: 0,
|
|
482
|
+
settings: null
|
|
483
|
+
}),
|
|
484
|
+
bindings: [binding("setPreviewPosition", "POSITION", [
|
|
485
|
+
"top-left",
|
|
486
|
+
"top-right",
|
|
487
|
+
"bottom-left",
|
|
488
|
+
"bottom-right",
|
|
489
|
+
"center",
|
|
490
|
+
"full-stage"
|
|
491
|
+
])]
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
apiVersion: 1,
|
|
495
|
+
extensionId: "kubohiroyatm",
|
|
496
|
+
editorId: "fixed-setPreviewMirroring",
|
|
497
|
+
opcodes: ["kubohiroyatm_setPreviewMirroring"],
|
|
498
|
+
contractId: "turbowarp-teachable-machine/setPreviewMirroring",
|
|
499
|
+
contractRevision: "1",
|
|
500
|
+
validationContext: () => ({
|
|
501
|
+
consumerId: "turbowarp-teachable-machine",
|
|
502
|
+
nowMs: 0,
|
|
503
|
+
settings: null
|
|
504
|
+
}),
|
|
505
|
+
bindings: [binding("setPreviewMirroring", "MIRRORING", ["mirrored", "unmirrored"])]
|
|
506
|
+
},
|
|
507
|
+
{
|
|
508
|
+
apiVersion: 1,
|
|
509
|
+
extensionId: "kubohiroyatm",
|
|
510
|
+
editorId: "fixed-setPoseOverlayVisibility",
|
|
511
|
+
opcodes: ["kubohiroyatm_setPoseOverlayVisibility"],
|
|
512
|
+
contractId: "turbowarp-teachable-machine/setPoseOverlayVisibility",
|
|
513
|
+
contractRevision: "1",
|
|
514
|
+
validationContext: () => ({
|
|
515
|
+
consumerId: "turbowarp-teachable-machine",
|
|
516
|
+
nowMs: 0,
|
|
517
|
+
settings: null
|
|
518
|
+
}),
|
|
519
|
+
bindings: [binding("setPoseOverlayVisibility", "VISIBILITY", ["on", "off"])]
|
|
520
|
+
},
|
|
521
|
+
{
|
|
522
|
+
apiVersion: 1,
|
|
523
|
+
extensionId: "kubohiroyatm",
|
|
524
|
+
editorId: "fixed-setPoseJointStyle",
|
|
525
|
+
opcodes: ["kubohiroyatm_setPoseJointStyle"],
|
|
526
|
+
contractId: "turbowarp-teachable-machine/setPoseJointStyle",
|
|
527
|
+
contractRevision: "1",
|
|
528
|
+
validationContext: () => ({
|
|
529
|
+
consumerId: "turbowarp-teachable-machine",
|
|
530
|
+
nowMs: 0,
|
|
531
|
+
settings: null
|
|
532
|
+
}),
|
|
533
|
+
bindings: [
|
|
534
|
+
binding("setPoseJointStyle", "PART", [
|
|
535
|
+
"nose",
|
|
536
|
+
"leftEye",
|
|
537
|
+
"rightEye",
|
|
538
|
+
"leftEar",
|
|
539
|
+
"rightEar",
|
|
540
|
+
"leftShoulder",
|
|
541
|
+
"rightShoulder",
|
|
542
|
+
"leftElbow",
|
|
543
|
+
"rightElbow",
|
|
544
|
+
"leftWrist",
|
|
545
|
+
"rightWrist",
|
|
546
|
+
"leftHip",
|
|
547
|
+
"rightHip",
|
|
548
|
+
"leftKnee",
|
|
549
|
+
"rightKnee",
|
|
550
|
+
"leftAnkle",
|
|
551
|
+
"rightAnkle"
|
|
552
|
+
]),
|
|
553
|
+
binding("setPoseJointStyle", "OPACITY"),
|
|
554
|
+
binding("setPoseJointStyle", "RADIUS")
|
|
555
|
+
]
|
|
556
|
+
},
|
|
557
|
+
{
|
|
558
|
+
apiVersion: 1,
|
|
559
|
+
extensionId: "kubohiroyatm",
|
|
560
|
+
editorId: "fixed-setPoseBoneStyle",
|
|
561
|
+
opcodes: ["kubohiroyatm_setPoseBoneStyle"],
|
|
562
|
+
contractId: "turbowarp-teachable-machine/setPoseBoneStyle",
|
|
563
|
+
contractRevision: "1",
|
|
564
|
+
validationContext: () => ({
|
|
565
|
+
consumerId: "turbowarp-teachable-machine",
|
|
566
|
+
nowMs: 0,
|
|
567
|
+
settings: null
|
|
568
|
+
}),
|
|
569
|
+
bindings: [binding("setPoseBoneStyle", "OPACITY"), binding("setPoseBoneStyle", "WIDTH")]
|
|
570
|
+
},
|
|
571
|
+
{
|
|
572
|
+
apiVersion: 1,
|
|
573
|
+
extensionId: "kubohiroyatm",
|
|
574
|
+
editorId: "fixed-setPoseOverlayMinimumConfidence",
|
|
575
|
+
opcodes: ["kubohiroyatm_setPoseOverlayMinimumConfidence"],
|
|
576
|
+
contractId: "turbowarp-teachable-machine/setPoseOverlayMinimumConfidence",
|
|
577
|
+
contractRevision: "1",
|
|
578
|
+
validationContext: () => ({
|
|
579
|
+
consumerId: "turbowarp-teachable-machine",
|
|
580
|
+
nowMs: 0,
|
|
581
|
+
settings: null
|
|
582
|
+
}),
|
|
583
|
+
bindings: [binding("setPoseOverlayMinimumConfidence", "CONFIDENCE")]
|
|
584
|
+
},
|
|
585
|
+
{
|
|
586
|
+
apiVersion: 1,
|
|
587
|
+
extensionId: "kubohiroyatm",
|
|
588
|
+
editorId: "fixed-setPoseConfidenceScaling",
|
|
589
|
+
opcodes: ["kubohiroyatm_setPoseConfidenceScaling"],
|
|
590
|
+
contractId: "turbowarp-teachable-machine/setPoseConfidenceScaling",
|
|
591
|
+
contractRevision: "1",
|
|
592
|
+
validationContext: () => ({
|
|
593
|
+
consumerId: "turbowarp-teachable-machine",
|
|
594
|
+
nowMs: 0,
|
|
595
|
+
settings: null
|
|
596
|
+
}),
|
|
597
|
+
bindings: [binding("setPoseConfidenceScaling", "PROPERTY", [
|
|
598
|
+
"joint-opacity",
|
|
599
|
+
"joint-radius",
|
|
600
|
+
"bone-opacity",
|
|
601
|
+
"bone-width"
|
|
602
|
+
]), binding("setPoseConfidenceScaling", "STATE", ["on", "off"])]
|
|
603
|
+
},
|
|
604
|
+
{
|
|
605
|
+
apiVersion: 1,
|
|
606
|
+
extensionId: "kubohiroyatm",
|
|
607
|
+
editorId: "fixed-setAccumulatedPoseParameters",
|
|
608
|
+
opcodes: ["kubohiroyatm_setAccumulatedPoseParameters"],
|
|
609
|
+
contractId: "turbowarp-teachable-machine/setAccumulatedPoseParameters",
|
|
610
|
+
contractRevision: "1",
|
|
611
|
+
validationContext: () => ({
|
|
612
|
+
consumerId: "turbowarp-teachable-machine",
|
|
613
|
+
nowMs: 0,
|
|
614
|
+
settings: null
|
|
615
|
+
}),
|
|
616
|
+
bindings: [binding("setAccumulatedPoseParameters", "ACCUMULATION"), binding("setAccumulatedPoseParameters", "DECAY")]
|
|
617
|
+
},
|
|
618
|
+
{
|
|
619
|
+
apiVersion: 1,
|
|
620
|
+
extensionId: "kubohiroyatm",
|
|
621
|
+
editorId: "fixed-setAccumulatedPoseThreshold",
|
|
622
|
+
opcodes: ["kubohiroyatm_setAccumulatedPoseThreshold"],
|
|
623
|
+
contractId: "turbowarp-teachable-machine/setAccumulatedPoseThreshold",
|
|
624
|
+
contractRevision: "1",
|
|
625
|
+
validationContext: () => ({
|
|
626
|
+
consumerId: "turbowarp-teachable-machine",
|
|
627
|
+
nowMs: 0,
|
|
628
|
+
settings: null
|
|
629
|
+
}),
|
|
630
|
+
bindings: [binding("setAccumulatedPoseThreshold", "THRESHOLD")]
|
|
631
|
+
},
|
|
632
|
+
{
|
|
633
|
+
apiVersion: 1,
|
|
634
|
+
extensionId: "kubohiroyatm",
|
|
635
|
+
editorId: "fixed-isPoseWithThreshold",
|
|
636
|
+
opcodes: ["kubohiroyatm_isPoseWithThreshold"],
|
|
637
|
+
contractId: "turbowarp-teachable-machine/isPoseWithThreshold",
|
|
638
|
+
contractRevision: "1",
|
|
639
|
+
validationContext: () => ({
|
|
640
|
+
consumerId: "turbowarp-teachable-machine",
|
|
641
|
+
nowMs: 0,
|
|
642
|
+
settings: null
|
|
643
|
+
}),
|
|
644
|
+
bindings: [binding("isPoseWithThreshold", "THRESHOLD")]
|
|
645
|
+
}
|
|
646
|
+
];
|
|
647
|
+
/** Register only currently declared opcodes; release obsolete feature-flag scopes. */
|
|
648
|
+
function fixedInputRegistration(scratch) {
|
|
649
|
+
const host = typeof scratch === "object" && scratch !== null ? scratch : {};
|
|
650
|
+
let active;
|
|
651
|
+
let activeOpcodes = "";
|
|
652
|
+
const removers = [];
|
|
653
|
+
let disposed = false;
|
|
654
|
+
const dispose = () => {
|
|
655
|
+
host.vm?.runtime?.off?.("RUNTIME_DISPOSED", shutdown);
|
|
656
|
+
for (const remove of removers.splice(0).reverse()) remove();
|
|
657
|
+
active = void 0;
|
|
658
|
+
activeOpcodes = "";
|
|
659
|
+
};
|
|
660
|
+
const shutdown = () => {
|
|
661
|
+
disposed = true;
|
|
662
|
+
dispose();
|
|
663
|
+
};
|
|
664
|
+
return {
|
|
665
|
+
ensure(opcodes) {
|
|
666
|
+
const api = host.gui?.blockEditors;
|
|
667
|
+
const signature = [...new Set(opcodes)].sort().join("\0");
|
|
668
|
+
if (disposed || api === active && signature === activeOpcodes) return;
|
|
669
|
+
dispose();
|
|
670
|
+
if (api?.apiVersion !== 1 || typeof api.registerFixedInputEditor !== "function") return;
|
|
671
|
+
try {
|
|
672
|
+
for (const definition of fixedInputEditors) if (definition.opcodes.every((opcode) => opcodes.includes(opcode))) {
|
|
673
|
+
const remove = api.registerFixedInputEditor.call(api, definition);
|
|
674
|
+
if (typeof remove !== "function") throw new TypeError("Invalid fixed registration cleanup.");
|
|
675
|
+
removers.push(remove);
|
|
676
|
+
}
|
|
677
|
+
active = api;
|
|
678
|
+
activeOpcodes = signature;
|
|
679
|
+
host.vm?.runtime?.on?.("RUNTIME_DISPOSED", shutdown);
|
|
680
|
+
} catch (error) {
|
|
681
|
+
dispose();
|
|
682
|
+
throw error;
|
|
683
|
+
}
|
|
684
|
+
},
|
|
685
|
+
dispose: shutdown
|
|
686
|
+
};
|
|
687
|
+
}
|
|
50
688
|
var block_definitions_default = {
|
|
51
689
|
extensionName: "Teachable Machine",
|
|
52
690
|
blocks: [
|
|
@@ -549,7 +1187,7 @@ function confidenceMultiplier(value) {
|
|
|
549
1187
|
}
|
|
550
1188
|
var package_default = {
|
|
551
1189
|
name: "@kubohiroya/turbowarp-teachable-machine",
|
|
552
|
-
version: "3.5.
|
|
1190
|
+
version: "3.5.2",
|
|
553
1191
|
description: "A TurboWarp extension for recognition using Teachable Machine pose, image, and audio models.",
|
|
554
1192
|
author: "Hiroya Kubo <hiroya@cuc.ac.jp>",
|
|
555
1193
|
license: "MPL-2.0",
|
|
@@ -581,7 +1219,9 @@ var package_default = {
|
|
|
581
1219
|
"dist/",
|
|
582
1220
|
"README.md",
|
|
583
1221
|
"LICENSE",
|
|
584
|
-
"THIRD_PARTY_NOTICES.md"
|
|
1222
|
+
"THIRD_PARTY_NOTICES.md",
|
|
1223
|
+
"schemas/",
|
|
1224
|
+
"docs/fixed-input-editors.ja.md"
|
|
585
1225
|
],
|
|
586
1226
|
unpkg: "./dist/tm.js",
|
|
587
1227
|
jsdelivr: "./dist/tm.js",
|
|
@@ -617,8 +1257,8 @@ var package_default = {
|
|
|
617
1257
|
"prepack": "npm run build && npm run release:consistency:check"
|
|
618
1258
|
},
|
|
619
1259
|
devDependencies: {
|
|
620
|
-
"@kubohiroya/turbowarp-camera-source": "0.
|
|
621
|
-
"@kubohiroya/vite-plugin-turbowarp-extension": "0.
|
|
1260
|
+
"@kubohiroya/turbowarp-camera-source": "0.17.1",
|
|
1261
|
+
"@kubohiroya/vite-plugin-turbowarp-extension": "0.6.1",
|
|
622
1262
|
"@teachablemachine/image": "0.8.5",
|
|
623
1263
|
"@teachablemachine/pose": "0.8.6",
|
|
624
1264
|
"@tensorflow-models/posenet": "2.2.2",
|
|
@@ -629,7 +1269,8 @@ var package_default = {
|
|
|
629
1269
|
"@types/node": "^22.20.1",
|
|
630
1270
|
"typescript": "^5.9.3",
|
|
631
1271
|
"vite": "^8.2.2",
|
|
632
|
-
"vitest": "^4.0.14"
|
|
1272
|
+
"vitest": "^4.0.14",
|
|
1273
|
+
"@kubohiroya/turbowarp-extension-data-editor": "0.2.1"
|
|
633
1274
|
},
|
|
634
1275
|
keywords: [
|
|
635
1276
|
"turbowarp",
|
|
@@ -640,7 +1281,13 @@ var package_default = {
|
|
|
640
1281
|
"audio",
|
|
641
1282
|
"camera",
|
|
642
1283
|
"teachable-machine"
|
|
643
|
-
]
|
|
1284
|
+
],
|
|
1285
|
+
gitHead: "97ef12018789316d6170a7aab29d7c5b0a4c90f4",
|
|
1286
|
+
"x-turbowarp-source": {
|
|
1287
|
+
"revision": "97ef12018789316d6170a7aab29d7c5b0a4c90f4",
|
|
1288
|
+
"revisionRole": "base-commit",
|
|
1289
|
+
"sourceState": "local-release-overlay"
|
|
1290
|
+
}
|
|
644
1291
|
};
|
|
645
1292
|
//#endregion
|
|
646
1293
|
//#region src/extension.ts
|
|
@@ -1017,7 +1664,10 @@ var TMExtension = class {
|
|
|
1017
1664
|
this.visibilityChangeListener = () => this.handleDocumentVisibilityChange();
|
|
1018
1665
|
if (this.featureFlags.temporalPoseScoring && typeof document !== "undefined") document.addEventListener("visibilitychange", this.visibilityChangeListener);
|
|
1019
1666
|
}
|
|
1667
|
+
fixedEditors = fixedInputRegistration(typeof Scratch === "undefined" ? void 0 : Scratch);
|
|
1020
1668
|
getInfo() {
|
|
1669
|
+
const visibleOpcodes = block_definitions_default.blocks.filter((block) => !block.featureFlag || this.featureFlags[block.featureFlag]).map((block) => `${EXTENSION_ID}_${block.opcode}`);
|
|
1670
|
+
this.fixedEditors.ensure(visibleOpcodes);
|
|
1021
1671
|
return {
|
|
1022
1672
|
id: EXTENSION_ID,
|
|
1023
1673
|
name: Scratch.translate(block_definitions_default.extensionName),
|
|
@@ -1977,6 +2627,12 @@ var TMExtension = class {
|
|
|
1977
2627
|
* that flag flips the returned keypoints, not the image, and the classifier head was trained on
|
|
1978
2628
|
* mirrored frames. Flipping the pixels is what keeps the model's input the same as before.
|
|
1979
2629
|
*
|
|
2630
|
+
* The WASM and CPU backends have no texture to upload to, so `fromPixels` reads the frame back
|
|
2631
|
+
* through Canvas2D there and this path loses its advantage -- but not its correctness. Driving
|
|
2632
|
+
* one deterministic frame through every backend returns the same probabilities to two decimals
|
|
2633
|
+
* (webgl / wasm / cpu: 0.08, 0.90, 0.02, 0.00) and `tf.memory().numTensors` stays flat over a
|
|
2634
|
+
* six-second run on each, so nothing here depends on which backend `compute-backend.ts` picked.
|
|
2635
|
+
*
|
|
1980
2636
|
* Returns null when there is no frame to take, and the canvas path answers instead.
|
|
1981
2637
|
*/
|
|
1982
2638
|
captureSquareFrame() {
|
|
@@ -2032,10 +2688,11 @@ var TMExtension = class {
|
|
|
2032
2688
|
square.tensor.dispose();
|
|
2033
2689
|
}
|
|
2034
2690
|
}
|
|
2035
|
-
const
|
|
2691
|
+
const video = this.webcam.webcam;
|
|
2692
|
+
const source = video ?? this.webcam.canvas;
|
|
2036
2693
|
return {
|
|
2037
2694
|
keypoints: [],
|
|
2038
|
-
prediction: await model.predict(source)
|
|
2695
|
+
prediction: await model.predict(source, Boolean(video))
|
|
2039
2696
|
};
|
|
2040
2697
|
}
|
|
2041
2698
|
currentPoseReporter() {
|
|
@@ -2082,6 +2739,7 @@ var TMExtension = class {
|
|
|
2082
2739
|
else if (typeof Scratch !== "undefined") Scratch.vm?.runtime?.emit(ACCUMULATED_POSE_CHANGED_EVENT, payload);
|
|
2083
2740
|
}
|
|
2084
2741
|
dispose() {
|
|
2742
|
+
this.fixedEditors.dispose();
|
|
2085
2743
|
this.stopCamera();
|
|
2086
2744
|
if (this.featureFlags.temporalPoseScoring && typeof document !== "undefined") document.removeEventListener("visibilitychange", this.visibilityChangeListener);
|
|
2087
2745
|
this.onAccumulatedPoseChanged = null;
|