@srsergio/taptapp-ar 1.0.40 → 1.0.41

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.
@@ -65,16 +65,12 @@ export class Controller {
65
65
  dummyRun(input: any): void;
66
66
  getProjectionMatrix(): number[];
67
67
  getRotatedZ90Matrix(m: any): any[];
68
- getWorldMatrix(modelViewTransform: any, targetIndex: any): any[] | null;
68
+ getWorldMatrix(modelViewTransform: any, targetIndex: any): any[];
69
69
  _detectAndMatch(inputData: any, targetIndexes: any): Promise<{
70
70
  targetIndex: any;
71
71
  modelViewTransform: any;
72
72
  }>;
73
- _trackAndUpdate(inputData: any, lastModelViewTransform: any, targetIndex: any): Promise<{
74
- modelViewTransform: any;
75
- inliers: number;
76
- octaveIndex: number;
77
- } | null>;
73
+ _trackAndUpdate(inputData: any, lastModelViewTransform: any, targetIndex: any): Promise<any>;
78
74
  processVideo(input: any): void;
79
75
  stopProcessVideo(): void;
80
76
  detect(input: any): Promise<{
@@ -102,7 +98,6 @@ export class Controller {
102
98
  x: number;
103
99
  y: number;
104
100
  }[];
105
- octaveIndex: number;
106
101
  debugExtra: {};
107
102
  }>;
108
103
  trackUpdate(modelViewTransform: any, trackFeatures: any): Promise<any>;
@@ -129,7 +124,7 @@ export class Controller {
129
124
  _workerTrackUpdate(modelViewTransform: any, trackingFeatures: any): Promise<any>;
130
125
  workerTrackDone: ((data: any) => void) | undefined;
131
126
  _trackUpdateOnMainThread(modelViewTransform: any, trackingFeatures: any): Promise<never[][] | null>;
132
- _glModelViewMatrix(modelViewTransform: any, targetIndex: any): any[] | null;
127
+ _glModelViewMatrix(modelViewTransform: any, targetIndex: any): any[];
133
128
  _glProjectionMatrix({ projectionTransform, width, height, near, far }: {
134
129
  projectionTransform: any;
135
130
  width: any;
@@ -181,20 +181,14 @@ class Controller {
181
181
  return { targetIndex: matchedTargetIndex, modelViewTransform };
182
182
  }
183
183
  async _trackAndUpdate(inputData, lastModelViewTransform, targetIndex) {
184
- if (!lastModelViewTransform)
185
- return null;
186
- const result = this.tracker.track(inputData, lastModelViewTransform, targetIndex);
187
- if (result.worldCoords.length < 6)
184
+ const { worldCoords, screenCoords } = this.tracker.track(inputData, lastModelViewTransform, targetIndex);
185
+ if (worldCoords.length < 6)
188
186
  return null; // Umbral de puntos mínimos para mantener el seguimiento
189
187
  const modelViewTransform = await this._workerTrackUpdate(lastModelViewTransform, {
190
- worldCoords: result.worldCoords,
191
- screenCoords: result.screenCoords,
188
+ worldCoords,
189
+ screenCoords,
192
190
  });
193
- return {
194
- modelViewTransform,
195
- inliers: result.worldCoords.length,
196
- octaveIndex: result.octaveIndex
197
- };
191
+ return modelViewTransform;
198
192
  }
199
193
  processVideo(input) {
200
194
  if (this.processingVideo)
@@ -208,7 +202,6 @@ class Controller {
208
202
  currentModelViewTransform: null,
209
203
  trackCount: 0,
210
204
  trackMiss: 0,
211
- stabilityCount: 0, // Nuevo: Contador para Live Adaptation
212
205
  filter: new OneEuroFilter({ minCutOff: this.filterMinCF, beta: this.filterBeta }),
213
206
  });
214
207
  }
@@ -221,22 +214,18 @@ class Controller {
221
214
  return acc + (!!s.isTracking ? 1 : 0);
222
215
  }, 0);
223
216
  // detect and match only if less then maxTrack
224
- // BUG FIX: Only match if we are NOT in a "ghosting" period for a target
225
- // to prevent the "found but immediately lost" loop that keeps opacity at 1.
226
217
  if (nTracking < this.maxTrack) {
227
218
  const matchingIndexes = [];
228
219
  for (let i = 0; i < this.trackingStates.length; i++) {
229
220
  const trackingState = this.trackingStates[i];
230
221
  if (trackingState.isTracking === true)
231
222
  continue;
232
- if (trackingState.showing === true)
233
- continue; // Don't try to re-detect if we are still buffers-showing the last position
234
223
  if (this.interestedTargetIndex !== -1 && this.interestedTargetIndex !== i)
235
224
  continue;
236
225
  matchingIndexes.push(i);
237
226
  }
238
227
  const { targetIndex: matchedTargetIndex, modelViewTransform } = await this._detectAndMatch(inputData, matchingIndexes);
239
- if (matchedTargetIndex !== -1 && modelViewTransform) {
228
+ if (matchedTargetIndex !== -1) {
240
229
  this.trackingStates[matchedTargetIndex].isTracking = true;
241
230
  this.trackingStates[matchedTargetIndex].currentModelViewTransform = modelViewTransform;
242
231
  }
@@ -245,80 +234,57 @@ class Controller {
245
234
  for (let i = 0; i < this.trackingStates.length; i++) {
246
235
  const trackingState = this.trackingStates[i];
247
236
  if (trackingState.isTracking) {
248
- if (!trackingState.currentModelViewTransform) {
237
+ let modelViewTransform = await this._trackAndUpdate(inputData, trackingState.currentModelViewTransform, i);
238
+ if (modelViewTransform === null) {
249
239
  trackingState.isTracking = false;
250
- trackingState.stabilityCount = 0;
251
240
  }
252
241
  else {
253
- let result = await this._trackAndUpdate(inputData, trackingState.currentModelViewTransform, i);
254
- if (result === null) {
255
- trackingState.isTracking = false;
256
- trackingState.stabilityCount = 0;
257
- }
258
- else {
259
- trackingState.currentModelViewTransform = result.modelViewTransform;
260
- // --- LIVE MODEL ADAPTATION LOGIC ---
261
- // Si el tracking es muy sólido (muchos inliers) y estable, refinamos el modelo
262
- // Requisito: > 35 inliers (muy exigente) para evitar polución por ruido
263
- if (result.inliers > 35) {
264
- trackingState.stabilityCount++;
265
- if (trackingState.stabilityCount > 30) { // 30 frames (~1s) de estabilidad absoluta
266
- this.tracker.applyLiveFeedback(i, result.octaveIndex, 0.05); // Menor alpha (5%) para ser más conservador
267
- if (this.debugMode)
268
- console.log(`✨ Live Reification: Target ${i} (Octave ${result.octaveIndex}) updated.`);
269
- trackingState.stabilityCount = 0;
270
- }
271
- }
272
- else {
273
- trackingState.stabilityCount = Math.max(0, trackingState.stabilityCount - 1);
274
- }
275
- // -----------------------------------
276
- }
242
+ trackingState.currentModelViewTransform = modelViewTransform;
277
243
  }
278
- // if not showing, then show it once it reaches warmup number of frames
279
- if (!trackingState.showing) {
280
- if (trackingState.isTracking) {
281
- trackingState.trackMiss = 0;
282
- trackingState.trackCount += 1;
283
- if (trackingState.trackCount > this.warmupTolerance) {
284
- trackingState.showing = true;
285
- trackingState.trackingMatrix = null;
286
- trackingState.filter.reset();
287
- }
244
+ }
245
+ // if not showing, then show it once it reaches warmup number of frames
246
+ if (!trackingState.showing) {
247
+ if (trackingState.isTracking) {
248
+ trackingState.trackMiss = 0;
249
+ trackingState.trackCount += 1;
250
+ if (trackingState.trackCount > this.warmupTolerance) {
251
+ trackingState.showing = true;
252
+ trackingState.trackingMatrix = null;
253
+ trackingState.filter.reset();
288
254
  }
289
255
  }
290
- // if showing, then count miss, and hide it when reaches tolerance
291
- if (trackingState.showing) {
292
- if (!trackingState.isTracking) {
293
- trackingState.trackCount = 0;
294
- trackingState.trackMiss += 1;
295
- if (trackingState.trackMiss > this.missTolerance) {
296
- trackingState.showing = false;
297
- trackingState.trackingMatrix = null;
298
- this.onUpdate &&
299
- this.onUpdate({ type: "updateMatrix", targetIndex: i, worldMatrix: null });
300
- }
301
- }
302
- else {
303
- trackingState.trackMiss = 0;
256
+ }
257
+ // if showing, then count miss, and hide it when reaches tolerance
258
+ if (trackingState.showing) {
259
+ if (!trackingState.isTracking) {
260
+ trackingState.trackCount = 0;
261
+ trackingState.trackMiss += 1;
262
+ if (trackingState.trackMiss > this.missTolerance) {
263
+ trackingState.showing = false;
264
+ trackingState.trackingMatrix = null;
265
+ this.onUpdate &&
266
+ this.onUpdate({ type: "updateMatrix", targetIndex: i, worldMatrix: null });
304
267
  }
305
268
  }
306
- // if showing, then call onUpdate, with world matrix
307
- if (trackingState.showing && trackingState.currentModelViewTransform) {
308
- const worldMatrix = this._glModelViewMatrix(trackingState.currentModelViewTransform, i);
309
- trackingState.trackingMatrix = trackingState.filter.filter(Date.now(), worldMatrix);
310
- let clone = [];
311
- for (let j = 0; j < trackingState.trackingMatrix.length; j++) {
312
- clone[j] = trackingState.trackingMatrix[j];
313
- }
314
- const isInputRotated = input.width === this.inputHeight && input.height === this.inputWidth;
315
- if (isInputRotated) {
316
- clone = this.getRotatedZ90Matrix(clone);
317
- }
318
- this.onUpdate &&
319
- this.onUpdate({ type: "updateMatrix", targetIndex: i, worldMatrix: clone, modelViewTransform: trackingState.currentModelViewTransform });
269
+ else {
270
+ trackingState.trackMiss = 0;
320
271
  }
321
272
  }
273
+ // if showing, then call onUpdate, with world matrix
274
+ if (trackingState.showing) {
275
+ const worldMatrix = this._glModelViewMatrix(trackingState.currentModelViewTransform, i);
276
+ trackingState.trackingMatrix = trackingState.filter.filter(Date.now(), worldMatrix);
277
+ let clone = [];
278
+ for (let j = 0; j < trackingState.trackingMatrix.length; j++) {
279
+ clone[j] = trackingState.trackingMatrix[j];
280
+ }
281
+ const isInputRotated = input.width === this.inputHeight && input.height === this.inputWidth;
282
+ if (isInputRotated) {
283
+ clone = this.getRotatedZ90Matrix(clone);
284
+ }
285
+ this.onUpdate &&
286
+ this.onUpdate({ type: "updateMatrix", targetIndex: i, worldMatrix: clone, modelViewTransform: trackingState.currentModelViewTransform });
287
+ }
322
288
  }
323
289
  this.onUpdate && this.onUpdate({ type: "processDone" });
324
290
  // Use requestAnimationFrame if available, otherwise just wait briefly
@@ -446,8 +412,6 @@ class Controller {
446
412
  return finalModelViewTransform;
447
413
  }
448
414
  _glModelViewMatrix(modelViewTransform, targetIndex) {
449
- if (!modelViewTransform)
450
- return null;
451
415
  const height = this.markerDimensions[targetIndex][1];
452
416
  const openGLWorldMatrix = [
453
417
  modelViewTransform[0][0],
@@ -20,7 +20,6 @@ export class Tracker {
20
20
  x: number;
21
21
  y: number;
22
22
  }[];
23
- octaveIndex: number;
24
23
  debugExtra: {};
25
24
  };
26
25
  /**
@@ -34,11 +33,4 @@ export class Tracker {
34
33
  * Pure JS implementation of Bilinear Warping
35
34
  */
36
35
  _computeProjection(M: any, inputData: any, prebuilt: any): void;
37
- /**
38
- * Refines the target data (Living Mind Map) using actual camera feedback
39
- * @param {number} targetIndex
40
- * @param {number} octaveIndex
41
- * @param {number} alpha - Blending factor (e.g. 0.1 for 10% new data)
42
- */
43
- applyLiveFeedback(targetIndex: number, octaveIndex: number, alpha: number): void;
44
36
  }
@@ -46,8 +46,6 @@ class Tracker {
46
46
  }
47
47
  track(inputData, lastModelViewTransform, targetIndex) {
48
48
  let debugExtra = {};
49
- if (!lastModelViewTransform)
50
- return { worldCoords: [], screenCoords: [], octaveIndex: 0, debugExtra };
51
49
  // Select the best octave based on current estimated distance/scale
52
50
  // We want the octave where the marker size is closest to its projected size on screen
53
51
  const modelViewProjectionTransform = buildModelViewProjectionTransform(this.projectionTransform, lastModelViewTransform);
@@ -89,7 +87,16 @@ class Tracker {
89
87
  });
90
88
  }
91
89
  }
92
- return { worldCoords, screenCoords, octaveIndex, debugExtra };
90
+ if (this.debugMode) {
91
+ debugExtra = {
92
+ octaveIndex,
93
+ projectedImage: Array.from(projectedImage),
94
+ matchingPoints,
95
+ goodTrack,
96
+ trackedPoints: screenCoords,
97
+ };
98
+ }
99
+ return { worldCoords, screenCoords, debugExtra };
93
100
  }
94
101
  /**
95
102
  * Pure JS implementation of NCC matching
@@ -225,33 +232,5 @@ class Tracker {
225
232
  }
226
233
  }
227
234
  }
228
- /**
229
- * Refines the target data (Living Mind Map) using actual camera feedback
230
- * @param {number} targetIndex
231
- * @param {number} octaveIndex
232
- * @param {number} alpha - Blending factor (e.g. 0.1 for 10% new data)
233
- */
234
- applyLiveFeedback(targetIndex, octaveIndex, alpha) {
235
- if (targetIndex === undefined || octaveIndex === undefined)
236
- return;
237
- const targetPrebuilts = this.prebuiltData[targetIndex];
238
- if (!targetPrebuilts)
239
- return;
240
- const prebuilt = targetPrebuilts[octaveIndex];
241
- if (!prebuilt || !prebuilt.projectedImage || !prebuilt.data)
242
- return;
243
- const markerPixels = prebuilt.data;
244
- const projectedPixels = prebuilt.projectedImage;
245
- const count = markerPixels.length;
246
- // Blend the projected (camera-sourced) pixels into the marker reference data
247
- // This allows the NCC matching to adapt to real-world lighting and print quality
248
- for (let i = 0; i < count; i++) {
249
- const val = projectedPixels[i];
250
- if (isNaN(val))
251
- continue; // Don't pollute with NaN
252
- // Simple linear blend
253
- markerPixels[i] = (1 - alpha) * markerPixels[i] + alpha * val;
254
- }
255
- }
256
235
  }
257
236
  export { Tracker };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@srsergio/taptapp-ar",
3
- "version": "1.0.40",
3
+ "version": "1.0.41",
4
4
  "description": "AR Compiler for Node.js and Browser",
5
5
  "repository": {
6
6
  "type": "git",
@@ -226,22 +226,17 @@ class Controller {
226
226
  return { targetIndex: matchedTargetIndex, modelViewTransform };
227
227
  }
228
228
  async _trackAndUpdate(inputData, lastModelViewTransform, targetIndex) {
229
- if (!lastModelViewTransform) return null;
230
- const result = this.tracker.track(
229
+ const { worldCoords, screenCoords } = this.tracker.track(
231
230
  inputData,
232
231
  lastModelViewTransform,
233
232
  targetIndex,
234
233
  );
235
- if (result.worldCoords.length < 6) return null; // Umbral de puntos mínimos para mantener el seguimiento
234
+ if (worldCoords.length < 6) return null; // Umbral de puntos mínimos para mantener el seguimiento
236
235
  const modelViewTransform = await this._workerTrackUpdate(lastModelViewTransform, {
237
- worldCoords: result.worldCoords,
238
- screenCoords: result.screenCoords,
236
+ worldCoords,
237
+ screenCoords,
239
238
  });
240
- return {
241
- modelViewTransform,
242
- inliers: result.worldCoords.length,
243
- octaveIndex: result.octaveIndex
244
- };
239
+ return modelViewTransform;
245
240
  }
246
241
 
247
242
  processVideo(input) {
@@ -257,7 +252,6 @@ class Controller {
257
252
  currentModelViewTransform: null,
258
253
  trackCount: 0,
259
254
  trackMiss: 0,
260
- stabilityCount: 0, // Nuevo: Contador para Live Adaptation
261
255
  filter: new OneEuroFilter({ minCutOff: this.filterMinCF, beta: this.filterBeta }),
262
256
  });
263
257
  }
@@ -273,14 +267,11 @@ class Controller {
273
267
  }, 0);
274
268
 
275
269
  // detect and match only if less then maxTrack
276
- // BUG FIX: Only match if we are NOT in a "ghosting" period for a target
277
- // to prevent the "found but immediately lost" loop that keeps opacity at 1.
278
270
  if (nTracking < this.maxTrack) {
279
271
  const matchingIndexes = [];
280
272
  for (let i = 0; i < this.trackingStates.length; i++) {
281
273
  const trackingState = this.trackingStates[i];
282
274
  if (trackingState.isTracking === true) continue;
283
- if (trackingState.showing === true) continue; // Don't try to re-detect if we are still buffers-showing the last position
284
275
  if (this.interestedTargetIndex !== -1 && this.interestedTargetIndex !== i) continue;
285
276
 
286
277
  matchingIndexes.push(i);
@@ -289,7 +280,7 @@ class Controller {
289
280
  const { targetIndex: matchedTargetIndex, modelViewTransform } =
290
281
  await this._detectAndMatch(inputData, matchingIndexes);
291
282
 
292
- if (matchedTargetIndex !== -1 && modelViewTransform) {
283
+ if (matchedTargetIndex !== -1) {
293
284
  this.trackingStates[matchedTargetIndex].isTracking = true;
294
285
  this.trackingStates[matchedTargetIndex].currentModelViewTransform = modelViewTransform;
295
286
  }
@@ -300,89 +291,69 @@ class Controller {
300
291
  const trackingState = this.trackingStates[i];
301
292
 
302
293
  if (trackingState.isTracking) {
303
- if (!trackingState.currentModelViewTransform) {
294
+ let modelViewTransform = await this._trackAndUpdate(
295
+ inputData,
296
+ trackingState.currentModelViewTransform,
297
+ i,
298
+ );
299
+ if (modelViewTransform === null) {
304
300
  trackingState.isTracking = false;
305
- trackingState.stabilityCount = 0;
306
301
  } else {
307
- let result = await this._trackAndUpdate(
308
- inputData,
309
- trackingState.currentModelViewTransform,
310
- i,
311
- );
312
- if (result === null) {
313
- trackingState.isTracking = false;
314
- trackingState.stabilityCount = 0;
315
- } else {
316
- trackingState.currentModelViewTransform = result.modelViewTransform;
317
-
318
- // --- LIVE MODEL ADAPTATION LOGIC ---
319
- // Si el tracking es muy sólido (muchos inliers) y estable, refinamos el modelo
320
- // Requisito: > 35 inliers (muy exigente) para evitar polución por ruido
321
- if (result.inliers > 35) {
322
- trackingState.stabilityCount++;
323
- if (trackingState.stabilityCount > 30) { // 30 frames (~1s) de estabilidad absoluta
324
- this.tracker.applyLiveFeedback(i, result.octaveIndex, 0.05); // Menor alpha (5%) para ser más conservador
325
- if (this.debugMode) console.log(`✨ Live Reification: Target ${i} (Octave ${result.octaveIndex}) updated.`);
326
- trackingState.stabilityCount = 0;
327
- }
328
- } else {
329
- trackingState.stabilityCount = Math.max(0, trackingState.stabilityCount - 1);
330
- }
331
- // -----------------------------------
332
- }
302
+ trackingState.currentModelViewTransform = modelViewTransform;
333
303
  }
304
+ }
334
305
 
335
- // if not showing, then show it once it reaches warmup number of frames
336
- if (!trackingState.showing) {
337
- if (trackingState.isTracking) {
338
- trackingState.trackMiss = 0;
339
- trackingState.trackCount += 1;
340
- if (trackingState.trackCount > this.warmupTolerance) {
341
- trackingState.showing = true;
342
- trackingState.trackingMatrix = null;
343
- trackingState.filter.reset();
344
- }
306
+ // if not showing, then show it once it reaches warmup number of frames
307
+ if (!trackingState.showing) {
308
+ if (trackingState.isTracking) {
309
+ trackingState.trackMiss = 0;
310
+ trackingState.trackCount += 1;
311
+ if (trackingState.trackCount > this.warmupTolerance) {
312
+ trackingState.showing = true;
313
+ trackingState.trackingMatrix = null;
314
+ trackingState.filter.reset();
345
315
  }
346
316
  }
317
+ }
347
318
 
348
- // if showing, then count miss, and hide it when reaches tolerance
349
- if (trackingState.showing) {
350
- if (!trackingState.isTracking) {
351
- trackingState.trackCount = 0;
352
- trackingState.trackMiss += 1;
353
-
354
- if (trackingState.trackMiss > this.missTolerance) {
355
- trackingState.showing = false;
356
- trackingState.trackingMatrix = null;
357
- this.onUpdate &&
358
- this.onUpdate({ type: "updateMatrix", targetIndex: i, worldMatrix: null });
359
- }
360
- } else {
361
- trackingState.trackMiss = 0;
319
+ // if showing, then count miss, and hide it when reaches tolerance
320
+ if (trackingState.showing) {
321
+ if (!trackingState.isTracking) {
322
+ trackingState.trackCount = 0;
323
+ trackingState.trackMiss += 1;
324
+
325
+ if (trackingState.trackMiss > this.missTolerance) {
326
+ trackingState.showing = false;
327
+ trackingState.trackingMatrix = null;
328
+ this.onUpdate &&
329
+ this.onUpdate({ type: "updateMatrix", targetIndex: i, worldMatrix: null });
362
330
  }
331
+ } else {
332
+ trackingState.trackMiss = 0;
363
333
  }
334
+ }
364
335
 
365
- // if showing, then call onUpdate, with world matrix
366
- if (trackingState.showing && trackingState.currentModelViewTransform) {
367
- const worldMatrix = this._glModelViewMatrix(trackingState.currentModelViewTransform, i);
368
- trackingState.trackingMatrix = trackingState.filter.filter(Date.now(), worldMatrix);
369
-
370
- let clone = [];
371
- for (let j = 0; j < trackingState.trackingMatrix.length; j++) {
372
- clone[j] = trackingState.trackingMatrix[j];
373
- }
336
+ // if showing, then call onUpdate, with world matrix
337
+ if (trackingState.showing) {
338
+ const worldMatrix = this._glModelViewMatrix(trackingState.currentModelViewTransform, i);
339
+ trackingState.trackingMatrix = trackingState.filter.filter(Date.now(), worldMatrix);
374
340
 
375
- const isInputRotated =
376
- input.width === this.inputHeight && input.height === this.inputWidth;
377
- if (isInputRotated) {
378
- clone = this.getRotatedZ90Matrix(clone);
379
- }
341
+ let clone = [];
342
+ for (let j = 0; j < trackingState.trackingMatrix.length; j++) {
343
+ clone[j] = trackingState.trackingMatrix[j];
344
+ }
380
345
 
381
- this.onUpdate &&
382
- this.onUpdate({ type: "updateMatrix", targetIndex: i, worldMatrix: clone, modelViewTransform: trackingState.currentModelViewTransform });
346
+ const isInputRotated =
347
+ input.width === this.inputHeight && input.height === this.inputWidth;
348
+ if (isInputRotated) {
349
+ clone = this.getRotatedZ90Matrix(clone);
383
350
  }
351
+
352
+ this.onUpdate &&
353
+ this.onUpdate({ type: "updateMatrix", targetIndex: i, worldMatrix: clone, modelViewTransform: trackingState.currentModelViewTransform });
384
354
  }
385
355
  }
356
+
386
357
  this.onUpdate && this.onUpdate({ type: "processDone" });
387
358
 
388
359
  // Use requestAnimationFrame if available, otherwise just wait briefly
@@ -530,7 +501,6 @@ class Controller {
530
501
  }
531
502
 
532
503
  _glModelViewMatrix(modelViewTransform, targetIndex) {
533
- if (!modelViewTransform) return null;
534
504
  const height = this.markerDimensions[targetIndex][1];
535
505
 
536
506
  const openGLWorldMatrix = [
@@ -61,7 +61,6 @@ class Tracker {
61
61
 
62
62
  track(inputData, lastModelViewTransform, targetIndex) {
63
63
  let debugExtra = {};
64
- if (!lastModelViewTransform) return { worldCoords: [], screenCoords: [], octaveIndex: 0, debugExtra };
65
64
 
66
65
  // Select the best octave based on current estimated distance/scale
67
66
  // We want the octave where the marker size is closest to its projected size on screen
@@ -128,7 +127,17 @@ class Tracker {
128
127
  }
129
128
  }
130
129
 
131
- return { worldCoords, screenCoords, octaveIndex, debugExtra };
130
+ if (this.debugMode) {
131
+ debugExtra = {
132
+ octaveIndex,
133
+ projectedImage: Array.from(projectedImage),
134
+ matchingPoints,
135
+ goodTrack,
136
+ trackedPoints: screenCoords,
137
+ };
138
+ }
139
+
140
+ return { worldCoords, screenCoords, debugExtra };
132
141
  }
133
142
 
134
143
  /**
@@ -291,34 +300,6 @@ class Tracker {
291
300
  }
292
301
  }
293
302
  }
294
-
295
- /**
296
- * Refines the target data (Living Mind Map) using actual camera feedback
297
- * @param {number} targetIndex
298
- * @param {number} octaveIndex
299
- * @param {number} alpha - Blending factor (e.g. 0.1 for 10% new data)
300
- */
301
- applyLiveFeedback(targetIndex, octaveIndex, alpha) {
302
- if (targetIndex === undefined || octaveIndex === undefined) return;
303
- const targetPrebuilts = this.prebuiltData[targetIndex];
304
- if (!targetPrebuilts) return;
305
-
306
- const prebuilt = targetPrebuilts[octaveIndex];
307
- if (!prebuilt || !prebuilt.projectedImage || !prebuilt.data) return;
308
-
309
- const markerPixels = prebuilt.data;
310
- const projectedPixels = prebuilt.projectedImage;
311
- const count = markerPixels.length;
312
-
313
- // Blend the projected (camera-sourced) pixels into the marker reference data
314
- // This allows the NCC matching to adapt to real-world lighting and print quality
315
- for (let i = 0; i < count; i++) {
316
- const val = projectedPixels[i];
317
- if (isNaN(val)) continue; // Don't pollute with NaN
318
- // Simple linear blend
319
- markerPixels[i] = (1 - alpha) * markerPixels[i] + alpha * val;
320
- }
321
- }
322
303
  }
323
304
 
324
305
  export { Tracker };