@srsergio/taptapp-ar 1.0.0

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.
Files changed (207) hide show
  1. package/README.md +62 -0
  2. package/dist/compiler/aframe.d.ts +1 -0
  3. package/dist/compiler/aframe.js +275 -0
  4. package/dist/compiler/compiler-base.d.ts +12 -0
  5. package/dist/compiler/compiler-base.js +165 -0
  6. package/dist/compiler/compiler.d.ts +9 -0
  7. package/dist/compiler/compiler.js +24 -0
  8. package/dist/compiler/compiler.worker.d.ts +1 -0
  9. package/dist/compiler/compiler.worker.js +28 -0
  10. package/dist/compiler/controller.d.ts +101 -0
  11. package/dist/compiler/controller.js +400 -0
  12. package/dist/compiler/controller.worker.d.ts +1 -0
  13. package/dist/compiler/controller.worker.js +61 -0
  14. package/dist/compiler/detector/crop-detector.d.ts +65 -0
  15. package/dist/compiler/detector/crop-detector.js +59 -0
  16. package/dist/compiler/detector/detector.d.ts +98 -0
  17. package/dist/compiler/detector/detector.js +1049 -0
  18. package/dist/compiler/detector/freak.d.ts +1 -0
  19. package/dist/compiler/detector/freak.js +89 -0
  20. package/dist/compiler/detector/kernels/cpu/binomialFilter.d.ts +6 -0
  21. package/dist/compiler/detector/kernels/cpu/binomialFilter.js +51 -0
  22. package/dist/compiler/detector/kernels/cpu/buildExtremas.d.ts +6 -0
  23. package/dist/compiler/detector/kernels/cpu/buildExtremas.js +89 -0
  24. package/dist/compiler/detector/kernels/cpu/computeExtremaAngles.d.ts +7 -0
  25. package/dist/compiler/detector/kernels/cpu/computeExtremaAngles.js +79 -0
  26. package/dist/compiler/detector/kernels/cpu/computeExtremaFreak.d.ts +6 -0
  27. package/dist/compiler/detector/kernels/cpu/computeExtremaFreak.js +68 -0
  28. package/dist/compiler/detector/kernels/cpu/computeFreakDescriptors.d.ts +6 -0
  29. package/dist/compiler/detector/kernels/cpu/computeFreakDescriptors.js +57 -0
  30. package/dist/compiler/detector/kernels/cpu/computeLocalization.d.ts +6 -0
  31. package/dist/compiler/detector/kernels/cpu/computeLocalization.js +54 -0
  32. package/dist/compiler/detector/kernels/cpu/computeOrientationHistograms.d.ts +6 -0
  33. package/dist/compiler/detector/kernels/cpu/computeOrientationHistograms.js +118 -0
  34. package/dist/compiler/detector/kernels/cpu/downsampleBilinear.d.ts +6 -0
  35. package/dist/compiler/detector/kernels/cpu/downsampleBilinear.js +29 -0
  36. package/dist/compiler/detector/kernels/cpu/extremaReduction.d.ts +6 -0
  37. package/dist/compiler/detector/kernels/cpu/extremaReduction.js +50 -0
  38. package/dist/compiler/detector/kernels/cpu/fakeShader.d.ts +20 -0
  39. package/dist/compiler/detector/kernels/cpu/fakeShader.js +80 -0
  40. package/dist/compiler/detector/kernels/cpu/index.d.ts +1 -0
  41. package/dist/compiler/detector/kernels/cpu/index.js +25 -0
  42. package/dist/compiler/detector/kernels/cpu/prune.d.ts +1 -0
  43. package/dist/compiler/detector/kernels/cpu/prune.js +103 -0
  44. package/dist/compiler/detector/kernels/cpu/smoothHistograms.d.ts +6 -0
  45. package/dist/compiler/detector/kernels/cpu/smoothHistograms.js +47 -0
  46. package/dist/compiler/detector/kernels/cpu/upsampleBilinear.d.ts +6 -0
  47. package/dist/compiler/detector/kernels/cpu/upsampleBilinear.js +43 -0
  48. package/dist/compiler/detector/kernels/index.d.ts +1 -0
  49. package/dist/compiler/detector/kernels/index.js +2 -0
  50. package/dist/compiler/detector/kernels/webgl/binomialFilter.d.ts +6 -0
  51. package/dist/compiler/detector/kernels/webgl/binomialFilter.js +67 -0
  52. package/dist/compiler/detector/kernels/webgl/buildExtremas.d.ts +6 -0
  53. package/dist/compiler/detector/kernels/webgl/buildExtremas.js +101 -0
  54. package/dist/compiler/detector/kernels/webgl/computeExtremaAngles.d.ts +6 -0
  55. package/dist/compiler/detector/kernels/webgl/computeExtremaAngles.js +78 -0
  56. package/dist/compiler/detector/kernels/webgl/computeExtremaFreak.d.ts +6 -0
  57. package/dist/compiler/detector/kernels/webgl/computeExtremaFreak.js +86 -0
  58. package/dist/compiler/detector/kernels/webgl/computeFreakDescriptors.d.ts +6 -0
  59. package/dist/compiler/detector/kernels/webgl/computeFreakDescriptors.js +52 -0
  60. package/dist/compiler/detector/kernels/webgl/computeLocalization.d.ts +6 -0
  61. package/dist/compiler/detector/kernels/webgl/computeLocalization.js +58 -0
  62. package/dist/compiler/detector/kernels/webgl/computeOrientationHistograms.d.ts +6 -0
  63. package/dist/compiler/detector/kernels/webgl/computeOrientationHistograms.js +116 -0
  64. package/dist/compiler/detector/kernels/webgl/downsampleBilinear.d.ts +6 -0
  65. package/dist/compiler/detector/kernels/webgl/downsampleBilinear.js +46 -0
  66. package/dist/compiler/detector/kernels/webgl/extremaReduction.d.ts +6 -0
  67. package/dist/compiler/detector/kernels/webgl/extremaReduction.js +48 -0
  68. package/dist/compiler/detector/kernels/webgl/index.d.ts +1 -0
  69. package/dist/compiler/detector/kernels/webgl/index.js +25 -0
  70. package/dist/compiler/detector/kernels/webgl/smoothHistograms.d.ts +6 -0
  71. package/dist/compiler/detector/kernels/webgl/smoothHistograms.js +49 -0
  72. package/dist/compiler/detector/kernels/webgl/upsampleBilinear.d.ts +6 -0
  73. package/dist/compiler/detector/kernels/webgl/upsampleBilinear.js +56 -0
  74. package/dist/compiler/estimation/esimate-experiment.d.ts +5 -0
  75. package/dist/compiler/estimation/esimate-experiment.js +267 -0
  76. package/dist/compiler/estimation/estimate.d.ts +5 -0
  77. package/dist/compiler/estimation/estimate.js +51 -0
  78. package/dist/compiler/estimation/estimator.d.ts +13 -0
  79. package/dist/compiler/estimation/estimator.js +30 -0
  80. package/dist/compiler/estimation/refine-estimate-experiment.d.ts +6 -0
  81. package/dist/compiler/estimation/refine-estimate-experiment.js +429 -0
  82. package/dist/compiler/estimation/refine-estimate.d.ts +6 -0
  83. package/dist/compiler/estimation/refine-estimate.js +299 -0
  84. package/dist/compiler/estimation/utils.d.ts +10 -0
  85. package/dist/compiler/estimation/utils.js +80 -0
  86. package/dist/compiler/image-list.d.ts +13 -0
  87. package/dist/compiler/image-list.js +52 -0
  88. package/dist/compiler/index.d.ts +3 -0
  89. package/dist/compiler/index.js +10 -0
  90. package/dist/compiler/input-loader.d.ts +23 -0
  91. package/dist/compiler/input-loader.js +88 -0
  92. package/dist/compiler/matching/hamming-distance.d.ts +1 -0
  93. package/dist/compiler/matching/hamming-distance.js +20 -0
  94. package/dist/compiler/matching/hierarchical-clustering.d.ts +7 -0
  95. package/dist/compiler/matching/hierarchical-clustering.js +109 -0
  96. package/dist/compiler/matching/hough.d.ts +1 -0
  97. package/dist/compiler/matching/hough.js +169 -0
  98. package/dist/compiler/matching/matcher.d.ts +28 -0
  99. package/dist/compiler/matching/matcher.js +48 -0
  100. package/dist/compiler/matching/matching.d.ts +41 -0
  101. package/dist/compiler/matching/matching.js +197 -0
  102. package/dist/compiler/matching/ransacHomography.d.ts +1 -0
  103. package/dist/compiler/matching/ransacHomography.js +136 -0
  104. package/dist/compiler/offline-compiler.d.ts +10 -0
  105. package/dist/compiler/offline-compiler.js +450 -0
  106. package/dist/compiler/tensorflow-setup.d.ts +7 -0
  107. package/dist/compiler/tensorflow-setup.js +73 -0
  108. package/dist/compiler/three.d.ts +66 -0
  109. package/dist/compiler/three.js +310 -0
  110. package/dist/compiler/tracker/extract-utils.d.ts +1 -0
  111. package/dist/compiler/tracker/extract-utils.js +29 -0
  112. package/dist/compiler/tracker/extract.d.ts +4 -0
  113. package/dist/compiler/tracker/extract.js +349 -0
  114. package/dist/compiler/tracker/tracker.d.ts +38 -0
  115. package/dist/compiler/tracker/tracker.js +327 -0
  116. package/dist/compiler/utils/cumsum.d.ts +5 -0
  117. package/dist/compiler/utils/cumsum.js +39 -0
  118. package/dist/compiler/utils/geometry.d.ts +8 -0
  119. package/dist/compiler/utils/geometry.js +101 -0
  120. package/dist/compiler/utils/homography.d.ts +1 -0
  121. package/dist/compiler/utils/homography.js +138 -0
  122. package/dist/compiler/utils/images.d.ts +24 -0
  123. package/dist/compiler/utils/images.js +99 -0
  124. package/dist/compiler/utils/randomizer.d.ts +5 -0
  125. package/dist/compiler/utils/randomizer.js +25 -0
  126. package/dist/index.d.ts +6 -0
  127. package/dist/index.js +7 -0
  128. package/dist/react/AREditor.d.ts +5 -0
  129. package/dist/react/AREditor.js +159 -0
  130. package/dist/react/ProgressDialog.d.ts +13 -0
  131. package/dist/react/ProgressDialog.js +57 -0
  132. package/dist/react/types.d.ts +22 -0
  133. package/dist/react/types.js +14 -0
  134. package/package.json +53 -0
  135. package/src/astro/ARScene.astro +59 -0
  136. package/src/astro/ARVideoTrigger.astro +73 -0
  137. package/src/astro/overlays/ErrorOverlay.astro +40 -0
  138. package/src/astro/overlays/LoadingOverlay.astro +28 -0
  139. package/src/astro/overlays/ScanningOverlay.astro +119 -0
  140. package/src/astro/scripts/ARScripts.astro +118 -0
  141. package/src/astro/styles/ARStyles.astro +147 -0
  142. package/src/compiler/aframe.js +343 -0
  143. package/src/compiler/compiler-base.js +195 -0
  144. package/src/compiler/compiler.js +25 -0
  145. package/src/compiler/compiler.worker.js +30 -0
  146. package/src/compiler/controller.js +473 -0
  147. package/src/compiler/controller.worker.js +77 -0
  148. package/src/compiler/detector/crop-detector.js +68 -0
  149. package/src/compiler/detector/detector.js +1130 -0
  150. package/src/compiler/detector/freak.js +91 -0
  151. package/src/compiler/detector/kernels/cpu/binomialFilter.js +59 -0
  152. package/src/compiler/detector/kernels/cpu/buildExtremas.js +108 -0
  153. package/src/compiler/detector/kernels/cpu/computeExtremaAngles.js +91 -0
  154. package/src/compiler/detector/kernels/cpu/computeExtremaFreak.js +92 -0
  155. package/src/compiler/detector/kernels/cpu/computeFreakDescriptors.js +68 -0
  156. package/src/compiler/detector/kernels/cpu/computeLocalization.js +71 -0
  157. package/src/compiler/detector/kernels/cpu/computeOrientationHistograms.js +141 -0
  158. package/src/compiler/detector/kernels/cpu/downsampleBilinear.js +33 -0
  159. package/src/compiler/detector/kernels/cpu/extremaReduction.js +53 -0
  160. package/src/compiler/detector/kernels/cpu/fakeShader.js +88 -0
  161. package/src/compiler/detector/kernels/cpu/index.js +26 -0
  162. package/src/compiler/detector/kernels/cpu/prune.js +114 -0
  163. package/src/compiler/detector/kernels/cpu/smoothHistograms.js +57 -0
  164. package/src/compiler/detector/kernels/cpu/upsampleBilinear.js +51 -0
  165. package/src/compiler/detector/kernels/index.js +2 -0
  166. package/src/compiler/detector/kernels/webgl/binomialFilter.js +72 -0
  167. package/src/compiler/detector/kernels/webgl/buildExtremas.js +109 -0
  168. package/src/compiler/detector/kernels/webgl/computeExtremaAngles.js +82 -0
  169. package/src/compiler/detector/kernels/webgl/computeExtremaFreak.js +105 -0
  170. package/src/compiler/detector/kernels/webgl/computeFreakDescriptors.js +56 -0
  171. package/src/compiler/detector/kernels/webgl/computeLocalization.js +70 -0
  172. package/src/compiler/detector/kernels/webgl/computeOrientationHistograms.js +129 -0
  173. package/src/compiler/detector/kernels/webgl/downsampleBilinear.js +50 -0
  174. package/src/compiler/detector/kernels/webgl/extremaReduction.js +50 -0
  175. package/src/compiler/detector/kernels/webgl/index.js +26 -0
  176. package/src/compiler/detector/kernels/webgl/smoothHistograms.js +53 -0
  177. package/src/compiler/detector/kernels/webgl/upsampleBilinear.js +62 -0
  178. package/src/compiler/estimation/esimate-experiment.js +316 -0
  179. package/src/compiler/estimation/estimate.js +67 -0
  180. package/src/compiler/estimation/estimator.js +34 -0
  181. package/src/compiler/estimation/refine-estimate-experiment.js +512 -0
  182. package/src/compiler/estimation/refine-estimate.js +365 -0
  183. package/src/compiler/estimation/utils.js +97 -0
  184. package/src/compiler/image-list.js +62 -0
  185. package/src/compiler/index.js +13 -0
  186. package/src/compiler/input-loader.js +107 -0
  187. package/src/compiler/matching/hamming-distance.js +23 -0
  188. package/src/compiler/matching/hierarchical-clustering.js +131 -0
  189. package/src/compiler/matching/hough.js +206 -0
  190. package/src/compiler/matching/matcher.js +59 -0
  191. package/src/compiler/matching/matching.js +237 -0
  192. package/src/compiler/matching/ransacHomography.js +192 -0
  193. package/src/compiler/offline-compiler.js +553 -0
  194. package/src/compiler/tensorflow-setup.js +88 -0
  195. package/src/compiler/three.js +368 -0
  196. package/src/compiler/tracker/extract-utils.js +34 -0
  197. package/src/compiler/tracker/extract.js +419 -0
  198. package/src/compiler/tracker/tracker.js +397 -0
  199. package/src/compiler/utils/cumsum.js +40 -0
  200. package/src/compiler/utils/geometry.js +114 -0
  201. package/src/compiler/utils/homography.js +150 -0
  202. package/src/compiler/utils/images.js +111 -0
  203. package/src/compiler/utils/randomizer.js +29 -0
  204. package/src/index.ts +8 -0
  205. package/src/react/AREditor.tsx +394 -0
  206. package/src/react/ProgressDialog.tsx +185 -0
  207. package/src/react/types.ts +35 -0
@@ -0,0 +1,111 @@
1
+ // simpler version of upsampling. better performance
2
+ const _upsampleBilinear = ({ image, padOneWidth, padOneHeight }) => {
3
+ const { width, height, data } = image;
4
+ const dstWidth = image.width * 2 + (padOneWidth ? 1 : 0);
5
+ const dstHeight = image.height * 2 + (padOneHeight ? 1 : 0);
6
+ const temp = new Float32Array(dstWidth * dstHeight);
7
+
8
+ for (let i = 0; i < width; i++) {
9
+ for (let j = 0; j < height; j++) {
10
+ const v = 0.25 * data[j * width + i];
11
+ const ii = Math.floor(i / 2);
12
+ const jj = Math.floor(j / 2);
13
+ const pos = Math.floor(j / 2) * dstWidth + Math.floor(i / 2);
14
+ temp[pos] += v;
15
+ temp[pos + 1] += v;
16
+ temp[pos + dstWidth] += v;
17
+ temp[pos + dstWidth + 1] += v;
18
+ }
19
+ }
20
+ return { data: temp, width: dstWidth, height: dstHeight };
21
+ };
22
+
23
+ // artoolkit version. slower. is it necessary?
24
+ const upsampleBilinear = ({ image, padOneWidth, padOneHeight }) => {
25
+ const { width, height, data } = image;
26
+
27
+ const dstWidth = image.width * 2 + (padOneWidth ? 1 : 0);
28
+ const dstHeight = image.height * 2 + (padOneHeight ? 1 : 0);
29
+
30
+ const temp = new Float32Array(dstWidth * dstHeight);
31
+ for (let i = 0; i < dstWidth; i++) {
32
+ const si = 0.5 * i - 0.25;
33
+ let si0 = Math.floor(si);
34
+ let si1 = Math.ceil(si);
35
+ if (si0 < 0) si0 = 0; // border
36
+ if (si1 >= width) si1 = width - 1; // border
37
+
38
+ for (let j = 0; j < dstHeight; j++) {
39
+ const sj = 0.5 * j - 0.25;
40
+ let sj0 = Math.floor(sj);
41
+ let sj1 = Math.ceil(sj);
42
+ if (sj0 < 0) sj0 = 0; // border
43
+ if (sj1 >= height) sj1 = height - 1; //border
44
+
45
+ const value =
46
+ (si1 - si) * (sj1 - sj) * data[sj0 * width + si0] +
47
+ (si1 - si) * (sj - sj0) * data[sj1 * width + si0] +
48
+ (si - si0) * (sj1 - sj) * data[sj0 * width + si1] +
49
+ (si - si0) * (sj - sj0) * data[sj1 * width + si1];
50
+
51
+ temp[j * dstWidth + i] = value;
52
+ }
53
+ }
54
+
55
+ return { data: temp, width: dstWidth, height: dstHeight };
56
+ };
57
+
58
+ const downsampleBilinear = ({ image }) => {
59
+ const { data, width, height } = image;
60
+
61
+ const dstWidth = Math.floor(width / 2);
62
+ const dstHeight = Math.floor(height / 2);
63
+
64
+ const temp = new Float32Array(dstWidth * dstHeight);
65
+ const offsets = [0, 1, width, width + 1];
66
+
67
+ for (let j = 0; j < dstHeight; j++) {
68
+ for (let i = 0; i < dstWidth; i++) {
69
+ let srcPos = j * 2 * width + i * 2;
70
+ let value = 0.0;
71
+ for (let d = 0; d < offsets.length; d++) {
72
+ value += data[srcPos + offsets[d]];
73
+ }
74
+ value *= 0.25;
75
+ temp[j * dstWidth + i] = value;
76
+ }
77
+ }
78
+ return { data: temp, width: dstWidth, height: dstHeight };
79
+ };
80
+
81
+ const resize = ({ image, ratio }) => {
82
+ const width = Math.round(image.width * ratio);
83
+ const height = Math.round(image.height * ratio);
84
+
85
+ //const imageData = new Float32Array(width * height);
86
+ const imageData = new Uint8Array(width * height);
87
+ for (let i = 0; i < width; i++) {
88
+ let si1 = Math.round((1.0 * i) / ratio);
89
+ let si2 = Math.round((1.0 * (i + 1)) / ratio) - 1;
90
+ if (si2 >= image.width) si2 = image.width - 1;
91
+
92
+ for (let j = 0; j < height; j++) {
93
+ let sj1 = Math.round((1.0 * j) / ratio);
94
+ let sj2 = Math.round((1.0 * (j + 1)) / ratio) - 1;
95
+ if (sj2 >= image.height) sj2 = image.height - 1;
96
+
97
+ let sum = 0;
98
+ let count = 0;
99
+ for (let ii = si1; ii <= si2; ii++) {
100
+ for (let jj = sj1; jj <= sj2; jj++) {
101
+ sum += 1.0 * image.data[jj * image.width + ii];
102
+ count += 1;
103
+ }
104
+ }
105
+ imageData[j * width + i] = Math.floor(sum / count);
106
+ }
107
+ }
108
+ return { data: imageData, width: width, height: height };
109
+ };
110
+
111
+ export { downsampleBilinear, upsampleBilinear, resize };
@@ -0,0 +1,29 @@
1
+ const mRandSeed = 1234;
2
+
3
+ const createRandomizer = () => {
4
+ const randomizer = {
5
+ seed: mRandSeed,
6
+
7
+ arrayShuffle(options) {
8
+ const { arr, sampleSize } = options;
9
+ for (let i = 0; i < sampleSize; i++) {
10
+ this.seed = (214013 * this.seed + 2531011) % (1 << 31);
11
+ let k = (this.seed >> 16) & 0x7fff;
12
+ k = k % arr.length;
13
+
14
+ let tmp = arr[i];
15
+ arr[i] = arr[k];
16
+ arr[k] = tmp;
17
+ }
18
+ },
19
+
20
+ nextInt(maxValue) {
21
+ this.seed = (214013 * this.seed + 2531011) % (1 << 31);
22
+ let k = (this.seed >> 16) & 0x7fff;
23
+ k = k % maxValue;
24
+ return k;
25
+ },
26
+ };
27
+ return randomizer;
28
+ };
29
+ export { createRandomizer };
package/src/index.ts ADDED
@@ -0,0 +1,8 @@
1
+ export * from "./react/AREditor";
2
+ export * from "./react/ProgressDialog";
3
+ export * from "./react/types";
4
+ export * from "./compiler/offline-compiler";
5
+
6
+ // Re-export specific compiler components if needed
7
+ export { Controller } from "./compiler/controller";
8
+ export { Compiler } from "./compiler/compiler";
@@ -0,0 +1,394 @@
1
+ import { useState, useRef, useCallback } from "react";
2
+ import { customAlphabet } from "nanoid";
3
+ import { Image, Video, Upload, Camera, LoaderCircle } from "lucide-react";
4
+
5
+ const ALLOWED_MIME_TYPES = ["image/jpeg", "image/png", "image/webp"];
6
+ const ALLOWED_VIDEO_TYPES = ["video/mp4", "video/webm"];
7
+
8
+ interface FileUploadState {
9
+ file: File | null;
10
+ preview: string;
11
+ }
12
+
13
+ interface AREditorProps {
14
+ adminId: string;
15
+ }
16
+
17
+ const useFileUpload = (allowedTypes: string[]) => {
18
+ const [fileState, setFileState] = useState<FileUploadState>({ file: null, preview: "" });
19
+ const [dimensions, setDimensions] = useState<{ width?: number; height?: number }>({});
20
+ const fileInputRef = useRef<HTMLInputElement>(null);
21
+
22
+ const handleFileChange = useCallback(
23
+ (file: File | null) => {
24
+ if (fileState.preview) {
25
+ URL.revokeObjectURL(fileState.preview);
26
+ }
27
+
28
+ if (!file) {
29
+ setFileState({ file: null, preview: "" });
30
+ return;
31
+ }
32
+
33
+ // Para archivos .mind, validar la extensión en lugar del tipo MIME
34
+ if (allowedTypes.includes(".mind")) {
35
+ if (!file.name.toLowerCase().endsWith(".mind")) {
36
+ throw new Error("El archivo debe tener extensión .mind");
37
+ }
38
+ } else if (!allowedTypes.includes(file.type)) {
39
+ throw new Error("Tipo de archivo no permitido");
40
+ }
41
+
42
+ if (file.type.includes("video")) {
43
+ const video = document.createElement("video");
44
+ video.src = URL.createObjectURL(file);
45
+ }
46
+
47
+ console.log("Archivo cargado:", {
48
+ nombre: file.name,
49
+ tamaño: (file.size / 1024).toFixed(2) + " KB",
50
+ tipo: file.type || "application/octet-stream",
51
+ });
52
+
53
+ const preview = URL.createObjectURL(file);
54
+ if (file.type.includes("video")) {
55
+ const video = document.createElement("video");
56
+ video.src = URL.createObjectURL(file);
57
+ video.addEventListener("loadedmetadata", () => {
58
+ const width = video.videoWidth;
59
+ const height = video.videoHeight;
60
+ setDimensions({ width, height });
61
+ console.log("Ancho y alto del video:", width, height);
62
+ });
63
+ }
64
+
65
+ setFileState({ file, preview });
66
+ },
67
+ [allowedTypes, fileState.preview],
68
+ );
69
+
70
+ const reset = useCallback(() => {
71
+ if (fileState.preview) {
72
+ URL.revokeObjectURL(fileState.preview);
73
+ }
74
+ setFileState({ file: null, preview: "" });
75
+ if (fileInputRef.current) {
76
+ fileInputRef.current.value = "";
77
+ }
78
+ }, [fileState.preview]);
79
+
80
+ return { fileState, handleFileChange, reset, fileInputRef, dimensions };
81
+ };
82
+
83
+ const useUploadFile = () => {
84
+ const uploadFile = async (file: File, type: "image" | "video" | "mind") => {
85
+ const customNanoid = customAlphabet("1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ", 21);
86
+ const id = customNanoid();
87
+ const formData = new FormData();
88
+ formData.append("file", file);
89
+
90
+ const endpoint =
91
+ type === "video"
92
+ ? `https://r2-worker.sergiolazaromondargo.workers.dev/video/${id}`
93
+ : type === "mind"
94
+ ? `https://r2-worker.sergiolazaromondargo.workers.dev/mind/${id}`
95
+ : `https://r2-worker.sergiolazaromondargo.workers.dev/${id}`;
96
+
97
+ const response = await fetch(endpoint, {
98
+ method: "PUT",
99
+ body: formData,
100
+ });
101
+
102
+ if (!response.ok) {
103
+ throw new Error(`Error al subir ${type}: ${response.status} ${response.statusText}`);
104
+ }
105
+
106
+ return await response.json();
107
+ };
108
+
109
+ return { uploadFile };
110
+ };
111
+
112
+ export const AREditor: React.FC<AREditorProps> = ({ adminId }) => {
113
+ const {
114
+ fileState: imageState,
115
+ handleFileChange: handleImageChange,
116
+ reset: resetImage,
117
+ fileInputRef: imageInputRef,
118
+ } = useFileUpload(ALLOWED_MIME_TYPES);
119
+
120
+ const {
121
+ fileState: mindState,
122
+ handleFileChange: handleMindChange,
123
+ reset: resetMind,
124
+ fileInputRef: mindInputRef,
125
+ } = useFileUpload([".mind"]);
126
+
127
+ const {
128
+ fileState: videoState,
129
+ handleFileChange: handleVideoChange,
130
+ reset: resetVideo,
131
+ fileInputRef: videoInputRef,
132
+ dimensions: videoDimensions,
133
+ } = useFileUpload(ALLOWED_VIDEO_TYPES);
134
+
135
+ const [videoScale, setVideoScale] = useState<number>(1);
136
+ const [loading, setLoading] = useState(false);
137
+ const [error, setError] = useState<string>("");
138
+
139
+ const { uploadFile } = useUploadFile();
140
+
141
+ const handleSave = async () => {
142
+ try {
143
+ setLoading(true);
144
+ setError("");
145
+
146
+ if (!imageState.file || !mindState.file || !videoState.file) {
147
+ throw new Error("Se requieren una imagen, un archivo .mind y un video");
148
+ }
149
+
150
+ const [imageResult, mindResult, videoResult] = await Promise.all([
151
+ uploadFile(imageState.file, "image"),
152
+ uploadFile(mindState.file, "mind"),
153
+ uploadFile(videoState.file, "video"),
154
+ ]);
155
+
156
+ const data = {
157
+ adminId,
158
+ data: [
159
+ {
160
+ id: `photos-${Date.now()}`,
161
+ type: "photos",
162
+ images: [{ image: imageResult.url, fileId: imageResult.fileId }],
163
+ },
164
+ {
165
+ id: `videoNative-${Date.now()}`,
166
+ type: "videoNative",
167
+ url: videoResult.url,
168
+ fileId: videoResult.fileId,
169
+ scale: videoScale,
170
+ width: videoDimensions.width,
171
+ height: videoDimensions.height,
172
+ },
173
+ {
174
+ id: `ar-${Date.now()}`,
175
+ type: "ar",
176
+ url: mindResult.url,
177
+ fileId: mindResult.fileId,
178
+ },
179
+ ],
180
+ type: "ar",
181
+ };
182
+
183
+ const response = await fetch("/api/updateadmin.json", {
184
+ method: "POST",
185
+ headers: { "Content-Type": "application/json" },
186
+ body: JSON.stringify(data),
187
+ });
188
+
189
+ if (!response.ok) {
190
+ throw new Error(`Error actualizando datos AR: ${response.status}`);
191
+ }
192
+
193
+ alert("¡Guardado exitosamente!");
194
+ resetImage();
195
+ resetMind();
196
+ resetVideo();
197
+ } catch (error: any) {
198
+ setError(error.message);
199
+ } finally {
200
+ setLoading(false);
201
+ }
202
+ };
203
+
204
+ const FileUploadSection = ({
205
+ type,
206
+ icon: Icon,
207
+ fileState,
208
+ inputRef,
209
+ onFileChange,
210
+ allowedTypes,
211
+ label,
212
+ }: {
213
+ type: string;
214
+ icon: typeof Image;
215
+ fileState: FileUploadState;
216
+ inputRef: React.RefObject<HTMLInputElement>;
217
+ onFileChange: (file: File | null) => void;
218
+ allowedTypes: string[];
219
+ label: string;
220
+ }) => (
221
+ <div className="group relative overflow-hidden rounded-xl shadow-lg bg-white/80 backdrop-blur-sm transition-all duration-300 hover:shadow-xl hover:scale-[1.02] border border-gray-100">
222
+ <input
223
+ ref={inputRef}
224
+ type="file"
225
+ accept={allowedTypes.join(",")}
226
+ onChange={(e) => {
227
+ try {
228
+ const file = e.target.files?.[0] || null;
229
+ onFileChange(file);
230
+ } catch (error: any) {
231
+ setError(error.message);
232
+ }
233
+ }}
234
+ className="hidden"
235
+ />
236
+
237
+ {!fileState.file ? (
238
+ <label
239
+ htmlFor={inputRef.current?.id}
240
+ onClick={() => inputRef.current?.click()}
241
+ className="flex cursor-pointer flex-col items-center justify-center p-10 bg-gradient-to-br from-gray-50 to-white transition-colors group-hover:from-blue-50 group-hover:to-purple-50"
242
+ >
243
+ <div className="transform transition-transform duration-300 group-hover:scale-110">
244
+ <Icon className="h-16 w-16 text-gray-400 group-hover:text-blue-500" />
245
+ </div>
246
+ <span className="mt-4 text-lg font-medium bg-gradient-to-r from-gray-600 to-gray-800 bg-clip-text text-transparent group-hover:from-blue-600 group-hover:to-purple-600">
247
+ {label}
248
+ </span>
249
+ <span className="mt-2 text-sm text-gray-400 group-hover:text-gray-500">
250
+ {allowedTypes.join(", ")}
251
+ </span>
252
+ </label>
253
+ ) : (
254
+ <div className="p-6 space-y-4">
255
+ <div className="relative aspect-video w-full overflow-hidden rounded-lg ring-1 ring-gray-100">
256
+ {type === "video" ? (
257
+ <video src={fileState.preview} controls className="h-full w-full object-cover">
258
+ Tu navegador no soporta la reproducción de videos.
259
+ </video>
260
+ ) : type === "image" ? (
261
+ <img src={fileState.preview} alt="Preview" className="h-full w-full object-cover" />
262
+ ) : (
263
+ <div className="flex h-full flex-col items-center justify-center space-y-3 bg-gradient-to-br from-blue-50 to-purple-50 p-4">
264
+ <div className="flex items-center justify-center rounded-full bg-gradient-to-r from-blue-400 to-purple-400 p-3">
265
+ <Upload className="h-6 w-6 text-white" />
266
+ </div>
267
+ <div className="text-center space-y-2">
268
+ <span className="block text-lg font-medium text-gray-600">
269
+ {fileState.file.name}
270
+ </span>
271
+ <span className="block text-sm text-gray-500">
272
+ Tamaño: {(fileState.file.size / 1024).toFixed(2)} KB
273
+ </span>
274
+ <span className="mt-1 block text-sm font-medium text-green-600">
275
+ ✓ Archivo AR cargado correctamente
276
+ </span>
277
+ </div>
278
+ </div>
279
+ )}
280
+ </div>
281
+ <div className="flex items-center justify-between">
282
+ <div className="flex items-center space-x-3">
283
+ <Icon className="h-5 w-5 text-blue-500" />
284
+ <span className="text-sm font-medium text-gray-600">{fileState.file.name}</span>
285
+ </div>
286
+ <button
287
+ onClick={() => onFileChange(null)}
288
+ className="rounded-full bg-gradient-to-r from-blue-500 to-purple-500 px-4 py-2 text-sm font-medium text-white shadow-md transition-all hover:from-blue-600 hover:to-purple-600 hover:shadow-lg active:scale-95"
289
+ >
290
+ Cambiar
291
+ </button>
292
+ </div>
293
+ </div>
294
+ )}
295
+ </div>
296
+ );
297
+
298
+ return (
299
+ <div className="min-h-screen w-full bg-gradient-to-br from-blue-50 via-white to-purple-50 p-4 md:p-8">
300
+ <div className="mx-auto max-w-3xl rounded-3xl bg-white/90 backdrop-blur-md p-6 md:p-10 shadow-2xl ring-1 ring-black/10">
301
+ <div className="flex flex-col items-center justify-center space-y-8">
302
+ <div className="rounded-2xl bg-gradient-to-br from-blue-500 to-purple-500 p-6 shadow-xl shadow-blue-300/30 hover:scale-105 transition-transform">
303
+ <Camera className="h-12 w-12 text-white" />
304
+ </div>
305
+ <h1 className="bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-5xl font-bold text-transparent text-center">
306
+ Editor de Experiencia AR
307
+ </h1>
308
+ <p className="text-2xl text-gray-600 text-center font-light">
309
+ Crea una experiencia de realidad aumentada única
310
+ </p>
311
+ </div>
312
+
313
+ <div className="mt-12 space-y-8">
314
+ <FileUploadSection
315
+ type="image"
316
+ icon={Image}
317
+ fileState={imageState}
318
+ inputRef={imageInputRef}
319
+ onFileChange={handleImageChange}
320
+ allowedTypes={ALLOWED_MIME_TYPES}
321
+ label="Haz clic para seleccionar una imagen"
322
+ />
323
+
324
+ <FileUploadSection
325
+ type="mind"
326
+ icon={Upload}
327
+ fileState={mindState}
328
+ inputRef={mindInputRef}
329
+ onFileChange={handleMindChange}
330
+ allowedTypes={[".mind"]}
331
+ label="Haz clic para seleccionar archivo .mind"
332
+ />
333
+
334
+ <FileUploadSection
335
+ type="video"
336
+ icon={Video}
337
+ fileState={videoState}
338
+ inputRef={videoInputRef}
339
+ onFileChange={handleVideoChange}
340
+ allowedTypes={ALLOWED_VIDEO_TYPES}
341
+ label="Haz clic para seleccionar un video"
342
+ />
343
+
344
+ <div className="space-y-4 rounded-2xl border border-gray-200/50 bg-white/90 backdrop-blur-md p-8 shadow-lg ring-1 ring-black/10">
345
+ <label className="flex items-center justify-between text-2xl font-semibold text-gray-800">
346
+ <span>Escala del Video</span>
347
+ <span className="bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent font-bold">
348
+ {videoScale}x
349
+ </span>
350
+ </label>
351
+ <div className="relative py-8">
352
+ <div className="absolute h-3 w-full rounded-full bg-gradient-to-r from-blue-400 to-purple-400 opacity-20"></div>
353
+ <div
354
+ className="absolute h-3 rounded-full bg-gradient-to-r from-blue-400 to-purple-400 shadow-lg"
355
+ style={{ width: `${(videoScale / 2) * 100}%` }}
356
+ ></div>
357
+ <input
358
+ type="range"
359
+ min="0.1"
360
+ max="2"
361
+ step="0.1"
362
+ value={videoScale}
363
+ onChange={(e) => setVideoScale(Number(e.target.value))}
364
+ className="relative h-3 w-full cursor-pointer appearance-none rounded-lg bg-transparent focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-offset-4"
365
+ style={{ WebkitAppearance: "none" }}
366
+ />
367
+ </div>
368
+ </div>
369
+ </div>
370
+
371
+ {error && (
372
+ <div className="mt-6 rounded-xl bg-red-50 p-4 text-red-700 shadow-sm ring-1 ring-red-100">
373
+ {error}
374
+ </div>
375
+ )}
376
+
377
+ <button
378
+ onClick={handleSave}
379
+ disabled={loading}
380
+ className="mt-10 w-full rounded-xl bg-gradient-to-r from-blue-600 to-purple-600 py-5 text-xl font-semibold text-white shadow-xl transition-all hover:from-blue-700 hover:to-purple-700 disabled:from-gray-400 disabled:to-gray-400 disabled:shadow-none focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-offset-4"
381
+ >
382
+ {loading ? (
383
+ <div className="flex items-center justify-center space-x-3">
384
+ <LoaderCircle className="h-7 w-7 animate-spin" />
385
+ <span>Guardando...</span>
386
+ </div>
387
+ ) : (
388
+ "Guardar"
389
+ )}
390
+ </button>
391
+ </div>
392
+ </div>
393
+ );
394
+ };