@primestyleai/tryon 5.8.53 → 5.8.55
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.
- package/dist/pose-detect.d.ts +9 -1
- package/dist/react/index.js +72 -44
- package/dist/storefront/primestyle-tryon.js +72 -44
- package/package.json +1 -1
package/dist/pose-detect.d.ts
CHANGED
|
@@ -67,7 +67,15 @@ export interface BodyLandmarks {
|
|
|
67
67
|
y: number;
|
|
68
68
|
};
|
|
69
69
|
}
|
|
70
|
+
/** Pixel dimensions of the image the landmarks were detected on. Sent to
|
|
71
|
+
* the backend alongside the landmarks so it can convert normalized x/y
|
|
72
|
+
* into pixels — without this, horizontal and vertical distances on a
|
|
73
|
+
* non-square image are skewed by the aspect ratio. */
|
|
74
|
+
export interface BodyLandmarksWithDims extends BodyLandmarks {
|
|
75
|
+
imageWidth: number;
|
|
76
|
+
imageHeight: number;
|
|
77
|
+
}
|
|
70
78
|
export declare function detectMeasurementLines(imageSrc: string): Promise<MeasurementLines | null>;
|
|
71
79
|
/** Detect full body landmarks for per-field measurement guides.
|
|
72
80
|
* Accepts a URL string OR an already-loaded HTMLImageElement to avoid CORS issues. */
|
|
73
|
-
export declare function detectBodyLandmarks(imageSrc: string | HTMLImageElement): Promise<
|
|
81
|
+
export declare function detectBodyLandmarks(imageSrc: string | HTMLImageElement): Promise<BodyLandmarksWithDims | null>;
|
package/dist/react/index.js
CHANGED
|
@@ -121,7 +121,9 @@ async function detectBodyLandmarks(imageSrc) {
|
|
|
121
121
|
rightKnee: { x: lm[RIGHT_KNEE].x, y: lm[RIGHT_KNEE].y },
|
|
122
122
|
leftAnkle: { x: lm[LEFT_ANKLE].x, y: lm[LEFT_ANKLE].y },
|
|
123
123
|
rightAnkle: { x: lm[RIGHT_ANKLE].x, y: lm[RIGHT_ANKLE].y },
|
|
124
|
-
nose: { x: lm[NOSE].x, y: lm[NOSE].y }
|
|
124
|
+
nose: { x: lm[NOSE].x, y: lm[NOSE].y },
|
|
125
|
+
imageWidth: img.naturalWidth || img.width,
|
|
126
|
+
imageHeight: img.naturalHeight || img.height
|
|
125
127
|
};
|
|
126
128
|
} catch (err) {
|
|
127
129
|
console.error("[PS-SDK] Body landmark detection failed:", err);
|
|
@@ -7760,36 +7762,57 @@ function FaceOverlay({
|
|
|
7760
7762
|
] }, key))
|
|
7761
7763
|
] });
|
|
7762
7764
|
}
|
|
7763
|
-
function
|
|
7765
|
+
function StageCycler({
|
|
7764
7766
|
category,
|
|
7765
7767
|
sizingDone,
|
|
7768
|
+
tryOnProcessing,
|
|
7769
|
+
tryOnDone,
|
|
7766
7770
|
t
|
|
7767
7771
|
}) {
|
|
7768
|
-
const
|
|
7772
|
+
const sizingStages = category === "head" ? [
|
|
7769
7773
|
{ title: t("DETECTING HEAD"), desc: t("Reading head landmarks from your photo.") },
|
|
7770
7774
|
{ title: t("MAPPING CIRCUMFERENCE"), desc: t("Estimating head width and depth.") },
|
|
7771
7775
|
{ title: t("MATCHING HAT SIZE"), desc: t("Comparing your circumference to the size chart.") },
|
|
7772
7776
|
{ title: t("FINALIZING RESULT"), desc: t("Almost done — preparing your recommendation.") }
|
|
7773
|
-
] : [
|
|
7777
|
+
] : category === "face" ? [
|
|
7774
7778
|
{ title: t("DETECTING FACE"), desc: t("Identifying 478 face landmarks in your photo.") },
|
|
7775
7779
|
{ title: t("CALIBRATING SCALE"), desc: t("Using iris size as the pixel-to-mm anchor.") },
|
|
7776
7780
|
{ title: t("MEASURING FRAME"), desc: t("Mapping bridge, lens width and temple length.") },
|
|
7777
7781
|
{ title: t("MATCHING FRAME SIZE"), desc: t("Comparing your measurements to the size chart.") },
|
|
7778
7782
|
{ title: t("FINALIZING RESULT"), desc: t("Almost done — preparing your recommendation.") }
|
|
7783
|
+
] : [
|
|
7784
|
+
// Body + foot fall through here — broadest set of stages so long
|
|
7785
|
+
// Gemini estimates still have fresh text to cycle through.
|
|
7786
|
+
{ title: t("DETECTING POSE"), desc: t("Identifying body landmarks from your photo.") },
|
|
7787
|
+
{ title: t("SCANNING FRAME"), desc: t("Our AI is mapping your proportions.") },
|
|
7788
|
+
{ title: t("ANALYZING BODY"), desc: t("Measuring shoulders, chest, waist and hips.") },
|
|
7789
|
+
{ title: t("MATCHING SIZE"), desc: t("Comparing your measurements to the size guide.") },
|
|
7790
|
+
{ title: t("FINALIZING RESULT"), desc: t("Almost done — preparing your recommendation.") }
|
|
7791
|
+
];
|
|
7792
|
+
const tryOnStages = [
|
|
7793
|
+
{ title: t("GENERATING TRY-ON"), desc: t("Rendering the garment on your photo.") },
|
|
7794
|
+
{ title: t("REFINING DETAILS"), desc: t("Fine-tuning fit, drape and shadows.") },
|
|
7795
|
+
{ title: t("ALMOST THERE"), desc: t("Final compositing in progress.") },
|
|
7796
|
+
{ title: t("FINISHING TOUCHES"), desc: t("Polishing the result.") }
|
|
7779
7797
|
];
|
|
7798
|
+
const active = tryOnProcessing ? tryOnStages : sizingStages;
|
|
7799
|
+
const isDone = tryOnProcessing ? !!tryOnDone : sizingDone;
|
|
7780
7800
|
const [idx, setIdx] = useState(0);
|
|
7781
7801
|
useEffect(() => {
|
|
7782
|
-
|
|
7802
|
+
setIdx(0);
|
|
7803
|
+
}, [tryOnProcessing]);
|
|
7804
|
+
useEffect(() => {
|
|
7805
|
+
if (isDone) return;
|
|
7783
7806
|
const id = setInterval(() => {
|
|
7784
|
-
setIdx((i) => Math.min(i + 1,
|
|
7807
|
+
setIdx((i) => Math.min(i + 1, active.length - 1));
|
|
7785
7808
|
}, 900);
|
|
7786
7809
|
return () => clearInterval(id);
|
|
7787
|
-
}, [
|
|
7788
|
-
const current =
|
|
7810
|
+
}, [isDone, active.length]);
|
|
7811
|
+
const current = active[idx] ?? active[0];
|
|
7789
7812
|
return /* @__PURE__ */ jsx("div", { className: "ps-msc-stage", style: { alignSelf: "center", marginTop: "auto", marginBottom: "auto" }, children: /* @__PURE__ */ jsxs("div", { className: "ps-msc-stage-slot", children: [
|
|
7790
7813
|
/* @__PURE__ */ jsx("div", { className: "ps-msc-stage-title", children: current.title }),
|
|
7791
7814
|
/* @__PURE__ */ jsx("div", { className: "ps-msc-stage-desc", children: current.desc })
|
|
7792
|
-
] }, idx) });
|
|
7815
|
+
] }, `${tryOnProcessing ? "t" : "s"}-${idx}`) });
|
|
7793
7816
|
}
|
|
7794
7817
|
function SkeletonOverlay({ landmarks, imgWidth, imgHeight }) {
|
|
7795
7818
|
const W = imgWidth;
|
|
@@ -8025,7 +8048,8 @@ function SectionDetailView({
|
|
|
8025
8048
|
tryOnProcessing,
|
|
8026
8049
|
backLabel,
|
|
8027
8050
|
internationalSizes,
|
|
8028
|
-
continueLabel
|
|
8051
|
+
continueLabel,
|
|
8052
|
+
renderRaw = false
|
|
8029
8053
|
}) {
|
|
8030
8054
|
const recSize = sectionResult?.recommendedSize || "";
|
|
8031
8055
|
const [selectedSize, setSelectedSize] = useState(null);
|
|
@@ -8143,6 +8167,18 @@ function SectionDetailView({
|
|
|
8143
8167
|
return { range: val, ...parsed };
|
|
8144
8168
|
}, [section, sizeColIdx, sizeHeader, unitLbl, columnUnits]);
|
|
8145
8169
|
const fitRows = useMemo(() => {
|
|
8170
|
+
if (renderRaw) {
|
|
8171
|
+
const raw = sectionResult?.matchDetails || [];
|
|
8172
|
+
return raw.map((m) => ({
|
|
8173
|
+
area: m.measurement.replace(/\s*\(.*?\)\s*$/, "").trim() || m.measurement,
|
|
8174
|
+
rawUserValue: m.userValue,
|
|
8175
|
+
rawChartRange: m.chartRange,
|
|
8176
|
+
fit: m.fit,
|
|
8177
|
+
userNum: 0,
|
|
8178
|
+
chartLabel: "",
|
|
8179
|
+
isLength: false
|
|
8180
|
+
}));
|
|
8181
|
+
}
|
|
8146
8182
|
const mainDetails = sectionResult?.matchDetails || [];
|
|
8147
8183
|
const lengthDetails = lengthEntry?.secResult?.matchDetails || [];
|
|
8148
8184
|
const details = [...mainDetails, ...lengthDetails];
|
|
@@ -8212,11 +8248,12 @@ function SectionDetailView({
|
|
|
8212
8248
|
}
|
|
8213
8249
|
return { area: m.measurement, userNum, chartLabel: cleanNumFn(chartLabel), fit, isLength: false };
|
|
8214
8250
|
});
|
|
8215
|
-
}, [sectionResult, lengthEntry, userMeasurements, displaySize, recSize, chartRangeFor, selectedLength, recLength]);
|
|
8251
|
+
}, [sectionResult, lengthEntry, userMeasurements, displaySize, recSize, chartRangeFor, selectedLength, recLength, renderRaw]);
|
|
8216
8252
|
const goodCount = fitRows.filter(
|
|
8217
8253
|
(r) => r.fit === "good" || r.fit === "a-bit-tight" || r.fit === "a-bit-loose"
|
|
8218
8254
|
).length;
|
|
8219
8255
|
const matchPercent = fitRows.length > 0 ? Math.round(goodCount / fitRows.length * 100) : 0;
|
|
8256
|
+
const showMatchPercent = !renderRaw;
|
|
8220
8257
|
const secAny = sectionResult;
|
|
8221
8258
|
const backendSize = secAny?.size || recSize;
|
|
8222
8259
|
const backendLength = secAny?.length || recLength;
|
|
@@ -8343,7 +8380,10 @@ function SectionDetailView({
|
|
|
8343
8380
|
borderRadius: "8px",
|
|
8344
8381
|
padding: "4px 12px"
|
|
8345
8382
|
}, children: [
|
|
8346
|
-
/* @__PURE__ */
|
|
8383
|
+
/* @__PURE__ */ jsxs("span", { className: "ps-msd-card-size", children: [
|
|
8384
|
+
displaySizeLabel,
|
|
8385
|
+
!selectedCountry && finalDisplayLength ? ` / ${finalDisplayLength}` : ""
|
|
8386
|
+
] }),
|
|
8347
8387
|
finalDisplayLength && /* @__PURE__ */ jsx("span", { className: "ps-msd-card-size-meta", children: finalDisplayLength }),
|
|
8348
8388
|
selectedCountry && isRecommended && /* @__PURE__ */ jsxs("span", { className: "ps-msd-card-size-meta", style: { fontSize: "11px", opacity: 0.7 }, children: [
|
|
8349
8389
|
"(",
|
|
@@ -8380,7 +8420,7 @@ function SectionDetailView({
|
|
|
8380
8420
|
/* @__PURE__ */ jsxs("div", { className: "ps-msd-row-cells", children: [
|
|
8381
8421
|
/* @__PURE__ */ jsxs("div", { className: "ps-msd-row-cell", children: [
|
|
8382
8422
|
/* @__PURE__ */ jsx("span", { className: "ps-msd-cell-label", children: t("USER") }),
|
|
8383
|
-
/* @__PURE__ */ jsx("span", { className: "ps-msd-cell-value", children: isNaN(row.userNum) || row.userNum === 0 ? "—" : `${dNum(row.userNum)} ${unitLbl}` })
|
|
8423
|
+
/* @__PURE__ */ jsx("span", { className: "ps-msd-cell-value", children: renderRaw ? row.rawUserValue || "—" : isNaN(row.userNum) || row.userNum === 0 ? "—" : `${dNum(row.userNum)} ${unitLbl}` })
|
|
8384
8424
|
] }),
|
|
8385
8425
|
/* @__PURE__ */ jsxs("div", { className: "ps-msd-row-cell ps-right", children: [
|
|
8386
8426
|
/* @__PURE__ */ jsxs("span", { className: "ps-msd-cell-label", children: [
|
|
@@ -8388,7 +8428,7 @@ function SectionDetailView({
|
|
|
8388
8428
|
" ",
|
|
8389
8429
|
displaySize
|
|
8390
8430
|
] }),
|
|
8391
|
-
/* @__PURE__ */ jsx("span", { className: "ps-msd-cell-value", children: dLabel(row.chartLabel) })
|
|
8431
|
+
/* @__PURE__ */ jsx("span", { className: "ps-msd-cell-value", children: renderRaw ? row.rawChartRange || "—" : dLabel(row.chartLabel) })
|
|
8392
8432
|
] })
|
|
8393
8433
|
] }),
|
|
8394
8434
|
/* @__PURE__ */ jsxs("div", { className: `ps-msd-row-badge ${fitClass}`, children: [
|
|
@@ -8487,7 +8527,7 @@ function SectionDetailView({
|
|
|
8487
8527
|
] })
|
|
8488
8528
|
] })
|
|
8489
8529
|
] }),
|
|
8490
|
-
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.4vw", marginBottom: "1.2vw" }, children: [
|
|
8530
|
+
showMatchPercent && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.4vw", marginBottom: "1.2vw" }, children: [
|
|
8491
8531
|
/* @__PURE__ */ jsxs("svg", { width: "1vw", height: "1vw", viewBox: "0 0 16 16", fill: "none", children: [
|
|
8492
8532
|
/* @__PURE__ */ jsx("circle", { cx: "8", cy: "8", r: "8", fill: "var(--ps-accent)" }),
|
|
8493
8533
|
/* @__PURE__ */ jsx("path", { d: "M4.5 8L7 10.5L11.5 5.5", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
|
|
@@ -8510,8 +8550,8 @@ function SectionDetailView({
|
|
|
8510
8550
|
const fitBg = row.fit === "good" ? "rgba(33,84,239,0.08)" : row.fit.includes("tight") ? "rgba(220,38,38,0.08)" : "rgba(217,119,6,0.08)";
|
|
8511
8551
|
return /* @__PURE__ */ jsxs("tr", { style: { borderBottom: i < fitRows.length - 1 ? "1px solid rgba(0,0,0,0.04)" : "none" }, children: [
|
|
8512
8552
|
/* @__PURE__ */ jsx("td", { style: { padding: "0.55vw 0.6vw", fontSize: "0.75vw", fontWeight: 500, color: "var(--ps-text-primary)" }, children: row.area }),
|
|
8513
|
-
/* @__PURE__ */ jsx("td", { style: { padding: "0.55vw 0.6vw", fontSize: "0.75vw", color: "var(--ps-text-secondary)" }, children: isNaN(row.userNum) || row.userNum === 0 ? "—" : `${dNum(row.userNum)} ${unitLbl}` }),
|
|
8514
|
-
/* @__PURE__ */ jsx("td", { style: { padding: "0.55vw 0.6vw", fontSize: "0.75vw", color: "var(--ps-text-secondary)" }, children: dLabel(row.chartLabel) }),
|
|
8553
|
+
/* @__PURE__ */ jsx("td", { style: { padding: "0.55vw 0.6vw", fontSize: "0.75vw", color: "var(--ps-text-secondary)" }, children: renderRaw ? row.rawUserValue || "—" : isNaN(row.userNum) || row.userNum === 0 ? "—" : `${dNum(row.userNum)} ${unitLbl}` }),
|
|
8554
|
+
/* @__PURE__ */ jsx("td", { style: { padding: "0.55vw 0.6vw", fontSize: "0.75vw", color: "var(--ps-text-secondary)" }, children: renderRaw ? row.rawChartRange || "—" : dLabel(row.chartLabel) }),
|
|
8515
8555
|
/* @__PURE__ */ jsx("td", { style: { padding: "0.55vw 0.6vw", textAlign: "right" }, children: /* @__PURE__ */ jsx("span", { style: { fontSize: "0.6vw", fontWeight: 600, color: fitColor, background: fitBg, borderRadius: "1vw", padding: "0.15vw 0.5vw", whiteSpace: "nowrap" }, children: row.isLength ? lengthFitLabelFn(row.fit, t) : fitLabelFn(row.fit, t) }) })
|
|
8516
8556
|
] }, i);
|
|
8517
8557
|
}) })
|
|
@@ -8776,7 +8816,6 @@ function SizeResultView({
|
|
|
8776
8816
|
const [poseLines, setPoseLines] = useState(null);
|
|
8777
8817
|
const [poseReady, setPoseReady] = useState(false);
|
|
8778
8818
|
const [imgDims, setImgDims] = useState({ w: 800, h: 1200 });
|
|
8779
|
-
const analyzingDone = estimationDone;
|
|
8780
8819
|
const handleImgLoad = useCallback((e) => {
|
|
8781
8820
|
const el = e.currentTarget;
|
|
8782
8821
|
if (el.naturalWidth && el.naturalHeight) {
|
|
@@ -8958,31 +8997,17 @@ function SizeResultView({
|
|
|
8958
8997
|
] }),
|
|
8959
8998
|
(() => {
|
|
8960
8999
|
const isFaceCategory = measurementType === "face" || measurementType === "head";
|
|
8961
|
-
|
|
8962
|
-
|
|
8963
|
-
|
|
8964
|
-
|
|
8965
|
-
|
|
8966
|
-
|
|
8967
|
-
|
|
8968
|
-
|
|
8969
|
-
|
|
8970
|
-
|
|
8971
|
-
|
|
8972
|
-
/* @__PURE__ */ jsxs("div", { className: `ps-tryon-snap-step${analyzingDone ? " ps-done" : detectionDone ? " ps-active" : ""}`, children: [
|
|
8973
|
-
/* @__PURE__ */ jsx("div", { className: "ps-tryon-snap-step-icon", children: !detectionDone ? /* @__PURE__ */ jsx("span", { className: "ps-tryon-snap-num", children: "2" }) : !analyzingDone ? /* @__PURE__ */ jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) : /* @__PURE__ */ jsx("span", { className: "ps-tryon-snap-check", children: "✓" }) }),
|
|
8974
|
-
/* @__PURE__ */ jsx("span", { children: t("Analyzing your size") })
|
|
8975
|
-
] }),
|
|
8976
|
-
/* @__PURE__ */ jsxs("div", { className: `ps-tryon-snap-step${analyzingDone ? " ps-active" : ""}`, children: [
|
|
8977
|
-
/* @__PURE__ */ jsx("div", { className: "ps-tryon-snap-step-icon", children: !analyzingDone ? /* @__PURE__ */ jsx("span", { className: "ps-tryon-snap-num", children: "3" }) : /* @__PURE__ */ jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) }),
|
|
8978
|
-
/* @__PURE__ */ jsx("span", { children: t("Finding best fit for you") })
|
|
8979
|
-
] })
|
|
8980
|
-
] }),
|
|
8981
|
-
tryOnProcessing && /* @__PURE__ */ jsxs("div", { className: `ps-tryon-snap-step${tryOnDone ? " ps-done" : " ps-active"}`, children: [
|
|
8982
|
-
/* @__PURE__ */ jsx("div", { className: "ps-tryon-snap-step-icon", children: tryOnDone ? /* @__PURE__ */ jsx("span", { className: "ps-tryon-snap-check", children: "✓" }) : /* @__PURE__ */ jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) }),
|
|
8983
|
-
/* @__PURE__ */ jsx("span", { children: t("Generating virtual try-on") })
|
|
8984
|
-
] })
|
|
8985
|
-
] });
|
|
9000
|
+
isFaceCategory ? measurementType === "head" ? t("Detecting head") : t("Detecting face") : t("Detecting body pose");
|
|
9001
|
+
return /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-right-col", style: { display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsx(
|
|
9002
|
+
StageCycler,
|
|
9003
|
+
{
|
|
9004
|
+
category: isFaceCategory ? measurementType : "body",
|
|
9005
|
+
sizingDone,
|
|
9006
|
+
tryOnProcessing,
|
|
9007
|
+
tryOnDone,
|
|
9008
|
+
t
|
|
9009
|
+
}
|
|
9010
|
+
) });
|
|
8986
9011
|
})()
|
|
8987
9012
|
] }),
|
|
8988
9013
|
(allDone || sizingResult && !isSnapProcessing) && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -9255,6 +9280,7 @@ function SizeResultView({
|
|
|
9255
9280
|
productImage: resultImageUrl || productImage,
|
|
9256
9281
|
productTitle,
|
|
9257
9282
|
isMobile: true,
|
|
9283
|
+
renderRaw: isAccessory,
|
|
9258
9284
|
isTryOnImage: !!resultImageUrl,
|
|
9259
9285
|
showLines,
|
|
9260
9286
|
onToggleLines: () => setShowLines(!showLines),
|
|
@@ -9298,7 +9324,8 @@ function SizeResultView({
|
|
|
9298
9324
|
onTryOn: resultImageUrl || isAccessory ? void 0 : handleSingleTryOn,
|
|
9299
9325
|
continueLabel: resultImageUrl ? t("Continue Shopping") : void 0,
|
|
9300
9326
|
tryOnProcessing,
|
|
9301
|
-
t
|
|
9327
|
+
t,
|
|
9328
|
+
renderRaw: isAccessory
|
|
9302
9329
|
}
|
|
9303
9330
|
) }, "panel-single")
|
|
9304
9331
|
] });
|
|
@@ -13030,6 +13057,7 @@ function FootSizeView(props) {
|
|
|
13030
13057
|
{
|
|
13031
13058
|
title: "Shoe Size",
|
|
13032
13059
|
fields,
|
|
13060
|
+
disablePhotoUpload: true,
|
|
13033
13061
|
...rest
|
|
13034
13062
|
}
|
|
13035
13063
|
);
|
|
@@ -9583,7 +9583,9 @@ async function detectBodyLandmarks(imageSrc) {
|
|
|
9583
9583
|
rightKnee: { x: lm[RIGHT_KNEE].x, y: lm[RIGHT_KNEE].y },
|
|
9584
9584
|
leftAnkle: { x: lm[LEFT_ANKLE].x, y: lm[LEFT_ANKLE].y },
|
|
9585
9585
|
rightAnkle: { x: lm[RIGHT_ANKLE].x, y: lm[RIGHT_ANKLE].y },
|
|
9586
|
-
nose: { x: lm[NOSE].x, y: lm[NOSE].y }
|
|
9586
|
+
nose: { x: lm[NOSE].x, y: lm[NOSE].y },
|
|
9587
|
+
imageWidth: img.naturalWidth || img.width,
|
|
9588
|
+
imageHeight: img.naturalHeight || img.height
|
|
9587
9589
|
};
|
|
9588
9590
|
} catch (err) {
|
|
9589
9591
|
console.error("[PS-SDK] Body landmark detection failed:", err);
|
|
@@ -17184,36 +17186,57 @@ function FaceOverlay({
|
|
|
17184
17186
|
] }, key))
|
|
17185
17187
|
] });
|
|
17186
17188
|
}
|
|
17187
|
-
function
|
|
17189
|
+
function StageCycler({
|
|
17188
17190
|
category,
|
|
17189
17191
|
sizingDone,
|
|
17192
|
+
tryOnProcessing,
|
|
17193
|
+
tryOnDone,
|
|
17190
17194
|
t: t2
|
|
17191
17195
|
}) {
|
|
17192
|
-
const
|
|
17196
|
+
const sizingStages = category === "head" ? [
|
|
17193
17197
|
{ title: t2("DETECTING HEAD"), desc: t2("Reading head landmarks from your photo.") },
|
|
17194
17198
|
{ title: t2("MAPPING CIRCUMFERENCE"), desc: t2("Estimating head width and depth.") },
|
|
17195
17199
|
{ title: t2("MATCHING HAT SIZE"), desc: t2("Comparing your circumference to the size chart.") },
|
|
17196
17200
|
{ title: t2("FINALIZING RESULT"), desc: t2("Almost done — preparing your recommendation.") }
|
|
17197
|
-
] : [
|
|
17201
|
+
] : category === "face" ? [
|
|
17198
17202
|
{ title: t2("DETECTING FACE"), desc: t2("Identifying 478 face landmarks in your photo.") },
|
|
17199
17203
|
{ title: t2("CALIBRATING SCALE"), desc: t2("Using iris size as the pixel-to-mm anchor.") },
|
|
17200
17204
|
{ title: t2("MEASURING FRAME"), desc: t2("Mapping bridge, lens width and temple length.") },
|
|
17201
17205
|
{ title: t2("MATCHING FRAME SIZE"), desc: t2("Comparing your measurements to the size chart.") },
|
|
17202
17206
|
{ title: t2("FINALIZING RESULT"), desc: t2("Almost done — preparing your recommendation.") }
|
|
17207
|
+
] : [
|
|
17208
|
+
// Body + foot fall through here — broadest set of stages so long
|
|
17209
|
+
// Gemini estimates still have fresh text to cycle through.
|
|
17210
|
+
{ title: t2("DETECTING POSE"), desc: t2("Identifying body landmarks from your photo.") },
|
|
17211
|
+
{ title: t2("SCANNING FRAME"), desc: t2("Our AI is mapping your proportions.") },
|
|
17212
|
+
{ title: t2("ANALYZING BODY"), desc: t2("Measuring shoulders, chest, waist and hips.") },
|
|
17213
|
+
{ title: t2("MATCHING SIZE"), desc: t2("Comparing your measurements to the size guide.") },
|
|
17214
|
+
{ title: t2("FINALIZING RESULT"), desc: t2("Almost done — preparing your recommendation.") }
|
|
17215
|
+
];
|
|
17216
|
+
const tryOnStages = [
|
|
17217
|
+
{ title: t2("GENERATING TRY-ON"), desc: t2("Rendering the garment on your photo.") },
|
|
17218
|
+
{ title: t2("REFINING DETAILS"), desc: t2("Fine-tuning fit, drape and shadows.") },
|
|
17219
|
+
{ title: t2("ALMOST THERE"), desc: t2("Final compositing in progress.") },
|
|
17220
|
+
{ title: t2("FINISHING TOUCHES"), desc: t2("Polishing the result.") }
|
|
17203
17221
|
];
|
|
17222
|
+
const active = tryOnProcessing ? tryOnStages : sizingStages;
|
|
17223
|
+
const isDone = tryOnProcessing ? !!tryOnDone : sizingDone;
|
|
17204
17224
|
const [idx, setIdx] = reactExports.useState(0);
|
|
17205
17225
|
reactExports.useEffect(() => {
|
|
17206
|
-
|
|
17226
|
+
setIdx(0);
|
|
17227
|
+
}, [tryOnProcessing]);
|
|
17228
|
+
reactExports.useEffect(() => {
|
|
17229
|
+
if (isDone) return;
|
|
17207
17230
|
const id2 = setInterval(() => {
|
|
17208
|
-
setIdx((i) => Math.min(i + 1,
|
|
17231
|
+
setIdx((i) => Math.min(i + 1, active.length - 1));
|
|
17209
17232
|
}, 900);
|
|
17210
17233
|
return () => clearInterval(id2);
|
|
17211
|
-
}, [
|
|
17212
|
-
const current =
|
|
17234
|
+
}, [isDone, active.length]);
|
|
17235
|
+
const current = active[idx] ?? active[0];
|
|
17213
17236
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-msc-stage", style: { alignSelf: "center", marginTop: "auto", marginBottom: "auto" }, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-msc-stage-slot", children: [
|
|
17214
17237
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-msc-stage-title", children: current.title }),
|
|
17215
17238
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-msc-stage-desc", children: current.desc })
|
|
17216
|
-
] }, idx) });
|
|
17239
|
+
] }, `${tryOnProcessing ? "t" : "s"}-${idx}`) });
|
|
17217
17240
|
}
|
|
17218
17241
|
function SkeletonOverlay({ landmarks, imgWidth, imgHeight }) {
|
|
17219
17242
|
const W2 = imgWidth;
|
|
@@ -17449,7 +17472,8 @@ function SectionDetailView({
|
|
|
17449
17472
|
tryOnProcessing,
|
|
17450
17473
|
backLabel,
|
|
17451
17474
|
internationalSizes,
|
|
17452
|
-
continueLabel
|
|
17475
|
+
continueLabel,
|
|
17476
|
+
renderRaw = false
|
|
17453
17477
|
}) {
|
|
17454
17478
|
const recSize = sectionResult?.recommendedSize || "";
|
|
17455
17479
|
const [selectedSize, setSelectedSize] = reactExports.useState(null);
|
|
@@ -17567,6 +17591,18 @@ function SectionDetailView({
|
|
|
17567
17591
|
return { range: val, ...parsed };
|
|
17568
17592
|
}, [section, sizeColIdx, sizeHeader, unitLbl, columnUnits]);
|
|
17569
17593
|
const fitRows = reactExports.useMemo(() => {
|
|
17594
|
+
if (renderRaw) {
|
|
17595
|
+
const raw = sectionResult?.matchDetails || [];
|
|
17596
|
+
return raw.map((m2) => ({
|
|
17597
|
+
area: m2.measurement.replace(/\s*\(.*?\)\s*$/, "").trim() || m2.measurement,
|
|
17598
|
+
rawUserValue: m2.userValue,
|
|
17599
|
+
rawChartRange: m2.chartRange,
|
|
17600
|
+
fit: m2.fit,
|
|
17601
|
+
userNum: 0,
|
|
17602
|
+
chartLabel: "",
|
|
17603
|
+
isLength: false
|
|
17604
|
+
}));
|
|
17605
|
+
}
|
|
17570
17606
|
const mainDetails = sectionResult?.matchDetails || [];
|
|
17571
17607
|
const lengthDetails = lengthEntry?.secResult?.matchDetails || [];
|
|
17572
17608
|
const details = [...mainDetails, ...lengthDetails];
|
|
@@ -17636,11 +17672,12 @@ function SectionDetailView({
|
|
|
17636
17672
|
}
|
|
17637
17673
|
return { area: m2.measurement, userNum, chartLabel: cleanNumFn(chartLabel), fit, isLength: false };
|
|
17638
17674
|
});
|
|
17639
|
-
}, [sectionResult, lengthEntry, userMeasurements, displaySize, recSize, chartRangeFor, selectedLength, recLength]);
|
|
17675
|
+
}, [sectionResult, lengthEntry, userMeasurements, displaySize, recSize, chartRangeFor, selectedLength, recLength, renderRaw]);
|
|
17640
17676
|
const goodCount = fitRows.filter(
|
|
17641
17677
|
(r2) => r2.fit === "good" || r2.fit === "a-bit-tight" || r2.fit === "a-bit-loose"
|
|
17642
17678
|
).length;
|
|
17643
17679
|
const matchPercent = fitRows.length > 0 ? Math.round(goodCount / fitRows.length * 100) : 0;
|
|
17680
|
+
const showMatchPercent = !renderRaw;
|
|
17644
17681
|
const secAny = sectionResult;
|
|
17645
17682
|
const backendSize = secAny?.size || recSize;
|
|
17646
17683
|
const backendLength = secAny?.length || recLength;
|
|
@@ -17767,7 +17804,10 @@ function SectionDetailView({
|
|
|
17767
17804
|
borderRadius: "8px",
|
|
17768
17805
|
padding: "4px 12px"
|
|
17769
17806
|
}, children: [
|
|
17770
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
17807
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-msd-card-size", children: [
|
|
17808
|
+
displaySizeLabel,
|
|
17809
|
+
!selectedCountry && finalDisplayLength ? ` / ${finalDisplayLength}` : ""
|
|
17810
|
+
] }),
|
|
17771
17811
|
finalDisplayLength && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-msd-card-size-meta", children: finalDisplayLength }),
|
|
17772
17812
|
selectedCountry && isRecommended && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-msd-card-size-meta", style: { fontSize: "11px", opacity: 0.7 }, children: [
|
|
17773
17813
|
"(",
|
|
@@ -17804,7 +17844,7 @@ function SectionDetailView({
|
|
|
17804
17844
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-msd-row-cells", children: [
|
|
17805
17845
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-msd-row-cell", children: [
|
|
17806
17846
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-msd-cell-label", children: t2("USER") }),
|
|
17807
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-msd-cell-value", children: isNaN(row.userNum) || row.userNum === 0 ? "—" : `${dNum(row.userNum)} ${unitLbl}` })
|
|
17847
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-msd-cell-value", children: renderRaw ? row.rawUserValue || "—" : isNaN(row.userNum) || row.userNum === 0 ? "—" : `${dNum(row.userNum)} ${unitLbl}` })
|
|
17808
17848
|
] }),
|
|
17809
17849
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-msd-row-cell ps-right", children: [
|
|
17810
17850
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-msd-cell-label", children: [
|
|
@@ -17812,7 +17852,7 @@ function SectionDetailView({
|
|
|
17812
17852
|
" ",
|
|
17813
17853
|
displaySize
|
|
17814
17854
|
] }),
|
|
17815
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-msd-cell-value", children: dLabel(row.chartLabel) })
|
|
17855
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-msd-cell-value", children: renderRaw ? row.rawChartRange || "—" : dLabel(row.chartLabel) })
|
|
17816
17856
|
] })
|
|
17817
17857
|
] }),
|
|
17818
17858
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-msd-row-badge ${fitClass}`, children: [
|
|
@@ -17911,7 +17951,7 @@ function SectionDetailView({
|
|
|
17911
17951
|
] })
|
|
17912
17952
|
] })
|
|
17913
17953
|
] }),
|
|
17914
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.4vw", marginBottom: "1.2vw" }, children: [
|
|
17954
|
+
showMatchPercent && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.4vw", marginBottom: "1.2vw" }, children: [
|
|
17915
17955
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "1vw", height: "1vw", viewBox: "0 0 16 16", fill: "none", children: [
|
|
17916
17956
|
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "8", cy: "8", r: "8", fill: "var(--ps-accent)" }),
|
|
17917
17957
|
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M4.5 8L7 10.5L11.5 5.5", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
|
|
@@ -17934,8 +17974,8 @@ function SectionDetailView({
|
|
|
17934
17974
|
const fitBg = row.fit === "good" ? "rgba(33,84,239,0.08)" : row.fit.includes("tight") ? "rgba(220,38,38,0.08)" : "rgba(217,119,6,0.08)";
|
|
17935
17975
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { style: { borderBottom: i < fitRows.length - 1 ? "1px solid rgba(0,0,0,0.04)" : "none" }, children: [
|
|
17936
17976
|
/* @__PURE__ */ jsxRuntimeExports.jsx("td", { style: { padding: "0.55vw 0.6vw", fontSize: "0.75vw", fontWeight: 500, color: "var(--ps-text-primary)" }, children: row.area }),
|
|
17937
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("td", { style: { padding: "0.55vw 0.6vw", fontSize: "0.75vw", color: "var(--ps-text-secondary)" }, children: isNaN(row.userNum) || row.userNum === 0 ? "—" : `${dNum(row.userNum)} ${unitLbl}` }),
|
|
17938
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("td", { style: { padding: "0.55vw 0.6vw", fontSize: "0.75vw", color: "var(--ps-text-secondary)" }, children: dLabel(row.chartLabel) }),
|
|
17977
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("td", { style: { padding: "0.55vw 0.6vw", fontSize: "0.75vw", color: "var(--ps-text-secondary)" }, children: renderRaw ? row.rawUserValue || "—" : isNaN(row.userNum) || row.userNum === 0 ? "—" : `${dNum(row.userNum)} ${unitLbl}` }),
|
|
17978
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("td", { style: { padding: "0.55vw 0.6vw", fontSize: "0.75vw", color: "var(--ps-text-secondary)" }, children: renderRaw ? row.rawChartRange || "—" : dLabel(row.chartLabel) }),
|
|
17939
17979
|
/* @__PURE__ */ jsxRuntimeExports.jsx("td", { style: { padding: "0.55vw 0.6vw", textAlign: "right" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { fontSize: "0.6vw", fontWeight: 600, color: fitColor, background: fitBg, borderRadius: "1vw", padding: "0.15vw 0.5vw", whiteSpace: "nowrap" }, children: row.isLength ? lengthFitLabelFn(row.fit, t2) : fitLabelFn(row.fit, t2) }) })
|
|
17940
17980
|
] }, i);
|
|
17941
17981
|
}) })
|
|
@@ -18200,7 +18240,6 @@ function SizeResultView({
|
|
|
18200
18240
|
const [poseLines, setPoseLines] = reactExports.useState(null);
|
|
18201
18241
|
const [poseReady, setPoseReady] = reactExports.useState(false);
|
|
18202
18242
|
const [imgDims, setImgDims] = reactExports.useState({ w: 800, h: 1200 });
|
|
18203
|
-
const analyzingDone = estimationDone;
|
|
18204
18243
|
const handleImgLoad = reactExports.useCallback((e) => {
|
|
18205
18244
|
const el2 = e.currentTarget;
|
|
18206
18245
|
if (el2.naturalWidth && el2.naturalHeight) {
|
|
@@ -18382,31 +18421,17 @@ function SizeResultView({
|
|
|
18382
18421
|
] }),
|
|
18383
18422
|
(() => {
|
|
18384
18423
|
const isFaceCategory = measurementType === "face" || measurementType === "head";
|
|
18385
|
-
|
|
18386
|
-
|
|
18387
|
-
|
|
18388
|
-
|
|
18389
|
-
|
|
18390
|
-
|
|
18391
|
-
|
|
18392
|
-
|
|
18393
|
-
|
|
18394
|
-
|
|
18395
|
-
|
|
18396
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-tryon-snap-step${analyzingDone ? " ps-done" : detectionDone ? " ps-active" : ""}`, children: [
|
|
18397
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-snap-step-icon", children: !detectionDone ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-snap-num", children: "2" }) : !analyzingDone ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-snap-check", children: "✓" }) }),
|
|
18398
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t2("Analyzing your size") })
|
|
18399
|
-
] }),
|
|
18400
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-tryon-snap-step${analyzingDone ? " ps-active" : ""}`, children: [
|
|
18401
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-snap-step-icon", children: !analyzingDone ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-snap-num", children: "3" }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) }),
|
|
18402
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t2("Finding best fit for you") })
|
|
18403
|
-
] })
|
|
18404
|
-
] }),
|
|
18405
|
-
tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-tryon-snap-step${tryOnDone ? " ps-done" : " ps-active"}`, children: [
|
|
18406
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-snap-step-icon", children: tryOnDone ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-snap-check", children: "✓" }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) }),
|
|
18407
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t2("Generating virtual try-on") })
|
|
18408
|
-
] })
|
|
18409
|
-
] });
|
|
18424
|
+
isFaceCategory ? measurementType === "head" ? t2("Detecting head") : t2("Detecting face") : t2("Detecting body pose");
|
|
18425
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr-right-col", style: { display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
18426
|
+
StageCycler,
|
|
18427
|
+
{
|
|
18428
|
+
category: isFaceCategory ? measurementType : "body",
|
|
18429
|
+
sizingDone,
|
|
18430
|
+
tryOnProcessing,
|
|
18431
|
+
tryOnDone,
|
|
18432
|
+
t: t2
|
|
18433
|
+
}
|
|
18434
|
+
) });
|
|
18410
18435
|
})()
|
|
18411
18436
|
] }),
|
|
18412
18437
|
(allDone || sizingResult && !isSnapProcessing) && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
@@ -18679,6 +18704,7 @@ function SizeResultView({
|
|
|
18679
18704
|
productImage: resultImageUrl || productImage,
|
|
18680
18705
|
productTitle,
|
|
18681
18706
|
isMobile: true,
|
|
18707
|
+
renderRaw: isAccessory,
|
|
18682
18708
|
isTryOnImage: !!resultImageUrl,
|
|
18683
18709
|
showLines,
|
|
18684
18710
|
onToggleLines: () => setShowLines(!showLines),
|
|
@@ -18722,7 +18748,8 @@ function SizeResultView({
|
|
|
18722
18748
|
onTryOn: resultImageUrl || isAccessory ? void 0 : handleSingleTryOn,
|
|
18723
18749
|
continueLabel: resultImageUrl ? t2("Continue Shopping") : void 0,
|
|
18724
18750
|
tryOnProcessing,
|
|
18725
|
-
t: t2
|
|
18751
|
+
t: t2,
|
|
18752
|
+
renderRaw: isAccessory
|
|
18726
18753
|
}
|
|
18727
18754
|
) }, "panel-single")
|
|
18728
18755
|
] });
|
|
@@ -22454,6 +22481,7 @@ function FootSizeView(props) {
|
|
|
22454
22481
|
{
|
|
22455
22482
|
title: "Shoe Size",
|
|
22456
22483
|
fields,
|
|
22484
|
+
disablePhotoUpload: true,
|
|
22457
22485
|
...rest
|
|
22458
22486
|
}
|
|
22459
22487
|
);
|