@srsergio/taptapp-ar 1.0.25 → 1.0.26

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.
@@ -136,36 +136,46 @@ class SimpleAR {
136
136
  const isPortrait = containerRect.height > containerRect.width;
137
137
  const isVideoLandscape = videoW > videoH;
138
138
  const needsRotation = isPortrait && isVideoLandscape;
139
- // The tracker uses 1280x720. Focal length is based on 720 (sensor height).
140
- const f = videoH / 2 / Math.tan((45.0 * Math.PI / 180) / 2);
141
- // Project Center of the marker into camera space
139
+ // Current display dimensions of the video (accounting for rotation)
140
+ const vW = needsRotation ? videoH : videoW;
141
+ const vH = needsRotation ? videoW : videoH;
142
+ // Robust "object-fit: cover" scale calculation
143
+ const perspectiveScale = Math.max(containerRect.width / vW, containerRect.height / vH);
144
+ const displayW = vW * perspectiveScale;
145
+ const displayH = vH * perspectiveScale;
146
+ const offsetX = (containerRect.width - displayW) / 2;
147
+ const offsetY = (containerRect.height - displayH) / 2;
148
+ // The tracker uses focal length based on height dimension in tracker space
149
+ const f = (videoH / 2) / Math.tan((45.0 * Math.PI / 180) / 2);
150
+ // Center of the marker in camera space (marker coordinates origin at top-left)
142
151
  const tx = mVT[0][0] * (markerW / 2) + mVT[0][1] * (markerH / 2) + mVT[0][3];
143
152
  const ty = mVT[1][0] * (markerW / 2) + mVT[1][1] * (markerH / 2) + mVT[1][3];
144
153
  const tz = mVT[2][0] * (markerW / 2) + mVT[2][1] * (markerH / 2) + mVT[2][3];
145
- let screenX, screenY, rotation, perspectiveScale;
154
+ let screenX, screenY, rotation;
146
155
  if (needsRotation) {
147
- // PORTRAIT MOBILE:
148
- // Browser rotates 1280 (W) -> vertical, 720 (H) -> horizontal
149
- const scale = containerRect.height / videoW;
150
- const displayW = videoH * scale;
151
- const offsetX = (containerRect.width - displayW) / 2;
152
- // Mapping: Buffer +X (Right) -> Screen +Y (Down), Buffer +Y (Down) -> Screen -X (Left)
153
- screenX = offsetX + (displayW / 2 - (ty * f / tz) * scale);
154
- screenY = (containerRect.height / 2 + (tx * f / tz) * scale);
156
+ // Mapping for 90deg clockwise rotation:
157
+ // Buffer X (0..videoW) -> Screen Y (0..displayH)
158
+ // Buffer Y (0..videoH) -> Screen X (displayW..0)
159
+ const bufferOffsetX = (tx * f / tz);
160
+ const bufferOffsetY = (ty * f / tz);
161
+ screenX = offsetX + (displayW / 2) - (bufferOffsetY * perspectiveScale);
162
+ screenY = offsetY + (displayH / 2) + (bufferOffsetX * perspectiveScale);
155
163
  rotation = Math.atan2(mVT[1][0], mVT[0][0]) - Math.PI / 2;
156
- perspectiveScale = scale;
157
164
  }
158
165
  else {
159
- // LANDSCAPE / LAPTOP:
160
- const scale = containerRect.width / videoW;
161
- const displayH = videoH * scale;
162
- const offsetY = (containerRect.height - displayH) / 2;
163
- screenX = (containerRect.width / 2 + (tx * f / tz) * scale);
164
- screenY = offsetY + (displayH / 2 + (ty * f / tz) * scale);
166
+ // Normal mapping:
167
+ // Buffer X -> Screen X
168
+ // Buffer Y -> Screen Y
169
+ const bufferOffsetX = (tx * f / tz);
170
+ const bufferOffsetY = (ty * f / tz);
171
+ screenX = offsetX + (displayW / 2) + (bufferOffsetX * perspectiveScale);
172
+ screenY = offsetY + (displayH / 2) + (bufferOffsetY * perspectiveScale);
165
173
  rotation = Math.atan2(mVT[1][0], mVT[0][0]);
166
- perspectiveScale = scale;
167
174
  }
168
- // Final Scale
175
+ // Final Scale calculation:
176
+ // f/tz converts world units to buffer pixels
177
+ // perspectiveScale converts buffer pixels to screen pixels
178
+ // matrixScale handles the target's relative orientation in 2D
169
179
  const matrixScale = Math.sqrt(mVT[0][0] ** 2 + mVT[1][0] ** 2);
170
180
  const finalScale = (f / tz) * perspectiveScale * matrixScale * this.scaleMultiplier;
171
181
  // Apply
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@srsergio/taptapp-ar",
3
- "version": "1.0.25",
3
+ "version": "1.0.26",
4
4
  "description": "AR Compiler for Node.js and Browser",
5
5
  "repository": {
6
6
  "type": "git",
@@ -163,43 +163,54 @@ class SimpleAR {
163
163
  const isVideoLandscape = videoW > videoH;
164
164
  const needsRotation = isPortrait && isVideoLandscape;
165
165
 
166
- // The tracker uses 1280x720. Focal length is based on 720 (sensor height).
167
- const f = videoH / 2 / Math.tan((45.0 * Math.PI / 180) / 2);
166
+ // Current display dimensions of the video (accounting for rotation)
167
+ const vW = needsRotation ? videoH : videoW;
168
+ const vH = needsRotation ? videoW : videoH;
168
169
 
169
- // Project Center of the marker into camera space
170
+ // Robust "object-fit: cover" scale calculation
171
+ const perspectiveScale = Math.max(containerRect.width / vW, containerRect.height / vH);
172
+
173
+ const displayW = vW * perspectiveScale;
174
+ const displayH = vH * perspectiveScale;
175
+ const offsetX = (containerRect.width - displayW) / 2;
176
+ const offsetY = (containerRect.height - displayH) / 2;
177
+
178
+ // The tracker uses focal length based on height dimension in tracker space
179
+ const f = (videoH / 2) / Math.tan((45.0 * Math.PI / 180) / 2);
180
+
181
+ // Center of the marker in camera space (marker coordinates origin at top-left)
170
182
  const tx = mVT[0][0] * (markerW / 2) + mVT[0][1] * (markerH / 2) + mVT[0][3];
171
183
  const ty = mVT[1][0] * (markerW / 2) + mVT[1][1] * (markerH / 2) + mVT[1][3];
172
184
  const tz = mVT[2][0] * (markerW / 2) + mVT[2][1] * (markerH / 2) + mVT[2][3];
173
185
 
174
- let screenX, screenY, rotation, perspectiveScale;
186
+ let screenX, screenY, rotation;
175
187
 
176
188
  if (needsRotation) {
177
- // PORTRAIT MOBILE:
178
- // Browser rotates 1280 (W) -> vertical, 720 (H) -> horizontal
179
- const scale = containerRect.height / videoW;
180
- const displayW = videoH * scale;
181
- const offsetX = (containerRect.width - displayW) / 2;
182
-
183
- // Mapping: Buffer +X (Right) -> Screen +Y (Down), Buffer +Y (Down) -> Screen -X (Left)
184
- screenX = offsetX + (displayW / 2 - (ty * f / tz) * scale);
185
- screenY = (containerRect.height / 2 + (tx * f / tz) * scale);
186
-
189
+ // Mapping for 90deg clockwise rotation:
190
+ // Buffer X (0..videoW) -> Screen Y (0..displayH)
191
+ // Buffer Y (0..videoH) -> Screen X (displayW..0)
192
+ const bufferOffsetX = (tx * f / tz);
193
+ const bufferOffsetY = (ty * f / tz);
194
+
195
+ screenX = offsetX + (displayW / 2) - (bufferOffsetY * perspectiveScale);
196
+ screenY = offsetY + (displayH / 2) + (bufferOffsetX * perspectiveScale);
187
197
  rotation = Math.atan2(mVT[1][0], mVT[0][0]) - Math.PI / 2;
188
- perspectiveScale = scale;
189
198
  } else {
190
- // LANDSCAPE / LAPTOP:
191
- const scale = containerRect.width / videoW;
192
- const displayH = videoH * scale;
193
- const offsetY = (containerRect.height - displayH) / 2;
194
-
195
- screenX = (containerRect.width / 2 + (tx * f / tz) * scale);
196
- screenY = offsetY + (displayH / 2 + (ty * f / tz) * scale);
197
-
199
+ // Normal mapping:
200
+ // Buffer X -> Screen X
201
+ // Buffer Y -> Screen Y
202
+ const bufferOffsetX = (tx * f / tz);
203
+ const bufferOffsetY = (ty * f / tz);
204
+
205
+ screenX = offsetX + (displayW / 2) + (bufferOffsetX * perspectiveScale);
206
+ screenY = offsetY + (displayH / 2) + (bufferOffsetY * perspectiveScale);
198
207
  rotation = Math.atan2(mVT[1][0], mVT[0][0]);
199
- perspectiveScale = scale;
200
208
  }
201
209
 
202
- // Final Scale
210
+ // Final Scale calculation:
211
+ // f/tz converts world units to buffer pixels
212
+ // perspectiveScale converts buffer pixels to screen pixels
213
+ // matrixScale handles the target's relative orientation in 2D
203
214
  const matrixScale = Math.sqrt(mVT[0][0] ** 2 + mVT[1][0] ** 2);
204
215
  const finalScale = (f / tz) * perspectiveScale * matrixScale * this.scaleMultiplier;
205
216