PageSourceSearch

https://app.posetracker.com/worker/poseWasmWorker.js

js posetracker.com collected 2026-09-30 23:56:14 UTC 4,087 bytes, 117 lines download raw bytes

1/**
2 * Pose estimation in a Web Worker — same logic as direct mode (WASM for MoveNet).
3 * Loads TFJS + WASM backend and pose-detection from CDN; can run in parallel with main thread.
4 */
5// Pinned to 4.22.0 (matches the bundled npm version) for stable CDN caching.
6const TFJS_VERSION = "4.22.0";
7const POSE_DETECTION_VERSION = "2.1.3";
8const WASM_CDN = `https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-wasm@${TFJS_VERSION}/dist/`;
9// Self-hosted MoveNet SinglePose Lightning — avoids the slow tfhub.dev download.
10const MOVENET_MODEL_URL =
11  "https://app.posetracker.com/scripts/tmp_model_to_remove.json";
12
13// Single importScripts call → libs fetched in parallel instead of sequentially.
14self.importScripts(
15  `https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-core@${TFJS_VERSION}`,
16  `https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-wasm@${TFJS_VERSION}`,
17  `https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-converter@${TFJS_VERSION}`,
18  `https://cdn.jsdelivr.net/npm/@tensorflow-models/pose-detection@${POSE_DETECTION_VERSION}`
19);
20
21let detector = null;
22
23self.onmessage = async function (e) {
24  const msg = e.data;
25
26  if (msg.action === "init") {
27    try {
28      const useBlaze = msg.blazepose === true;
29      const useTfjsBlaze =
30        useBlaze &&
31        (msg.blazeposeRuntime === "tfjs" ||
32          msg.blazeposeRuntime === "tensorflow" ||
33          msg.blazeposeRuntime === "tf");
34
35      if (useBlaze) {
36        if (!useTfjsBlaze) {
37          self.importScripts(
38            "https://cdn.jsdelivr.net/npm/@mediapipe/pose"
39          );
40        }
41        if (msg.isAndroid === true) {
42          tf.env().set("WEBGL_CPU_FORWARD", false);
43          tf.env().set("WEBGL_PACK", false);
44          tf.env().set("WEBGL_FORCE_F16_TEXTURES", false);
45          tf.env().set("WEBGL_RENDER_FLOAT32_ENABLED", false);
46          tf.env().set("WEBGL_FLUSH_THRESHOLD", 1.75);
47          tf.env().set("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION", 0);
48        }
49        await tf.setBackend("webgl");
50        await tf.ready();
51        if (tf.getBackend() !== "webgl") {
52          self.postMessage({ type: "no-webgl" });
53          return;
54        }
55        detector = await poseDetection.createDetector(
56          poseDetection.SupportedModels.BlazePose,
57          useTfjsBlaze
58            ? { runtime: "tfjs", modelType: "lite", enableSmoothing: false }
59            : {
60                runtime: "mediapipe",
61                solutionPath: "https://cdn.jsdelivr.net/npm/@mediapipe/pose",
62                enableSmoothing: false,
63              }
64        );
65      } else {
66        tf.wasm.setWasmPaths(WASM_CDN);
67        await tf.setBackend("wasm");
68        await tf.ready();
69        if (tf.getBackend() !== "wasm") {
70          self.postMessage({ type: "no-wasm" });
71          return;
72        }
73        detector = await poseDetection.createDetector(
74          poseDetection.SupportedModels.MoveNet,
75          {
76            modelType: poseDetection.movenet.modelType.SINGLEPOSE_LIGHTNING,
77            enableSmoothing: false,
78            modelUrl: MOVENET_MODEL_URL,
79          }
80        );
81      }
82      self.postMessage({ type: "init-done" });
83    } catch (err) {
84      self.postMessage({ type: "init-fail", error: String(err && err.message) });
85    }
86    return;
87  }
88
89  if (msg.action === "estimate") {
90    if (!detector) return;
91    const imageBitmap = msg.image;
92    try {
93      const poses = await detector.estimatePoses(imageBitmap);
94      const keypoints = (poses[0] && poses[0].keypoints) || [];
95      self.postMessage({
96        type: "pose",
97        keypoints: keypoints.map((kp) => ({
98          name: kp.name,
99          x: kp.x,
100          y: kp.y,
101          z: kp.z != null ? kp.z : 0,
102          score: kp.score != null ? kp.score : 0,
103        })),
104      });
105    } catch (err) {
106      self.postMessage({ type: "pose-error", error: String(err && err.message) });
107    } finally {
108      if (imageBitmap && imageBitmap.close) imageBitmap.close();
109    }
110    return;
111  }
112
113  if (msg.action === "dispose") {
114    if (detector && detector.dispose) detector.dispose();
115    detector = null;
116  }
117};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.