GoodCase.aiAI 动态 · Radar↗图谱 · AI Map↗课程 · LearnPrompt↗
出品GoodCase.aiAI News Radar ↗AI Map ↗LearnPrompt ↗
GoodCase.aiGoodCase.aiAI提示语案例合集
GoodCase.ai
排行榜案例Skills收藏投稿早报加入我们
中文EN
Agent 接入 →

出品

AI 动态 · Radar ↗图谱 · AI Map ↗课程 · LearnPrompt ↗
GoodCase.aiGoodCase.aiAI提示语案例合集
排行榜案例Skills收藏投稿早报加入我们
中文EN
Agent 接入 →

加载中…

GoodCase.ai · AI提示语案例合集
DSH 插件榜更新日志反馈
模型创作者Seedance 2.5Seedance 2.0GPT Image 2GeminiNano Banana ProClaudeClaude Opus 5.5Grok ImagineVeoKling 可灵Qwen ImageGPT Image 1.5MiniMax H3
图片徽章

图片徽章

创作者 · Aceternity UI

AI 编程(UI)Aceternity UI收录 2026/08/13已有人复测#not-rerun#web-ui
更多标签 (1)
#motion-3d
查看原始来源 ↗

Prompt

复刻提示词保留原文,另附运行环境、素材与验收要求;附加说明不是原作者原话。

// components/ui/images-badge.tsx
"use client";

import React, { useState } from "react";
import { motion } from "motion/react";
import { cn } from "@/lib/utils";

interface ImagesBadgeProps {
  text: string;
  images: string[];
  className?: string;
  /** 可选链接 URL */
  href?: string;
  /** 链接的 target 属性(例如,用于在新标签页打开的 "_blank") */
  target?: string;
  /** 文件夹尺寸 { width, height },单位为像素 */
  folderSize?: { width: number; height: number };
  /** 图片露出时的尺寸 { width, height },单位为像素 */
  teaserImageSize?: { width: number; height: number };
  /** 悬停时的图片尺寸 { width, height },单位为像素 */
  hoverImageSize?: { width: number; height: number };
  /** 悬停时图片向上平移的像素数 */
  hoverTranslateY?: number;
  /** 悬停时图片水平展开的像素数 */
  hoverSpread?: number;
  /** 悬停时扇形展开图片的旋转角度,单位为度 */
  hoverRotation?: number;
}

export function ImagesBadge({
  text,
  images,
  className,
  href,
  target,
  folderSize = { width: 32, height: 24 },
  teaserImageSize = { width: 20, height: 14 },
  hoverImageSize = { width: 48, height: 32 },
  hoverTranslateY = -35,
  hoverSpread = 20,
  hoverRotation = 15,
}: ImagesBadgeProps) {
  const [isHovered, setIsHovered] = useState(false);

  // 最多限制为 3 张图片
  const displayImages = images.slice(0, 3);

  // 按比例计算文件夹标签尺寸
  const tabWidth = folderSize.width * 0.375;
  const tabHeight = folderSize.height * 0.25;

  const Component = href ? "a" : "div";

  return (
    <Component
      href={href}
      target={target}
      rel={target === "_blank" ? "noopener noreferrer" : undefined}
      className={cn(
        "inline-flex cursor-pointer items-center gap-2 perspective-[1000px] transform-3d",
        className,
      )}
      onMouseEnter={() => setIsHovered(true)}
      onMouseLeave={() => setIsHovered(false)}
    >
      {/* 文件夹容器 */}
      <motion.div
        className="relative"
        style={{
          width: folderSize.width,
          height: folderSize.height,
          transformStyle: "preserve-3d",
        }}
      >
        {/* 文件夹背面 */}
        <div className="absolute inset-0 rounded-[4px] bg-gradient-to-b from-amber-400 to-amber-500 shadow-sm dark:from-amber-500 dark:to-amber-600">
          {/* 文件夹标签 */}
          <div
            className="absolute left-0.5 rounded-t-[2px] bg-gradient-to-b from-amber-300 to-amber-400 dark:from-amber-400 dark:to-amber-500"
            style={{
              top: -tabHeight * 0.65,
              width: tabWidth,
              height: tabHeight,
            }}
          />
        </div>

        {/* 弹出的图片 */}
        {displayImages.map((image, index) => {
          const totalImages = displayImages.length;

          // 根据索引计算旋转角度
          const baseRotation =
            totalImages === 1
              ? 0
              : totalImages === 2
                ? (index - 0.5) * hoverRotation
                : (index - 1) * hoverRotation;

          // 悬停位置——扇形展开
          const hoverY = hoverTranslateY - (totalImages - 1 - index) * 3;
          const hoverX =
            totalImages === 1
              ? 0
              : totalImages === 2
                ? (index - 0.5) * hoverSpread
                : (index - 1) * hoverSpread;

          // 预览位置——从文件夹中略微露出
          const teaseY = -4 - (totalImages - 1 - index) * 1;
          const teaseRotation =
            totalImages === 1
              ? 0
              : totalImages === 2
                ? (index - 0.5) * 3
                : (index - 1) * 3;

          return (
            <motion.div
              key={index}
              className="absolute top-0.5 left-1/2 origin-bottom overflow-hidden rounded-[3px] bg-white shadow-sm ring-1 shadow-black/10 ring-black/10 dark:bg-neutral-800 dark:shadow-white/10 dark:ring-white/10"
              animate={{
                x: `calc(-50% + ${isHovered ? hoverX : 0}px)`,
                y: isHovered ? hoverY : teaseY,
                rotate: isHovered ? baseRotation : teaseRotation,
                width: isHovered ? hoverImageSize.width : teaserImageSize.width,
                height: isHovered
                  ? hoverImageSize.height
                  : teaserImageSize.height,
              }}
              transition={{
                type: "spring",
                stiffness: 400,
                damping: 25,
                delay: index * 0.03,
              }}
              style={{
                zIndex: 10 + index,
              }}
            >
              <img
                src={image}
                alt={`预览 ${index + 1}`}
                className="h-full w-full object-cover"
              />
            </motion.div>
          );
        })}

        {/* 文件夹正面(悬停时变平) */}
        <motion.div
          className="absolute inset-x-0 bottom-0 h-[85%] origin-bottom rounded-[4px] bg-gradient-to-b from-amber-300 to-amber-400 shadow-sm dark:from-amber-400 dark:to-amber-500"
          animate={{
            rotateX: isHovered ? -45 : -25,
            scaleY: isHovered ? 0.8 : 1,
          }}
          transition={{
            type: "spring",
            stiffness: 400,
            damping: 25,
          }}
          style={{
            transformStyle: "preserve-3d",
            zIndex: 20,
          }}
        >
          {/* 文件夹线条细节 */}
          <div className="absolute top-1 right-1 left-1 h-px bg-amber-200/50 dark:bg-amber-300/50" />
        </motion.div>
      </motion.div>

      {/* 文本 */}
      <span className="text-sm font-medium text-neutral-700 dark:text-neutral-200">
        {text}
      </span>
    </Component>
  );
}
≡溯源 · 已核对已发布案例的 prompt 均经人工核对与原帖一致;平台逆向重构的 prompt 不予收录。核对原帖 ↗

适用模型与稳定度

建议模型

待补充模型
稳定度
83 / 100
成本
中
对应 Skill3D / 动效 Hero ↗

多人复现

1 个人用同一段 Prompt 跑出了自己的作品。

复现作品 · 非作者原作
卡尔
复现者卡尔
2026年10月15日
卡尔 的复现作品打开复现作品 ↗
glm-5.3

GLM-5.3 单次生成;Codex 人工修复运行依赖、必要源码及移动布局,未重新生成。桌面/手机真实渲染和资源检查通过;完整功能与视觉还原尚未全部验收。源码、截图和修复记录见复现出处。

复现出处 ↗

继续探索

继续看相关 Case。

查看全部 AI 编程(UI) Case →
3D 动画图钉
AI 编程(UI)Aceternity UI收录 2026/08/13

3D 动画图钉

复制这段 TSX 组件源码,交给 Cursor、v0、Claude 等 AI 编程工具,说明这是「3D Animated Pin」的 Aceternity UI 组件实现,即可让它接入你的 React 项目,再按需替换文案、配色与触发参数复用。

Skill · 3D / 动效 Hero

提示语

// components/ui/3d-pin.tsx "use client"; import React, { useState } from "react"; import { motion } from "motion/react"; import { cn } from "@/lib/utils"; export const PinContainer = ({ children, title, href, className, containerClassName…

来源热度 · Aceternity UI
—
稳定度
46
查看 Case →
3D 地球
AI 编程(UI)Aceternity UI收录 2026/08/13

3D 地球

复制这段 TSX 组件源码,交给 Cursor、v0、Claude 等 AI 编程工具,说明这是「3D Globe」的 Aceternity UI 组件实现,即可让它接入你的 React 项目,再按需替换文案、配色与触发参数复用。

Skill · 3D / 动效 Hero

提示语

// components/ui/3d-globe.tsx "use client"; import React, { useRef, useMemo, useState, useCallback, Suspense } from "react"; import { Canvas, useFrame, useThree } from "@react-three/fiber"; import { OrbitControls, Html, useTexture } from "…

来源热度 · Aceternity UI
—
稳定度
60
查看 Case →
3D Marquee
AI 编程(UI)Aceternity UI收录 2026/08/13

3D Marquee

复制这段 TSX 组件源码,交给 Cursor、v0、Claude 等 AI 编程工具,说明这是「3D Marquee」的 Aceternity UI 组件实现,即可让它接入你的 React 项目,再按需替换文案、配色与触发参数复用。

Skill · 3D / 动效 Hero

提示语

// components/ui/3d-marquee.tsx "use client"; import { motion } from "motion/react"; import { cn } from "@/lib/utils"; export const ThreeDMarquee = ({ images, className, }: { images: string[]; className?: string; }) => { // Split the image…

来源热度 · Aceternity UI
—
稳定度
84
查看 Case →

同作者

同作者更多 · Aceternity UI →

  • 视差首屏图片AI 编程(UI) · 2026-08-13
  • 世界地图AI 编程(UI) · 2026-08-13
  • 文件上传AI 编程(UI) · 2026-08-13
  • 占位符与消失输入框AI 编程(UI) · 2026-08-13
  • Evervault 卡片AI 编程(UI) · 2026-08-13
  • 侧边栏AI 编程(UI) · 2026-08-13

Case 详情页把原帖效果、Prompt 与复测证据放在同一条阅读路径里。