Skip to content

Interactive ML (Teachable Machines) - #650

Merged
whuang37 merged 13 commits into
google:mainfrom
whuang37:teachable-machines
Oct 8, 2026
Merged

whuang37 merged 13 commits into
google:mainfrom
whuang37:teachable-machines

Conversation

@whuang37

@whuang37 whuang37 commented Sep 29, 2026 •

Copy link
Copy Markdown
Collaborator

Description

Port of teachable machines for hand pose and sound. Everything works off static poses for now so nothing dynamic.

Most the code is in the demo + tflite export. the future is probably fitting this in with the detectors in the SDK but since its an addon had to rewrite a tflite export/import for that.

import * as xb from 'xrblocks';
import {
  captureHand,
  HandTrainer,
  Predictor,
} from 'xrblocks/addons/interactive-ml/index.js';

const trainer = new HandTrainer();
// Read the SDK's existing hand tracking from your Script.update().
const frame = captureHand(user.hands, xb.Handedness.RIGHT, performance.now());
if (frame) trainer.addExample('open', [frame]);
// Repeat for other poses, such as 'closed', with several takes per class.
const model = await trainer.train();
const result = model.predictHand([freshFrame]);
// result: {label, score, scores}. label is null when the pose is unknown.
import {
  SoundTrainer,
  YamnetExtractor,
} from 'xrblocks/addons/interactive-ml/index.js';

const extractor = await YamnetExtractor.load(tf); // Supply TensorFlow.js.
const trainer = new SoundTrainer(extractor);
await trainer.addExample('clap', clapClip);
await trainer.addExample('background', backgroundClip);
const model = await trainer.train();
const result = await trainer.predict(model, freshClip);

Type of Change

  • Bug fix
  • New feature / enhancement
  • New demo or sample
  • Documentation update

Media / Screen Recordings & Screenshots (If Applicable)

  • Simulator Recording:
  • Device Recording:
teachable-machines.mp4

Checklist

  • [ x Tested in simulator & device: Verified functionality in desktop simulator and/or physical hardware (where applicable).
  • Large Assets ($\ge$ 1MB): Submitted separately to xrblocks/proprietary-assets via jsdelivr CDN.
  • SDK Dynamic Dependencies: All new SDK dependencies are dynamically loaded at runtime.
  • Security: Confirmed no hardcoded API keys or secrets are committed.

Comment thread package.json Outdated
try {
loading ??= (async () => {
const tf = await import(
'https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@4.22.0/+esm'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

put it to constants.ts for easier maintenance and updates?

Comment thread demos/interactive-ml/audio.worker.js Outdated
try {
accelerated = await tf.setBackend('webgl');
} catch {
/* Worker has no usable GPU context. */

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a console.error

Comment thread src/addons/interactive-ml/Yamnet.ts Outdated
!(samples instanceof Float32Array) ||
!Number.isFinite(sampleRate) ||
sampleRate < 8000 ||
sampleRate > 192000 ||

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: consider to centralize to constants.ts in this folder?

@whuang37
whuang37 merged commit ea6d5f3 into google:main Oct 8, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants