@@ -77,6 +77,93 @@ const WECHAT_INLINE_VIDEO_PROPS: Record<string, string> = {
7777 "x5-video-player-fullscreen" : "false" ,
7878} ;
7979
80+ type GeneralizationSlide = {
81+ key : string ;
82+ poster : string ;
83+ mp4 : string ;
84+ labelType : "Robustness" | "Generalization" ;
85+ task : string ;
86+ phase ?: string ;
87+ } ;
88+
89+ const GENERALIZATION_CAROUSEL_SLIDES : GeneralizationSlide [ ] = [
90+ {
91+ key : "cable-robust-full" ,
92+ poster : "https://ik.imagekit.io/3ic6kgidz/cable_robust_full.jpg" ,
93+ mp4 : "https://ik.imagekit.io/7rgtwup0y/cable_robust_full.mp4" ,
94+ labelType : "Robustness" ,
95+ task : "Cable Mounting" ,
96+ phase : "(Full-Disturbance)" ,
97+ } ,
98+ {
99+ key : "cable-robust-post" ,
100+ poster : "https://ik.imagekit.io/3ic6kgidz/cable_robust_post.jpg" ,
101+ mp4 : "https://ik.imagekit.io/7rgtwup0y/cable_robust_post.mp4" ,
102+ labelType : "Robustness" ,
103+ task : "Cable Mounting" ,
104+ phase : "(Post-Grasp Disturbance)" ,
105+ } ,
106+ {
107+ key : "gen-cable" ,
108+ poster : "https://ik.imagekit.io/3ic6kgidz/gen_cable.jpg" ,
109+ mp4 : "https://ik.imagekit.io/3ic6kgidz/gen_cable.mp4" ,
110+ labelType : "Generalization" ,
111+ task : "Cable Mounting" ,
112+ } ,
113+ {
114+ key : "gen-clip" ,
115+ poster : "https://ik.imagekit.io/3ic6kgidz/gen_clip.jpg" ,
116+ mp4 : "https://ik.imagekit.io/3ic6kgidz/gen_clip.mp4" ,
117+ labelType : "Generalization" ,
118+ task : "Binder Clip Removal" ,
119+ } ,
120+ {
121+ key : "gen-herbal" ,
122+ poster : "https://ik.imagekit.io/3ic6kgidz/gen_herbal.jpg" ,
123+ mp4 : "https://ik.imagekit.io/3ic6kgidz/gen_herbal.mp4" ,
124+ labelType : "Generalization" ,
125+ task : "Herbal Transfer" ,
126+ } ,
127+ {
128+ key : "herbal-robust-post" ,
129+ poster : "https://ik.imagekit.io/3ic6kgidz/herbal_robust_post.jpg" ,
130+ mp4 : "https://ik.imagekit.io/7rgtwup0y/herbal_robust_post.mp4" ,
131+ labelType : "Robustness" ,
132+ task : "Herbal Transfer" ,
133+ phase : "(Post-Grasp Disturbance)" ,
134+ } ,
135+ ] ;
136+
137+ function GeneralizationSlideCard ( { slide } : { slide : GeneralizationSlide } ) {
138+ return (
139+ < Card className = "border-[#174BE5]/50 bg-black/40 border-0 card" >
140+ < CardContent className = "cardContent flex flex-col items-center justify-center p-2 md:p-6 gap-1 md:gap-1" >
141+ < video
142+ preload = "none"
143+ autoPlay
144+ loop
145+ muted
146+ playsInline
147+ { ...WECHAT_INLINE_VIDEO_PROPS }
148+ poster = { slide . poster }
149+ className = "aspect-video w-full object-cover border-2 md:border-6 border-[#174BE5]/50 rounded-xl"
150+ >
151+ < source src = { slide . mp4 } />
152+ </ video >
153+ < div className = "w-full text-center bg-black/70 p-1 rounded-lg shadow-md border border-white/20" >
154+ < p className = "user-study-label text-[#174BE5]" >
155+ < span className = "label-type" > { slide . labelType } </ span >
156+ < span className = "label-task" > { slide . task } </ span >
157+ { slide . phase ? (
158+ < span className = "label-phase" > { slide . phase } </ span >
159+ ) : null }
160+ </ p >
161+ </ div >
162+ </ CardContent >
163+ </ Card >
164+ ) ;
165+ }
166+
80167const pageNavItems : { text : string ; id : string } [ ] = [
81168 { text : "Highlights" , id : "highlights" } ,
82169 { text : "Data Collection Modes" , id : "data-collection-modes" } ,
@@ -900,179 +987,52 @@ export default function Home() {
900987 />
901988 </div> */ }
902989 < div className = "w-full min-w-0 max-w-full md:max-w-[1400px] px-3 sm:px-6 md:px-20 3xl:px-64 mt-5 md:mt-10 p-2 md:p-6 overflow-x-clip" >
903- < Carousel
904- opts = { {
905- align : "center" ,
906- loop : true ,
907- containScroll : "trimSnaps" ,
908- dragFree : false ,
909- breakpoints : {
910- "(max-width: 640px)" : { slidesToScroll : 1 } ,
911- "(min-width: 641px) and (max-width: 768px)" : {
912- slidesToScroll : 1 ,
990+ < p className = "mb-2 text-center text-[10px] text-white/50 md:hidden" >
991+ 左右滑动查看更多视频
992+ </ p >
993+ { /* iOS 微信:Embla 轨道使用 translate3d,会导致 WKWebView 内 video 无法绘制;窄屏改用原生横向滚动 */ }
994+ < div className = "md:hidden -mx-1 flex w-full touch-pan-x gap-3 overflow-x-auto overscroll-x-contain px-2 pb-3 snap-x snap-mandatory [-webkit-overflow-scrolling:touch]" >
995+ { GENERALIZATION_CAROUSEL_SLIDES . map ( ( slide ) => (
996+ < div
997+ key = { slide . key }
998+ className = "w-[min(88vw,400px)] shrink-0 snap-center"
999+ >
1000+ < GeneralizationSlideCard slide = { slide } />
1001+ </ div >
1002+ ) ) }
1003+ </ div >
1004+
1005+ < div className = "relative hidden md:block" >
1006+ < Carousel
1007+ opts = { {
1008+ align : "center" ,
1009+ loop : true ,
1010+ containScroll : "trimSnaps" ,
1011+ dragFree : false ,
1012+ breakpoints : {
1013+ "(max-width: 640px)" : { slidesToScroll : 1 } ,
1014+ "(min-width: 641px) and (max-width: 768px)" : {
1015+ slidesToScroll : 1 ,
1016+ } ,
1017+ "(min-width: 769px)" : { slidesToScroll : 1 } ,
9131018 } ,
914- "(min-width: 769px)" : { slidesToScroll : 1 } ,
915- } ,
916- } }
917- className = "w-full user-study-carousel"
918- >
919- < CarouselContent className = "-ml-2 md:-ml-4" >
920- < CarouselItem className = "carouselItem basis-full md:basis-1/2 lg:basis-1/3 pl-2 md:pl-4" >
921- < Card className = "border-[#174BE5]/50 bg-black/40 border-0 card" >
922- < CardContent className = "cardContent flex flex-col items-center justify-center p-2 md:p-6 gap-1 md:gap-1" >
923- < video
924- preload = "none"
925- autoPlay
926- loop
927- muted
928- playsInline
929- { ...WECHAT_INLINE_VIDEO_PROPS }
930- poster = "https://ik.imagekit.io/3ic6kgidz/cable_robust_full.jpg"
931- className = "border-2 md:border-6 border-[#174BE5]/50 rounded-xl w-full"
932- >
933- < source src = "https://ik.imagekit.io/7rgtwup0y/cable_robust_full.mp4" />
934- </ video >
935- < div className = "w-full text-center bg-black/70 p-1 rounded-lg shadow-md border border-white/20" >
936- < p className = "user-study-label text-[#174BE5]" >
937- < span className = "label-type" > Robustness</ span >
938- < span className = "label-task" > Cable Mounting</ span >
939- < span className = "label-phase" > (Full-Disturbance)</ span >
940- </ p >
941- </ div >
942- </ CardContent >
943- </ Card >
944- </ CarouselItem >
945- < CarouselItem className = "carouselItem basis-full md:basis-1/2 lg:basis-1/3 pl-2 md:pl-4" >
946- < Card className = "card border-[#174BE5]/50 bg-black/40 border-0" >
947- < CardContent className = "cardContent flex flex-col items-center justify-center p-2 md:p-6 gap-1 md:gap-1" >
948- < video
949- preload = "none"
950- autoPlay
951- loop
952- muted
953- playsInline
954- { ...WECHAT_INLINE_VIDEO_PROPS }
955- poster = "https://ik.imagekit.io/3ic6kgidz/cable_robust_post.jpg"
956- className = "border-2 md:border-6 border-[#174BE5]/50 rounded-xl w-full"
957- >
958- < source src = "https://ik.imagekit.io/7rgtwup0y/cable_robust_post.mp4" />
959- </ video >
960- < div className = "w-full text-center bg-black/70 p-1 rounded-lg shadow-md border border-white/20" >
961- < p className = "user-study-label text-[#174BE5]" >
962- < span className = "label-type" > Robustness</ span >
963- < span className = "label-task" > Cable Mounting</ span >
964- < span className = "label-phase" >
965- (Post-Grasp Disturbance)
966- </ span >
967- </ p >
968- </ div >
969- </ CardContent >
970- </ Card >
971- </ CarouselItem >
972- < CarouselItem className = "carouselItem basis-full md:basis-1/2 lg:basis-1/3 pl-2 md:pl-4" >
973- < Card className = "card border-[#174BE5]/50 bg-black/40 border-0" >
974- < CardContent className = "cardContent flex flex-col items-center justify-center p-2 md:p-6 gap-1 md:gap-1" >
975- < video
976- preload = "none"
977- autoPlay
978- loop
979- muted
980- playsInline
981- { ...WECHAT_INLINE_VIDEO_PROPS }
982- poster = "https://ik.imagekit.io/3ic6kgidz/gen_cable.jpg"
983- className = "border-2 md:border-6 border-[#174BE5]/50 rounded-xl w-full"
984- >
985- < source src = "https://ik.imagekit.io/3ic6kgidz/gen_cable.mp4" />
986- </ video >
987- < div className = "w-full text-center bg-black/70 p-1 rounded-lg shadow-md border border-white/20" >
988- < p className = "user-study-label text-[#174BE5]" >
989- < span className = "label-type" > Generalization</ span >
990- < span className = "label-task" > Cable Mounting</ span >
991- </ p >
992- </ div >
993- </ CardContent >
994- </ Card >
995- </ CarouselItem >
996- < CarouselItem className = "carouselItem basis-full md:basis-1/2 lg:basis-1/3 pl-2 md:pl-4" >
997- < Card className = "card border-[#174BE5]/50 bg-black/40 border-0" >
998- < CardContent className = "cardContent flex flex-col items-center justify-center p-2 md:p-6 gap-1 md:gap-1" >
999- < video
1000- preload = "none"
1001- autoPlay
1002- loop
1003- muted
1004- playsInline
1005- { ...WECHAT_INLINE_VIDEO_PROPS }
1006- poster = "https://ik.imagekit.io/3ic6kgidz/gen_clip.jpg"
1007- className = "border-2 md:border-6 border-[#174BE5]/50 rounded-xl w-full"
1008- >
1009- < source src = "https://ik.imagekit.io/3ic6kgidz/gen_clip.mp4" />
1010- </ video >
1011- < div className = "w-full text-center bg-black/70 p-1 rounded-lg shadow-md border border-white/20" >
1012- < p className = "user-study-label text-[#174BE5]" >
1013- < span className = "label-type" > Generalization</ span >
1014- < span className = "label-task" > Binder Clip Removal</ span >
1015- </ p >
1016- </ div >
1017- </ CardContent >
1018- </ Card >
1019- </ CarouselItem >
1020- < CarouselItem className = "carouselItem basis-full md:basis-1/2 lg:basis-1/3 pl-2 md:pl-4" >
1021- < Card className = "card border-[#174BE5]/50 bg-black/40 border-0" >
1022- < CardContent className = "cardContent flex flex-col items-center justify-center p-2 md:p-6 gap-1 md:gap-1" >
1023- < video
1024- preload = "none"
1025- autoPlay
1026- loop
1027- muted
1028- playsInline
1029- { ...WECHAT_INLINE_VIDEO_PROPS }
1030- poster = "https://ik.imagekit.io/3ic6kgidz/gen_herbal.jpg"
1031- className = "border-2 md:border-6 border-[#174BE5]/50 rounded-xl w-full"
1032- >
1033- < source src = "https://ik.imagekit.io/3ic6kgidz/gen_herbal.mp4" />
1034- </ video >
1035- < div className = "w-full text-center bg-black/70 p-1 rounded-lg shadow-md border border-white/20" >
1036- < p className = "user-study-label text-[#174BE5]" >
1037- < span className = "label-type" > Generalization</ span >
1038- < span className = "label-task" > Herbal Transfer</ span >
1039- </ p >
1040- </ div >
1041- </ CardContent >
1042- </ Card >
1043- </ CarouselItem >
1044- < CarouselItem className = "carouselItem basis-full md:basis-1/2 lg:basis-1/3 pl-2 md:pl-4" >
1045- < Card className = "card border-[#174BE5]/50 bg-black/40 border-0" >
1046- < CardContent className = "cardContent flex flex-col items-center justify-center p-2 md:p-6 gap-1 md:gap-1" >
1047- < video
1048- preload = "none"
1049- autoPlay
1050- loop
1051- muted
1052- playsInline
1053- { ...WECHAT_INLINE_VIDEO_PROPS }
1054- poster = "https://ik.imagekit.io/3ic6kgidz/herbal_robust_post.jpg"
1055- className = "border-2 md:border-6 border-[#174BE5]/50 rounded-xl w-full"
1056- >
1057- < source src = "https://ik.imagekit.io/7rgtwup0y/herbal_robust_post.mp4" />
1058- </ video >
1059- < div className = "w-full text-center bg-black/70 p-1 rounded-lg shadow-md border border-white/20" >
1060- < p className = "user-study-label text-[#174BE5]" >
1061- < span className = "label-type" > Robustness</ span >
1062- < span className = "label-task" > Herbal Transfer</ span >
1063- < span className = "label-phase" >
1064- (Post-Grasp Disturbance)
1065- </ span >
1066- </ p >
1067- </ div >
1068- </ CardContent >
1069- </ Card >
1070- </ CarouselItem >
1071- { /* Optional hidden items retained for future use */ }
1072- </ CarouselContent >
1073- < CarouselPrevious className = "left-1 md:left-4 size-9 md:size-11 !opacity-100 border border-[#174BE5]/60 bg-white/95 text-[#174BE5] shadow-[0_0_14px_rgba(23,75,229,0.45)] hover:bg-white" />
1074- < CarouselNext className = "right-1 md:right-4 size-9 md:size-11 !opacity-100 border border-[#174BE5]/60 bg-white/95 text-[#174BE5] shadow-[0_0_14px_rgba(23,75,229,0.45)] hover:bg-white" />
1075- </ Carousel >
1019+ } }
1020+ className = "w-full user-study-carousel"
1021+ >
1022+ < CarouselContent className = "-ml-2 md:-ml-4" >
1023+ { GENERALIZATION_CAROUSEL_SLIDES . map ( ( slide ) => (
1024+ < CarouselItem
1025+ key = { slide . key }
1026+ className = "carouselItem basis-full md:basis-1/2 lg:basis-1/3 pl-2 md:pl-4"
1027+ >
1028+ < GeneralizationSlideCard slide = { slide } />
1029+ </ CarouselItem >
1030+ ) ) }
1031+ </ CarouselContent >
1032+ < CarouselPrevious className = "left-1 md:left-4 size-9 md:size-11 !opacity-100 border border-[#174BE5]/60 bg-white/95 text-[#174BE5] shadow-[0_0_14px_rgba(23,75,229,0.45)] hover:bg-white" />
1033+ < CarouselNext className = "right-1 md:right-4 size-9 md:size-11 !opacity-100 border border-[#174BE5]/60 bg-white/95 text-[#174BE5] shadow-[0_0_14px_rgba(23,75,229,0.45)] hover:bg-white" />
1034+ </ Carousel >
1035+ </ div >
10761036 </ div >
10771037 < div className = "w-full px-4 md:px-6 flex flex-col items-center mt-5 md:mt-10" >
10781038 < div className = "w-full max-w-4xl" >
0 commit comments