let’s make the ZIP export all final logo variants in high-res, like your “Versions & Usage” page:

PNG Logo (transparent)

PNG Reverse Logo (light-on-dark)

JPG Logo (no transparency, brand background)

Text Logo (wordmark only, transparent)

PNG Icon (icon only, transparent)

PNG Reverse Icon (icon on dark)

…and generate them at multiple large sizes (e.g. 1000, 2000, 3000 px wide for crisp 300-ppi print at common widths).

Below is a drop-in implementation that extends your ZIP builder. It uses your existing generatedSvgUrl, name, palette, fontFamily, textSize, and layout.

1) Add these helpers (inside your page or a /services/export/logoAssets.ts util)
type RenderOpts = {
  width: number;              // output width in px
  bg?: string | null;         // background fill (null = transparent)
  withIcon: boolean;
  withText: boolean;
  layout: "side-by-side" | "top-bottom";
  iconSize?: number;          // px
  textSize?: number;          // px
  textColor: string;          // hex
  fontFamily: string;         // CSS font family
  name: string;               // brand name
  svgUrl?: string | null;     // icon SVG/PNG data URL
  pad?: number;               // padding around composition
};

// raster renderer (returns Blob)
async function renderLogoPNG(opts: RenderOpts): Promise<Blob> {
  const {
    width, bg = null, withIcon, withText, layout,
    iconSize = 300, textSize = 160, textColor, fontFamily, name, svgUrl, pad = 64,
  } = opts;

  // generous height to keep 300ppi-friendly aspect
  const height = Math.round(width * (layout === "side-by-side" ? 0.5 : 0.75));
  const canvas = document.createElement("canvas");
  const ctx = canvas.getContext("2d")!;
  canvas.width = width; canvas.height = height;

  // background (or transparent)
  if (bg) { ctx.fillStyle = bg; ctx.fillRect(0, 0, width, height); }
  else { ctx.clearRect(0,0,width,height); }

  const centerX = width / 2;
  const centerY = height / 2;

  let iconDrawn = false;
  if (withIcon && svgUrl) {
    const img = new Image(); img.crossOrigin = "anonymous";
    await new Promise<void>((res) => { img.onload = () => res(); img.onerror = () => res(); img.src = svgUrl; });
    if (layout === "side-by-side") {
      const total = iconSize + (withText ? pad : 0);
      const x = withText ? centerX - total/2 : centerX - iconSize/2;
      ctx.drawImage(img, x, centerY - iconSize/2, iconSize, iconSize);
    } else {
      ctx.drawImage(img, centerX - iconSize/2, centerY - (withText ? (iconSize/2 + pad/2) : iconSize/2), iconSize, iconSize);
    }
    iconDrawn = true;
  }

  if (withText) {
    ctx.fillStyle = textColor;
    ctx.font = `bold ${textSize}px ${fontFamily}`;
    ctx.textBaseline = "alphabetic";
    ctx.textAlign = layout === "side-by-side" ? "left" : "center";
    const metrics = ctx.measureText(name);
    if (layout === "side-by-side") {
      const x = iconDrawn ? centerX + (pad/2) : centerX - metrics.width/2;
      const y = centerY + (iconDrawn ? iconSize/2 : textSize/2);
      ctx.fillText(name, x, y);
    } else {
      ctx.fillText(name, centerX, centerY + iconSize/2 + textSize/2);
    }
  }

  return await new Promise<Blob>((resolve) => canvas.toBlob((b) => resolve(b!), "image/png"));
}

// JPG helper (flatten on chosen background)
async function renderLogoJPG(opts: Omit<RenderOpts, "bg"> & { bg: string; quality?: number }): Promise<Blob> {
  const blobPng = await renderLogoPNG({ ...opts, bg: opts.bg });
  const img = await blobToImage(blobPng);
  const canvas = document.createElement("canvas");
  const ctx = canvas.getContext("2d")!;
  canvas.width = img.width; canvas.height = img.height;
  ctx.drawImage(img, 0, 0);
  return await new Promise<Blob>((resolve) => canvas.toBlob((b) => resolve(b!), "image/jpeg", opts.quality ?? 0.92));
}

function blobToImage(blob: Blob): Promise<HTMLImageElement> {
  return new Promise((resolve) => {
    const url = URL.createObjectURL(blob);
    const img = new Image();
    img.onload = () => { URL.revokeObjectURL(url); resolve(img); };
    img.src = url;
  });
}