{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "bloom-lockup",
  "title": "Bloom Lockup",
  "description": "Logo reveal in four seconds. A wall of finished work blooms outward from your logo, cuts in tight on it, then bends away through a lens and a flash while the logo rises to take its wordmark and tagline. Measured frame by frame off a reference recording.",
  "dependencies": [
    "remotion",
    "@remotion/google-fonts"
  ],
  "registryDependencies": [
    "https://snapcn.dev/r/snap-cn-ui.json"
  ],
  "files": [
    {
      "path": "registry/snap-cn/bloom-lockup/index.tsx",
      "content": "// Bloom Lockup · snapcn — https://snapcn.dev/docs/scenes/bloom-lockup\n\"use client\";\n\nimport { loadFont as loadGeistMono } from \"@remotion/google-fonts/GeistMono\";\nimport { loadFont as loadPoppins } from \"@remotion/google-fonts/Poppins\";\nimport { type ReactNode, useEffect, useId, useState } from \"react\";\nimport {\n  AbsoluteFill,\n  continueRender,\n  delayRender,\n  Img,\n  useCurrentFrame,\n  useVideoConfig,\n} from \"remotion\";\nimport {\n  resolveFont,\n  type SnapCnTheme,\n  useSnapCnTheme,\n} from \"@/lib/snap-cn-ui\";\nimport {\n  BEHIND_LOGO,\n  BLOOM_CARDS,\n  BLOOM_DELAY,\n  BLOOM_FADE,\n  BLOOM_SECONDS,\n  BLOOM_ZOOM,\n  CARD_HALO,\n  CARD_IMAGES,\n  HOLD_SECONDS,\n  LENS,\n  LENS_FLASH,\n  LENS_FROM,\n  LENS_RADIUS,\n  LENS_ZOOM,\n  LOCKUP_CARDS,\n  LOCKUP_SECONDS,\n  LOGO_FADE,\n  LOGO_SIZE_BLOOM,\n  LOGO_SIZE_LOCKUP,\n  LOGO_Y,\n  SNAPCN_MARK,\n  TAGLINE_FADE,\n  TAGLINE_RISE,\n  TAGLINE_Y,\n  WORDMARK_FADE,\n  WORDMARK_RISE,\n  WORDMARK_Y,\n} from \"./data\";\n\nconst { fontFamily: POPPINS } = loadPoppins(\"normal\", {\n  weights: [\"600\"],\n  subsets: [\"latin\"],\n});\nconst { fontFamily: GEIST_MONO } = loadGeistMono(\"normal\", {\n  weights: [\"400\"],\n  subsets: [\"latin\"],\n});\n\nconst STAGE_W = 1920;\nconst STAGE_H = 1080;\nconst RATE = 30;\n\nexport interface BloomLockupProps {\n  /** The wordmark under the logo. */\n  wordmark?: string;\n  /** The line under the wordmark. */\n  tagline?: string;\n  /** Your mark as SVG paths, like Cut Lockup's `logo`. Defaults to the snapcn mark. */\n  logo?: {\n    width: number;\n    height: number;\n    shapes: readonly string[];\n    /** Share of the tile the mark fills. */\n    fill?: number;\n  };\n  /** Pictures for the cards; repeats if there are fewer than cards. */\n  images?: readonly string[];\n  /** One picture per card on the first board, in order. */\n  imagesA?: readonly string[];\n  /** One picture per card on the second board, in order. */\n  imagesB?: readonly string[];\n  wordmarkFont?: string;\n  wordmarkWeight?: number;\n  /** Wordmark size on a 1920x1080 stage. */\n  wordmarkSize?: number;\n  speed?: number;\n  theme?: Partial<SnapCnTheme>;\n  mode?: \"light\" | \"dark\";\n}\n\n/** Sample a 1/30s table at a time in seconds; holds both ends. */\nexport const sample = (table: readonly number[], seconds: number) => {\n  const x = Math.max(0, Math.min(seconds * RATE, table.length - 1));\n  const i = Math.floor(x);\n  const a = table[i] ?? 0;\n  return a + ((table[i + 1] ?? a) - a) * (x - i);\n};\n\n/** Opacity of a bloom card at `t`: the wave leaves the logo and spreads outward. */\nexport const cardFade = (i: number, t: number) => {\n  const k = (t - (BLOOM_DELAY[i] ?? 0)) / (BLOOM_FADE[i] ?? 0.2);\n  const x = Math.max(0, Math.min(1, k));\n  return x * x * (3 - 2 * x);\n};\n\n/** Frames in the whole clip at `fps`. */\nexport const clipFrames = (fps: number) =>\n  Math.ceil((BLOOM_SECONDS + LOCKUP_SECONDS + HOLD_SECONDS) * fps);\n\n/** What a lens of strength `q` shows at `r` radii out, as a share of `r`. */\nexport const lensFactor = (q: number, r: number) =>\n  1 / Math.sqrt(1 + q * r * r);\n\n/** The uniform scale that leaves the least for the 8-bit map to carry. */\nexport const lensSplit = (q: number, rMax: number) => {\n  const worst = (c: number) => {\n    let m = 0;\n    for (let j = 1; j <= 64; j++) {\n      const r = (rMax * j) / 64;\n      m = Math.max(m, r * Math.abs(lensFactor(q, r) / c - 1));\n    }\n    return m;\n  };\n  let lo = lensFactor(q, rMax);\n  let hi = 1;\n  for (let it = 0; it < 60; it++) {\n    const a = lo + (hi - lo) / 3;\n    const b = hi - (hi - lo) / 3;\n    if (worst(a) < worst(b)) hi = b;\n    else lo = a;\n  }\n  return (lo + hi) / 2;\n};\n\nconst MAP_W = 240;\nconst MAP_H = 135;\ntype LensMap = { href: string; scale: number; split: number };\n\n/** One displacement map per lens row, decoded before the first frame that needs it. */\nconst useLensMaps = () => {\n  const [maps, setMaps] = useState<LensMap[] | null>(null);\n  useEffect(() => {\n    const handle = delayRender(\"bloom-lockup: lens maps\");\n    const cx = STAGE_W / 2;\n    const cy = STAGE_H / 2;\n    const rMax = Math.hypot(cx, cy) / LENS_RADIUS;\n    const canvas = document.createElement(\"canvas\");\n    canvas.width = MAP_W;\n    canvas.height = MAP_H;\n    const ctx = canvas.getContext(\"2d\");\n    if (!ctx) {\n      continueRender(handle);\n      return;\n    }\n    const out = LENS.map((q) => {\n      const split = lensSplit(q, rMax);\n      const field: number[] = [];\n      let peak = 1e-3;\n      for (let j = 0; j < MAP_H; j++) {\n        for (let i = 0; i < MAP_W; i++) {\n          const dx = ((i + 0.5) / MAP_W) * STAGE_W - cx;\n          const dy = ((j + 0.5) / MAP_H) * STAGE_H - cy;\n          const g = lensFactor(q, Math.hypot(dx, dy) / LENS_RADIUS) / split - 1;\n          field.push(dx * g, dy * g);\n          peak = Math.max(peak, Math.abs(dx * g), Math.abs(dy * g));\n        }\n      }\n      const scale = peak * 2.02;\n      const img = ctx.createImageData(MAP_W, MAP_H);\n      for (let p = 0; p < MAP_W * MAP_H; p++) {\n        img.data[p * 4] = Math.round(255 * (0.5 + (field[2 * p] ?? 0) / scale));\n        img.data[p * 4 + 1] = Math.round(\n          255 * (0.5 + (field[2 * p + 1] ?? 0) / scale),\n        );\n        img.data[p * 4 + 2] = 128;\n        img.data[p * 4 + 3] = 255;\n      }\n      ctx.putImageData(img, 0, 0);\n      return { href: canvas.toDataURL(\"image/png\"), scale, split };\n    });\n    Promise.all(\n      out.map((m) => {\n        const im = new Image();\n        im.src = m.href;\n        return im.decode().catch(() => undefined);\n      }),\n    ).then(() => {\n      setMaps(out);\n      continueRender(handle);\n    });\n  }, []);\n  return maps;\n};\n\n/** Type at a fraction of a device row: two copies added by the fraction between. */\nconst Line: React.FC<{\n  y: number;\n  opacity: number;\n  px: number;\n  children: ReactNode;\n}> = ({ y, opacity, px, children }) => {\n  if (opacity <= 0) return null;\n  const row = Math.floor(y * px);\n  const f = y * px - row;\n  return (\n    <g opacity={opacity} style={{ isolation: \"isolate\" }}>\n      {[\n        { r: row, w: 1 - f },\n        { r: row + 1, w: f },\n      ].map(({ r, w }) => (\n        <g\n          key={r}\n          transform={`translate(${STAGE_W / 2} ${(r + 1e-3) / px})`}\n          style={{ opacity: w, mixBlendMode: \"plus-lighter\" }}\n        >\n          {children}\n        </g>\n      ))}\n    </g>\n  );\n};\n\nconst Card: React.FC<{\n  rect: readonly number[];\n  src: string;\n  halo: number;\n  opacity: number;\n  fill: string;\n}> = ({ rect, src, halo, opacity, fill }) => {\n  const [x = 0, y = 0, w = 0, h = 0] = rect;\n  if (opacity <= 0) return null;\n  return (\n    <div\n      style={{\n        position: \"absolute\",\n        left: x,\n        top: y,\n        width: w,\n        height: h,\n        opacity,\n        overflow: \"hidden\",\n        background: fill,\n        boxShadow: `0 0 ${halo}px ${halo * 0.6}px rgba(0,0,0,0.05)`,\n      }}\n    >\n      <Img\n        src={src}\n        style={{\n          width: \"100%\",\n          height: \"100%\",\n          maxWidth: \"none\",\n          objectFit: \"cover\",\n          display: \"block\",\n        }}\n      />\n    </div>\n  );\n};\n\n/**\n * Bloom Lockup: a wall of finished work blooms outward from your logo, cuts in\n * tight on it, then bends away through a lens and a flash as the logo rises to its wordmark. `t` is\n * seconds into the clip.\n */\nexport const BloomLockupScene: React.FC<BloomLockupProps & { t: number }> = ({\n  t,\n  wordmark = \"snapcn\",\n  tagline = \"snapcn.dev\",\n  logo = SNAPCN_MARK,\n  images = CARD_IMAGES,\n  imagesA,\n  imagesB,\n  wordmarkFont,\n  wordmarkWeight = 600,\n  wordmarkSize = 112,\n  theme,\n  mode,\n}) => {\n  const c = useSnapCnTheme(theme, mode);\n  const { width, height } = useVideoConfig();\n  const px = Math.max(width / STAGE_W, height / STAGE_H);\n  const bloom = t < BLOOM_SECONDS;\n  const b = t - BLOOM_SECONDS;\n  const pick = (list: readonly string[], i: number) =>\n    list[i % Math.max(1, list.length)] ?? \"\";\n\n  const size = bloom ? sample(LOGO_SIZE_BLOOM, t) : sample(LOGO_SIZE_LOCKUP, b);\n  const y = bloom ? STAGE_H / 2 : sample(LOGO_Y, b);\n  const zoom = bloom ? sample(BLOOM_ZOOM, t) : 1 + 0.00009 * (0.55 - b) * 60;\n  const lift = bloom ? 0 : -3.5 * (b - 0.4);\n  const uid = useId().replace(/:/g, \"\");\n  const maps = useLensMaps();\n  const row = bloom ? -1 : Math.round((b - LENS_FROM) * RATE);\n  const gone = row >= LENS.length;\n  const map = row >= 0 && !gone ? (maps?.[row] ?? null) : null;\n  const flash = bloom ? undefined : LENS_FLASH[row - (LENS.length - 2)];\n  const logoScale =\n    (size * ((\"fill\" in logo ? logo.fill : undefined) ?? 0.56)) /\n    Math.max(logo.width, logo.height);\n\n  return (\n    <AbsoluteFill style={{ background: c.background, overflow: \"hidden\" }}>\n      {map ? (\n        <svg width={0} height={0} style={{ position: \"absolute\" }} aria-hidden>\n          <filter\n            id={uid}\n            x={0}\n            y={0}\n            width={STAGE_W}\n            height={STAGE_H}\n            filterUnits=\"userSpaceOnUse\"\n            primitiveUnits=\"userSpaceOnUse\"\n            colorInterpolationFilters=\"sRGB\"\n          >\n            <feImage\n              href={map.href}\n              x={0}\n              y={0}\n              width={STAGE_W}\n              height={STAGE_H}\n              preserveAspectRatio=\"none\"\n              result=\"map\"\n            />\n            <feDisplacementMap\n              in=\"SourceGraphic\"\n              in2=\"map\"\n              scale={map.scale}\n              xChannelSelector=\"R\"\n              yChannelSelector=\"G\"\n              result=\"bent\"\n            />\n            {flash ? (\n              <>\n                <feComponentTransfer in=\"bent\" result=\"lit\">\n                  <feFuncR type=\"linear\" slope={flash[0]} />\n                  <feFuncG type=\"linear\" slope={flash[1]} />\n                  <feFuncB type=\"linear\" slope={flash[2]} />\n                </feComponentTransfer>\n                <feGaussianBlur in=\"lit\" stdDeviation={flash[3]} />\n              </>\n            ) : null}\n          </filter>\n        </svg>\n      ) : null}\n      <AbsoluteFill\n        style={{\n          filter: map ? `url(#${uid})` : undefined,\n        }}\n      >\n        <AbsoluteFill\n          style={{\n            transform: `translateY(${lift}px) scale(${\n              zoom * (map ? (LENS_ZOOM[row] ?? 1) / map.split : 1)\n            })`,\n            transformOrigin: \"50% 50%\",\n          }}\n        >\n          {bloom\n            ? BLOOM_CARDS.map((rect, i) =>\n                !imagesA && i === BEHIND_LOGO.bloom ? null : (\n                  <Card\n                    key={rect.join()}\n                    rect={rect}\n                    src={imagesA ? pick(imagesA, i) : pick(images, i)}\n                    halo={CARD_HALO.bloom}\n                    fill={c.card}\n                    opacity={cardFade(i, t)}\n                  />\n                ),\n              )\n            : !gone &&\n              LOCKUP_CARDS.map((rect, i) =>\n                !imagesB && i === BEHIND_LOGO.lockup ? null : (\n                  <Card\n                    key={rect.join()}\n                    rect={rect}\n                    src={imagesB ? pick(imagesB, i) : pick(images, i + 7)}\n                    halo={CARD_HALO.lockup}\n                    fill={c.card}\n                    opacity={1}\n                  />\n                ),\n              )}\n        </AbsoluteFill>\n      </AbsoluteFill>\n\n      <div\n        style={{\n          position: \"absolute\",\n          left: STAGE_W / 2 - size / 2,\n          top: y - size / 2,\n          width: size,\n          height: size,\n          borderRadius: size * 0.235,\n          background: c.foreground,\n          opacity: bloom ? sample(LOGO_FADE, t) : 1,\n          boxShadow: `0 ${size * 0.1}px ${size * 0.34}px rgba(0,0,0,0.22)`,\n        }}\n      >\n        <svg\n          viewBox={`0 0 ${size} ${size}`}\n          width={size}\n          height={size}\n          style={{ position: \"absolute\", inset: 0 }}\n        >\n          <title>{wordmark}</title>\n          <g\n            transform={`translate(${size / 2} ${size / 2}) scale(${logoScale}) translate(${-logo.width / 2} ${-logo.height / 2})`}\n          >\n            {logo.shapes.map((d) => (\n              <path key={d} d={d} fill={c.card} fillRule=\"evenodd\" />\n            ))}\n          </g>\n        </svg>\n      </div>\n\n      {!bloom && (\n        <svg\n          viewBox={`0 0 ${STAGE_W} ${STAGE_H}`}\n          width=\"100%\"\n          height=\"100%\"\n          style={{ position: \"absolute\", inset: 0 }}\n        >\n          <title>{tagline}</title>\n          <Line\n            y={WORDMARK_Y + sample(WORDMARK_RISE, b)}\n            opacity={sample(WORDMARK_FADE, b)}\n            px={px}\n          >\n            <text\n              textAnchor=\"middle\"\n              fill={c.foreground}\n              style={{\n                fontFamily: resolveFont(wordmarkFont) ?? POPPINS,\n                fontWeight: wordmarkWeight,\n                fontSize: wordmarkSize,\n                letterSpacing: \"-0.02em\",\n                textRendering: \"geometricPrecision\",\n              }}\n            >\n              {wordmark}\n            </text>\n          </Line>\n          <Line\n            y={TAGLINE_Y + sample(TAGLINE_RISE, b)}\n            opacity={sample(TAGLINE_FADE, b)}\n            px={px}\n          >\n            <text\n              textAnchor=\"middle\"\n              fill={c.mutedForeground}\n              style={{\n                fontFamily: GEIST_MONO,\n                fontSize: 40,\n                textRendering: \"geometricPrecision\",\n              }}\n            >\n              {tagline}\n            </text>\n          </Line>\n        </svg>\n      )}\n    </AbsoluteFill>\n  );\n};\n\nexport const BloomLockup: React.FC<BloomLockupProps> = ({\n  speed = 1,\n  ...props\n}) => {\n  const frame = useCurrentFrame();\n  const { fps } = useVideoConfig();\n  return <BloomLockupScene {...props} t={(frame * speed) / fps} />;\n};\n\nexport default BloomLockup;\n",
      "type": "registry:component",
      "target": "components/snap-cn/bloom-lockup/index.tsx"
    },
    {
      "path": "registry/snap-cn/bloom-lockup/data.ts",
      "content": "// Bloom Lockup · snapcn — https://snapcn.dev/docs/scenes/bloom-lockup\n/**\n * Measured frame by frame off a screen recording, scaled to a 1920x1080 stage with\n * the logo's first resting place at its centre. Tables hold one sample per 1/30s.\n */\n\n/** Length of the bloom, then of the lockup, in seconds. The join is a hard cut. */\nexport const BLOOM_SECONDS = 1.825;\nexport const LOCKUP_SECONDS = 2.063;\n/** The last frame holds this long. */\nexport const HOLD_SECONDS = 0.1;\n\n/** Cards on the bloom board: x, y, width, height. */\nexport const BLOOM_CARDS = [\n  [43.1, -65.8, 226.5, 221.1],\n  [310.0, -65.8, 229.2, 347.9],\n  [582.4, -65.8, 223.8, 172.6],\n  [846.7, -65.8, 229.2, 366.7],\n  [1116.3, -65.8, 226.5, 245.4],\n  [1653.0, -65.8, 226.5, 226.5],\n  [1386.0, 39.3, 226.5, 391.0],\n  [579.7, 147.2, 226.5, 391.0],\n  [43.1, 195.7, 226.5, 391.0],\n  [1653.0, 201.1, 226.5, 142.9],\n  [310.0, 322.5, 229.2, 151.0],\n  [1653.0, 384.5, 226.5, 124.0],\n  [1383.3, 473.5, 229.2, 207.6],\n  [310.0, 514.0, 229.2, 199.6],\n  [1653.0, 551.7, 229.2, 124.0],\n  [579.7, 592.2, 229.2, 453.0],\n  [40.4, 629.9, 229.2, 391.0],\n  [1113.6, 651.5, 229.2, 391.0],\n  [1653.0, 716.2, 229.2, 159.1],\n  [1383.3, 721.6, 229.2, 275.1],\n  [849.4, 729.7, 223.8, 110.6],\n  [310.0, 754.0, 229.2, 183.4],\n  [849.4, 880.7, 223.8, 264.3],\n  [1653.0, 915.7, 226.5, 229.2],\n  [310.0, 977.8, 229.2, 167.2],\n  [1383.3, 1037.1, 229.2, 107.9],\n  [849.4, 352.2, 223.8, 334.4],\n  [1116.3, 220.0, 226.5, 391.0],\n] as const;\n/** When each bloom card starts, in seconds: a wave leaving the logo. */\nexport const BLOOM_DELAY = [\n  0.669, 0.466, 0.366, 0.271, 0.406, 0.68, 0.388, 0.217, 0.548, 0.58, 0.348,\n  0.55, 0.34, 0.34, 0.552, 0.249, 0.577, 0.262, 0.583, 0.411, 0.166, 0.386,\n  0.317, 0.58, 0.567, 0.478, 0.071, 0.196,\n] as const;\n/** How long each bloom card takes to arrive. */\nexport const BLOOM_FADE = [\n  0.239, 0.409, 0.395, 0.334, 0.389, 0.298, 0.42, 0.414, 0.394, 0.42, 0.401,\n  0.37, 0.42, 0.412, 0.42, 0.42, 0.385, 0.42, 0.42, 0.384, 0.203, 0.42, 0.391,\n  0.42, 0.353, 0.42, 0.124, 0.42,\n] as const;\nexport const BLOOM_ZOOM = [\n  0.9847, 0.9848, 0.9848, 0.9849, 0.9849, 0.9849, 0.985, 0.985, 0.9851, 0.9851,\n  0.9852, 0.9852, 0.9852, 0.9853, 0.9853, 0.9854, 0.9854, 0.9854, 0.9855,\n  0.9855, 0.9856, 0.9856, 0.9856, 0.9857, 0.9857, 0.9858, 0.9858, 0.9858, 0.986,\n  0.9863, 0.9865, 0.9867, 0.9868, 0.987, 0.9874, 0.9877, 0.9879, 0.9883, 0.9887,\n  0.9892, 0.9897, 0.9903, 0.9909, 0.9916, 0.9922, 0.993, 0.9938, 0.9943, 0.9953,\n  0.9962, 0.9972, 0.9981, 0.9993, 1.0003, 1.0014, 1.0016,\n] as const;\n\n/** The same grid at 1.33x. */\nexport const LOCKUP_CARDS = [\n  [103.7, -61.8, 302.0, 231.9],\n  [457.0, -61.8, 302.0, 172.6],\n  [813.0, -61.8, 299.3, 83.6],\n  [1160.8, -61.8, 304.7, 563.6],\n  [1516.8, -61.8, 302.0, 196.9],\n  [1870.0, 56.9, 110.6, 358.7],\n  [810.3, 75.7, 302.0, 649.9],\n  [457.0, 164.7, 302.0, 275.1],\n  [-68.8, 175.5, 121.3, 512.4],\n  [1516.8, 186.3, 302.0, 364.0],\n  [106.4, 221.4, 299.3, 515.1],\n  [1870.0, 472.2, 110.6, 186.1],\n  [457.0, 488.3, 302.0, 288.5],\n  [1158.1, 545.0, 304.7, 596.0],\n  [1514.1, 604.3, 304.7, 229.2],\n  [1870.0, 712.2, 110.6, 164.5],\n  [-68.8, 741.8, 121.3, 399.1],\n  [103.7, 790.4, 302.0, 199.6],\n  [807.6, 820.0, 304.7, 218.4],\n  [454.3, 828.1, 304.7, 312.8],\n  [1516.8, 884.7, 463.8, 256.2],\n  [106.4, 1041.1, 299.3, 99.8],\n] as const;\n/**\n * The wall leaves through a lens, then a flash, then a cut to the bare page. One row\n * per frame from `LENS_FROM` seconds into the lockup. A point `r` radii out shows what\n * sat at `r / sqrt(1 + q r^2)`: the edges stretch and the middle pulls back.\n */\nexport const LENS_FROM = 0.02;\nexport const LENS_RADIUS = 960;\nexport const LENS = [\n  0.01313, 0.01484, 0.01758, 0.02186, 0.02722, 0.03385, 0.04192, 0.05143,\n  0.06274, 0.07689, 0.09468, 0.11714, 0.14713, 0.19098, 0.25382, 0.34701,\n  0.5287, 1.56386,\n] as const;\nexport const LENS_ZOOM = [\n  1.0, 0.99627, 0.9925, 0.98863, 0.98457, 0.98025, 0.97571, 0.97095, 0.96603,\n  0.96092, 0.95548, 0.94957, 0.94291, 0.93499, 0.92518, 0.91473, 0.89903,\n  0.85653,\n] as const;\n/** The last two rows: channel gain and blur in stage px. */\nexport const LENS_FLASH = [\n  [1.424, 1.491, 1.47, 1.67],\n  [1.403, 1.45, 1.437, 1.79],\n] as const;\n\n/** The slot under the logo on each board stays empty unless you fill it. */\nexport const BEHIND_LOGO = { bloom: 26, lockup: 6 } as const;\n\nexport const CARD_HALO = { bloom: 12, lockup: 16 } as const;\n\nexport const LOGO_FADE = [\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0.089, 0.204, 0.379, 0.541, 0.737, 0.834, 0.91,\n  0.971, 0.981, 0.997, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n] as const;\nexport const LOGO_SIZE_BLOOM = [\n  143.9, 144.3, 145, 145.6, 146.1, 146.8, 147.4, 148, 148.8, 149.4, 150, 150.6,\n  151.1, 151.6, 152.2, 152.8, 153.3, 153.5, 154, 154.9, 156, 156.8, 157.3,\n  157.6, 157.7, 157.8, 157.8, 157.9, 157.9, 158, 158, 158, 158, 158, 158, 158,\n  158.1, 158.1, 158.2, 158.2, 158.3, 158.4, 158.4, 158.3, 158.3, 158.4, 158.4,\n  158.5, 158.9, 159.2, 159.6, 160, 160.4, 160.7, 160.8, 160.8,\n] as const;\nexport const LOGO_SIZE_LOCKUP = [\n  210.2, 210, 210, 210, 210, 210, 210.1, 210.1, 210, 210, 210, 210, 210.1,\n  210.2, 210.4, 210.5, 210.5, 210.6, 210.6, 210.6, 210.6, 210.6, 210.6, 210.6,\n  210.7, 210.7, 210.8, 210.8, 210.8, 210.9, 210.9, 211, 211, 211.1, 211.1,\n  211.2, 211.3, 211.3, 211.4, 211.4, 211.4, 211.5, 211.6, 211.7, 211.8, 212,\n  212.1, 212.3, 212.5, 212.7, 212.9, 213, 213.1, 213.3, 213.4, 213.5, 213.5,\n  213.6, 213.6, 213.6, 213.6, 213.6, 213.6,\n] as const;\nexport const LOGO_Y = [\n  540.4, 533.2, 516.9, 502.5, 492.3, 485.4, 473.4, 459.9, 452.1, 442, 437.3,\n  432.8, 428, 422.9, 418.6, 415.4, 414, 412.3, 411.6, 410.7, 409.9, 409.4,\n  409.2, 408.8, 408.6, 408.5, 408.4, 408.4, 408.3, 408.3, 408.3, 408.2, 408.2,\n  408.2, 408.2, 408.1, 408.1, 408, 407.9, 407.8, 407.8, 407.8, 407.7, 407.5,\n  407.4, 407.3, 407.3, 407.3, 407.1, 407, 406.9, 406.9, 406.9, 406.9, 406.8,\n  406.8, 406.7, 406.7, 406.7, 406.7, 406.7, 406.7, 406.7,\n] as const;\n\nexport const WORDMARK_Y = 653.6;\nexport const TAGLINE_Y = 715.7;\nexport const WORDMARK_FADE = [\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.006, 0.023, 0.161,\n  0.291, 0.432, 0.588, 0.676, 0.734, 0.789, 0.821, 0.85, 0.878, 0.898, 0.928,\n  0.935, 0.941, 0.946, 0.953, 0.969, 0.973, 0.975, 0.975, 0.976, 0.977, 0.977,\n  0.977, 0.979, 0.98, 0.982, 0.983, 0.984, 0.986, 0.987, 0.988, 0.989, 0.99,\n  0.992, 0.993, 0.994, 0.995, 0.996, 0.998, 0.999, 1,\n] as const;\nexport const WORDMARK_RISE = [\n  17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 17.5,\n  17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 15.9, 11.7, 9,\n  7.4, 5.8, 4.7, 4, 3.1, 2.4, 1.8, 1.3, 0.7, 0.6, 0.6, 0.6, 0.1, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n] as const;\nexport const TAGLINE_FADE = [\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.001, 0.06, 0.169, 0.353, 0.474,\n  0.596, 0.674, 0.791, 0.853, 0.911, 0.957, 0.975, 0.981, 0.982, 0.986, 0.988,\n  0.996, 0.999, 0.999, 0.999, 1, 1, 1,\n] as const;\nexport const TAGLINE_RISE = [\n  11.9, 11.9, 11.9, 11.9, 11.9, 11.9, 11.9, 11.9, 11.9, 11.9, 11.9, 11.9, 11.9,\n  11.9, 11.9, 11.9, 11.9, 11.9, 11.9, 11.9, 11.9, 11.9, 11.9, 11.9, 11.9, 11.9,\n  11.9, 11.9, 11.9, 11.9, 11.9, 11.9, 11.9, 11.9, 11.9, 11.9, 11.9, 11.9, 11.9,\n  11.9, 11.9, 11.9, 11.9, 11.9, 9.3, 5.9, 4.5, 2.2, 0.9, 0.2, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0,\n] as const;\n\n/** What fills the cards: snapcn showcase art and Unsplash-licensed photographs. */\nexport const CARD_IMAGES = [\n  \"https://media.snapcn.dev/demos/showcase/821d815affa6496c39cbdeeec7a84603.jpg\",\n  \"https://media.snapcn.dev/demos/showcase/stock-716.webp\",\n  \"https://media.snapcn.dev/demos/showcase/stock-888.webp\",\n  \"https://media.snapcn.dev/demos/showcase/937438c560ada1c83317f2c11b3454b0.jpg\",\n  \"https://media.snapcn.dev/demos/showcase/stock-896.webp\",\n  \"https://media.snapcn.dev/demos/showcase/stock-903.webp\",\n  \"https://media.snapcn.dev/demos/showcase/98f89cb9994f5c382ab964062c4039db.jpg\",\n  \"https://media.snapcn.dev/demos/showcase/stock-901.webp\",\n  \"https://media.snapcn.dev/demos/showcase/stock-906.webp\",\n  \"https://media.snapcn.dev/demos/showcase/b25b82db2892efff9be3204e860d30ee.jpg\",\n  \"https://media.snapcn.dev/demos/showcase/stock-909.webp\",\n  \"https://media.snapcn.dev/demos/showcase/stock-912.webp\",\n  \"https://media.snapcn.dev/demos/showcase/5e5305b05bd405a0d89570725434099e.webp\",\n  \"https://media.snapcn.dev/demos/showcase/stock-564.webp\",\n  \"https://media.snapcn.dev/demos/showcase/stock-402.webp\",\n  \"https://media.snapcn.dev/demos/showcase/438b9e6b50654a44d404fbf358c26e9f.webp\",\n  \"https://media.snapcn.dev/demos/showcase/stock-769.webp\",\n  \"https://media.snapcn.dev/demos/showcase/stock-788.webp\",\n  \"https://media.snapcn.dev/demos/showcase/767d99bb371a54d0d36751e8cecae43c.jpg\",\n  \"https://media.snapcn.dev/demos/showcase/stock-830.webp\",\n  \"https://media.snapcn.dev/demos/showcase/stock-741.webp\",\n  \"https://media.snapcn.dev/demos/showcase/c9ebc6337aa2268ac4b357f9cb1ac547.jpg\",\n  \"https://media.snapcn.dev/demos/showcase/stock-953.webp\",\n  \"https://media.snapcn.dev/demos/showcase/stock-857.webp\",\n  \"https://media.snapcn.dev/demos/showcase/stock-1016.webp\",\n  \"https://media.snapcn.dev/demos/showcase/stock-1019.webp\",\n  \"https://media.snapcn.dev/demos/showcase/stock-631.webp\",\n  \"https://media.snapcn.dev/demos/showcase/stock-396.webp\",\n] as const;\n\n/** The snapcn mark, outlined. */\nexport const SNAPCN_MARK = {\n  width: 723,\n  height: 632,\n  shapes: [\n    \"M92.2 44.6C66.0 51.0 44.4 67.9 32.7 91.1C23.3 109.8 23.5 104.2 23.5 284.9C23.5 442.1 23.6 450.7 26.4 459.0C34.0 482.0 49.6 494.3 78.2 500.0C93.9 503.1 98.1 505.1 107.3 513.6C115.6 521.2 118.9 530.6 118.9 546.7C119.1 565.7 125.5 577.4 139.7 584.9L147.9 589.1L301.2 589.6C439.4 590.1 455.5 589.8 464.3 587.6C476.0 584.3 485.1 577.1 491.0 565.8L495.3 557.8L495.7 508.6C496.0 481.5 496.0 455.0 495.7 450.0L495.3 440.6L490.4 448.5C484.8 457.7 474.6 466.5 463.8 471.3L456.1 474.9L329.4 475.4C236.9 475.7 200.3 475.4 194.0 474.1C174.0 469.8 153.7 455.2 143.2 437.5C133.0 420.3 132.9 417.5 133.3 308.3L133.8 210.5L137.5 201.4C144.4 184.0 160.5 168.5 179.8 160.9L188.6 157.3L318.4 156.8C445.0 156.5 448.5 156.5 458.5 159.6C471.0 163.5 481.8 171.2 489.5 181.8L495.3 190.0L495.7 137.7C496.2 80.3 495.3 72.3 487.0 60.4C482.3 53.5 471.6 46.2 463.2 43.8C459.7 42.9 391.7 42.2 279.3 42.4C134.9 42.6 99.2 42.9 92.2 44.6ZM594.6 173.2C543.5 203.9 501.0 229.7 500.4 230.7C499.8 231.6 499.3 270.4 499.6 316.7L500.0 401.2L522.6 415.5C535.2 423.3 555.2 435.8 567.2 443.1C579.3 450.5 611.5 470.4 638.7 487.3C666.0 504.2 689.8 517.9 691.5 517.9C693.2 517.9 695.7 516.9 697.0 515.4C699.1 513.3 699.5 493.4 699.5 319.2C699.5 197.0 698.8 123.9 697.9 121.4C696.8 118.3 695.4 117.4 692.1 117.4C689.3 117.5 655.8 136.6 594.6 173.2Z\",\n  ],\n} as const;\n",
      "type": "registry:component",
      "target": "components/snap-cn/bloom-lockup/data.ts"
    }
  ],
  "docs": "Docs and props: https://snapcn.dev/docs/scenes/bloom-lockup?ref=cli — 120 frames at 30fps; paints its own background. Pass your logo as SVG paths (logo={{ width, height, shapes }}) and your screens as images. — 82 Pro components too — charts, launch scenes, device shots: https://snapcn.dev/docs/pricing?ref=cli-docs",
  "type": "registry:component"
}
