@buildcores/render-client 1.0.5 → 1.0.7
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/api.d.ts +14 -7
- package/dist/hooks/useBuildRender.d.ts +2 -2
- package/dist/hooks/useSpriteRender.d.ts +2 -2
- package/dist/index.d.ts +196 -11
- package/dist/index.esm.js +95 -28
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +96 -27
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +65 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -322,27 +322,41 @@ function useBouncePatternProgress(enabled = true) {
|
|
|
322
322
|
}
|
|
323
323
|
|
|
324
324
|
// API Configuration
|
|
325
|
-
const API_BASE_URL = "https://
|
|
325
|
+
const API_BASE_URL = "https://www.renderapi.buildcores.com";
|
|
326
326
|
// API Endpoints
|
|
327
327
|
const API_ENDPOINTS = {
|
|
328
328
|
RENDER_BUILD_EXPERIMENTAL: "/render-build-experimental",
|
|
329
329
|
AVAILABLE_PARTS: "/available-parts",
|
|
330
330
|
};
|
|
331
331
|
// API URL helpers
|
|
332
|
-
const buildApiUrl = (endpoint) => {
|
|
333
|
-
|
|
332
|
+
const buildApiUrl = (endpoint, config) => {
|
|
333
|
+
const baseUrl = `${API_BASE_URL}${endpoint}`;
|
|
334
|
+
if (config.environment) {
|
|
335
|
+
const separator = endpoint.includes("?") ? "&" : "?";
|
|
336
|
+
return `${baseUrl}${separator}environment=${config.environment}`;
|
|
337
|
+
}
|
|
338
|
+
return baseUrl;
|
|
339
|
+
};
|
|
340
|
+
// Helper to build request headers with auth token
|
|
341
|
+
const buildHeaders = (config) => {
|
|
342
|
+
const headers = {
|
|
343
|
+
"Content-Type": "application/json",
|
|
344
|
+
accept: "application/json",
|
|
345
|
+
};
|
|
346
|
+
if (config.authToken) {
|
|
347
|
+
headers["Authorization"] = `Bearer ${config.authToken}`;
|
|
348
|
+
}
|
|
349
|
+
return headers;
|
|
334
350
|
};
|
|
335
351
|
// API Implementation
|
|
336
|
-
const renderBuildExperimental = async (request) => {
|
|
352
|
+
const renderBuildExperimental = async (request, config) => {
|
|
337
353
|
const requestWithFormat = {
|
|
338
354
|
...request,
|
|
339
355
|
format: request.format || "video", // Default to video format
|
|
340
356
|
};
|
|
341
|
-
const response = await fetch(buildApiUrl(API_ENDPOINTS.RENDER_BUILD_EXPERIMENTAL), {
|
|
357
|
+
const response = await fetch(buildApiUrl(API_ENDPOINTS.RENDER_BUILD_EXPERIMENTAL, config), {
|
|
342
358
|
method: "POST",
|
|
343
|
-
headers:
|
|
344
|
-
"Content-Type": "application/json",
|
|
345
|
-
},
|
|
359
|
+
headers: buildHeaders(config),
|
|
346
360
|
body: JSON.stringify(requestWithFormat),
|
|
347
361
|
});
|
|
348
362
|
if (!response.ok) {
|
|
@@ -357,16 +371,14 @@ const renderBuildExperimental = async (request) => {
|
|
|
357
371
|
},
|
|
358
372
|
};
|
|
359
373
|
};
|
|
360
|
-
const renderSpriteExperimental = async (request) => {
|
|
374
|
+
const renderSpriteExperimental = async (request, config) => {
|
|
361
375
|
const requestWithFormat = {
|
|
362
376
|
...request,
|
|
363
377
|
format: "sprite",
|
|
364
378
|
};
|
|
365
|
-
const response = await fetch(buildApiUrl(API_ENDPOINTS.RENDER_BUILD_EXPERIMENTAL), {
|
|
379
|
+
const response = await fetch(buildApiUrl(API_ENDPOINTS.RENDER_BUILD_EXPERIMENTAL, config), {
|
|
366
380
|
method: "POST",
|
|
367
|
-
headers:
|
|
368
|
-
"Content-Type": "application/json",
|
|
369
|
-
},
|
|
381
|
+
headers: buildHeaders(config),
|
|
370
382
|
body: JSON.stringify(requestWithFormat),
|
|
371
383
|
});
|
|
372
384
|
if (!response.ok) {
|
|
@@ -384,12 +396,10 @@ const renderSpriteExperimental = async (request) => {
|
|
|
384
396
|
},
|
|
385
397
|
};
|
|
386
398
|
};
|
|
387
|
-
const getAvailableParts = async () => {
|
|
388
|
-
const response = await fetch(buildApiUrl(API_ENDPOINTS.AVAILABLE_PARTS), {
|
|
399
|
+
const getAvailableParts = async (config) => {
|
|
400
|
+
const response = await fetch(buildApiUrl(API_ENDPOINTS.AVAILABLE_PARTS, config), {
|
|
389
401
|
method: "GET",
|
|
390
|
-
headers:
|
|
391
|
-
"Content-Type": "application/json",
|
|
392
|
-
},
|
|
402
|
+
headers: buildHeaders(config),
|
|
393
403
|
});
|
|
394
404
|
if (!response.ok) {
|
|
395
405
|
throw new Error(`Get available parts failed: ${response.status} ${response.statusText}`);
|
|
@@ -397,7 +407,6 @@ const getAvailableParts = async () => {
|
|
|
397
407
|
return response.json();
|
|
398
408
|
};
|
|
399
409
|
|
|
400
|
-
// API Types
|
|
401
410
|
/**
|
|
402
411
|
* Enum defining all available PC part categories that can be rendered.
|
|
403
412
|
*
|
|
@@ -466,7 +475,7 @@ const arePartsEqual = (parts1, parts2) => {
|
|
|
466
475
|
}
|
|
467
476
|
return true;
|
|
468
477
|
};
|
|
469
|
-
const useBuildRender = (parts, onLoadStart) => {
|
|
478
|
+
const useBuildRender = (parts, apiConfig, onLoadStart) => {
|
|
470
479
|
const [videoSrc, setVideoSrc] = React.useState(null);
|
|
471
480
|
const [isRenderingBuild, setIsRenderingBuild] = React.useState(false);
|
|
472
481
|
const [renderError, setRenderError] = React.useState(null);
|
|
@@ -476,7 +485,7 @@ const useBuildRender = (parts, onLoadStart) => {
|
|
|
476
485
|
setIsRenderingBuild(true);
|
|
477
486
|
setRenderError(null);
|
|
478
487
|
onLoadStart?.();
|
|
479
|
-
const response = await renderBuildExperimental(currentParts);
|
|
488
|
+
const response = await renderBuildExperimental(currentParts, apiConfig);
|
|
480
489
|
const objectUrl = URL.createObjectURL(response.video);
|
|
481
490
|
// Clean up previous video URL before setting new one
|
|
482
491
|
setVideoSrc((prevSrc) => {
|
|
@@ -492,7 +501,7 @@ const useBuildRender = (parts, onLoadStart) => {
|
|
|
492
501
|
finally {
|
|
493
502
|
setIsRenderingBuild(false);
|
|
494
503
|
}
|
|
495
|
-
}, [onLoadStart]);
|
|
504
|
+
}, [apiConfig, onLoadStart]);
|
|
496
505
|
// Effect to call API when parts content changes (using custom equality check)
|
|
497
506
|
React.useEffect(() => {
|
|
498
507
|
const shouldFetch = previousPartsRef.current === null ||
|
|
@@ -517,7 +526,7 @@ const useBuildRender = (parts, onLoadStart) => {
|
|
|
517
526
|
};
|
|
518
527
|
};
|
|
519
528
|
|
|
520
|
-
const useSpriteRender = (parts, onLoadStart) => {
|
|
529
|
+
const useSpriteRender = (parts, apiConfig, onLoadStart) => {
|
|
521
530
|
const [spriteSrc, setSpriteSrc] = React.useState(null);
|
|
522
531
|
const [isRenderingSprite, setIsRenderingSprite] = React.useState(false);
|
|
523
532
|
const [renderError, setRenderError] = React.useState(null);
|
|
@@ -528,7 +537,7 @@ const useSpriteRender = (parts, onLoadStart) => {
|
|
|
528
537
|
setIsRenderingSprite(true);
|
|
529
538
|
setRenderError(null);
|
|
530
539
|
onLoadStart?.();
|
|
531
|
-
const response = await renderSpriteExperimental(currentParts);
|
|
540
|
+
const response = await renderSpriteExperimental(currentParts, apiConfig);
|
|
532
541
|
const objectUrl = URL.createObjectURL(response.sprite);
|
|
533
542
|
// Clean up previous sprite URL before setting new one
|
|
534
543
|
setSpriteSrc((prevSrc) => {
|
|
@@ -550,7 +559,7 @@ const useSpriteRender = (parts, onLoadStart) => {
|
|
|
550
559
|
finally {
|
|
551
560
|
setIsRenderingSprite(false);
|
|
552
561
|
}
|
|
553
|
-
}, [onLoadStart]);
|
|
562
|
+
}, [apiConfig, onLoadStart]);
|
|
554
563
|
// Effect to call API when parts content changes (using custom equality check)
|
|
555
564
|
React.useEffect(() => {
|
|
556
565
|
const shouldFetch = previousPartsRef.current === null ||
|
|
@@ -631,13 +640,13 @@ const InstructionTooltip = ({ isVisible, progressValue, instructionIcon, }) => {
|
|
|
631
640
|
} })) }));
|
|
632
641
|
};
|
|
633
642
|
|
|
634
|
-
const BuildRender = ({ parts, size, mouseSensitivity = 0.2, touchSensitivity = 0.2, }) => {
|
|
643
|
+
const BuildRender = ({ parts, size, apiConfig, mouseSensitivity = 0.2, touchSensitivity = 0.2, }) => {
|
|
635
644
|
const canvasRef = React.useRef(null);
|
|
636
645
|
const [img, setImg] = React.useState(null);
|
|
637
646
|
const [isLoading, setIsLoading] = React.useState(true);
|
|
638
647
|
const [bouncingAllowed, setBouncingAllowed] = React.useState(false);
|
|
639
648
|
// Use custom hook for sprite rendering
|
|
640
|
-
const { spriteSrc, isRenderingSprite, renderError, spriteMetadata } = useSpriteRender(parts);
|
|
649
|
+
const { spriteSrc, isRenderingSprite, renderError, spriteMetadata } = useSpriteRender(parts, apiConfig);
|
|
641
650
|
const { value: progressValue, isBouncing } = useBouncePatternProgress(bouncingAllowed);
|
|
642
651
|
const total = spriteMetadata ? spriteMetadata.totalFrames : 72;
|
|
643
652
|
const cols = spriteMetadata ? spriteMetadata.cols : 12;
|
|
@@ -844,14 +853,74 @@ const useVideoScrubbing = (videoRef, options = {}) => {
|
|
|
844
853
|
};
|
|
845
854
|
};
|
|
846
855
|
|
|
856
|
+
const BuildRenderVideo = ({ parts, size, apiConfig, mouseSensitivity = 0.01, touchSensitivity = 0.01, }) => {
|
|
857
|
+
const videoRef = React.useRef(null);
|
|
858
|
+
const [isLoading, setIsLoading] = React.useState(true);
|
|
859
|
+
const [bouncingAllowed, setBouncingAllowed] = React.useState(false);
|
|
860
|
+
// Use custom hook for build rendering
|
|
861
|
+
const { videoSrc, isRenderingBuild, renderError } = useBuildRender(parts, apiConfig);
|
|
862
|
+
const { value: progressValue, isBouncing } = useBouncePatternProgress(bouncingAllowed);
|
|
863
|
+
const { isDragging, handleMouseDown, handleTouchStart, hasDragged } = useVideoScrubbing(videoRef, {
|
|
864
|
+
mouseSensitivity,
|
|
865
|
+
touchSensitivity,
|
|
866
|
+
});
|
|
867
|
+
const handleLoadStartInternal = React.useCallback(() => {
|
|
868
|
+
setIsLoading(true);
|
|
869
|
+
setBouncingAllowed(false);
|
|
870
|
+
}, []);
|
|
871
|
+
const handleCanPlayInternal = React.useCallback(() => {
|
|
872
|
+
setIsLoading(false);
|
|
873
|
+
// Start bouncing animation after delay
|
|
874
|
+
setTimeout(() => {
|
|
875
|
+
setBouncingAllowed(true);
|
|
876
|
+
}, 2000);
|
|
877
|
+
}, []);
|
|
878
|
+
React.useEffect(() => {
|
|
879
|
+
if (hasDragged.current || !videoRef.current)
|
|
880
|
+
return;
|
|
881
|
+
const duration = videoRef.current.duration;
|
|
882
|
+
if (!isFinite(duration))
|
|
883
|
+
return;
|
|
884
|
+
const time = calculateCircularTime(0, progressValue, 0.5, duration);
|
|
885
|
+
if (isFinite(time)) {
|
|
886
|
+
videoRef.current.currentTime = time;
|
|
887
|
+
}
|
|
888
|
+
}, [progressValue, hasDragged]);
|
|
889
|
+
return (jsxRuntime.jsxs("div", { style: { position: "relative", width: size, height: size }, children: [videoSrc && (jsxRuntime.jsx("video", { ref: videoRef, src: videoSrc, width: size, height: size, autoPlay: true, preload: "metadata", muted: true, playsInline: true, controls: false, disablePictureInPicture: true, controlsList: "nodownload nofullscreen noremoteplayback", ...{ "x-webkit-airplay": "deny" }, onMouseDown: handleMouseDown, onTouchStart: handleTouchStart, onLoadStart: handleLoadStartInternal, onCanPlay: handleCanPlayInternal, onLoadedData: () => {
|
|
890
|
+
if (videoRef.current) {
|
|
891
|
+
videoRef.current.pause();
|
|
892
|
+
}
|
|
893
|
+
}, style: {
|
|
894
|
+
cursor: isDragging ? "grabbing" : "grab",
|
|
895
|
+
touchAction: "none", // Prevents default touch behaviors like scrolling
|
|
896
|
+
display: "block",
|
|
897
|
+
// Completely hide video controls on all browsers including mobile
|
|
898
|
+
WebkitMediaControls: "none",
|
|
899
|
+
MozMediaControls: "none",
|
|
900
|
+
OMediaControls: "none",
|
|
901
|
+
msMediaControls: "none",
|
|
902
|
+
mediaControls: "none",
|
|
903
|
+
// Additional iOS-specific properties
|
|
904
|
+
WebkitTouchCallout: "none",
|
|
905
|
+
WebkitUserSelect: "none",
|
|
906
|
+
userSelect: "none",
|
|
907
|
+
}, children: "Your browser does not support the video tag." }, videoSrc)), jsxRuntime.jsx(LoadingErrorOverlay, { isVisible: isLoading || isRenderingBuild || !!renderError, renderError: renderError || undefined, size: size }), jsxRuntime.jsx(InstructionTooltip, { isVisible: !isLoading &&
|
|
908
|
+
!isRenderingBuild &&
|
|
909
|
+
!renderError &&
|
|
910
|
+
isBouncing &&
|
|
911
|
+
!hasDragged.current, progressValue: progressValue })] }));
|
|
912
|
+
};
|
|
913
|
+
|
|
847
914
|
exports.API_BASE_URL = API_BASE_URL;
|
|
848
915
|
exports.API_ENDPOINTS = API_ENDPOINTS;
|
|
849
916
|
exports.BuildRender = BuildRender;
|
|
917
|
+
exports.BuildRenderVideo = BuildRenderVideo;
|
|
850
918
|
exports.DragIcon = DragIcon;
|
|
851
919
|
exports.InstructionTooltip = InstructionTooltip;
|
|
852
920
|
exports.LoadingErrorOverlay = LoadingErrorOverlay;
|
|
853
921
|
exports.arePartsEqual = arePartsEqual;
|
|
854
922
|
exports.buildApiUrl = buildApiUrl;
|
|
923
|
+
exports.buildHeaders = buildHeaders;
|
|
855
924
|
exports.calculateCircularFrame = calculateCircularFrame;
|
|
856
925
|
exports.calculateCircularTime = calculateCircularTime;
|
|
857
926
|
exports.getAvailableParts = getAvailableParts;
|