{"record":{"id":"e05a8c271a771fb1","repo":"different-ai/openwork","slug":"use-a-square-image-for-the-app-icon","errorCode":null,"errorMessage":"Use a square image for the app icon.","messagePattern":"Use a square image for the app icon\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"ee/apps/den-web/app/(den)/dashboard/_components/brand-appearance-screen.tsx","lineNumber":47,"sourceCode":"};\n\nasync function createBrandAssetDraft(file: File, kind: BrandAssetKind): Promise<BrandAssetDraft> {\n  if (file.type !== \"image/png\" && file.type !== \"image/jpeg\") throw new Error(\"Use a PNG or JPEG image.\");\n  if (file.size > BRAND_ASSET_MAX_BYTES) throw new Error(\"Use an image under 2 MB.\");\n\n  let image: ImageBitmap;\n  try {\n    image = await createImageBitmap(file);\n  } catch {\n    throw new Error(\"OpenWork could not decode that image.\");\n  }\n\n  const { width, height } = image;\n  image.close();\n  if (width > 4096 || height > 4096) throw new Error(\"Use an image no larger than 4096×4096 pixels.\");\n  if (kind === \"icon\") {\n    if (width < 64 || height < 64) throw new Error(\"Use a square icon at least 64×64 pixels.\");\n    if (width !== height) throw new Error(\"Use a square image for the app icon.\");\n  } else {\n    const aspectRatio = width / height;\n    if (width < 128 || height < 32) throw new Error(\"Use a wordmark at least 128×32 pixels.\");\n    if (aspectRatio < 1.5 || aspectRatio > 8) throw new Error(\"Use a horizontal wordmark between 1.5:1 and 8:1.\");\n  }\n\n  return { file, previewUrl: URL.createObjectURL(file), width, height };\n}\n\nfunction BrandAssetUploadField({\n  kind,\n  title,\n  description,\n  currentUrl,\n  managedAsset,\n  draft,\n  clearPending,\n  disabled,","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-web/app/(den)/dashboard/_components/brand-appearance-screen.tsx#L29-L65","documentation":"For kind === \"icon\", the image must be perfectly square (width === height). Non-square icons are rejected because the icon is displayed in square containers and non-square art would be distorted or cropped unpredictably.","triggerScenarios":"Uploading a rectangular image as an app icon — e.g. a 400×300 logo lockup, a 1920×1080 banner, or a 512×480 icon export with rounding differences.","commonSituations":"Using a company logo (usually horizontal) as the icon instead of a dedicated square mark; exporting a non-square frame from Figma; canvas exports with odd padding.","solutions":["Export the square icon mark (e.g. 512×512) rather than the full horizontal logo.","In the design tool, set the frame to equal width/height and center the artwork with padding.","Crop the image to a square (center crop) before upload.","Note the 64×64 minimum still applies — use e.g. 512×512 to satisfy both checks."],"exampleFix":"// before\nawait draft(logoLockup /* 800x300 */, \"icon\");\n// after\nconst square = centerCropToSquare(logoLockup); // 300x300 or scaled 512x512\nawait draft(square, \"icon\");","handlingStrategy":"validation","validationCode":"async function isSquareIcon(file: File): Promise<boolean> {\n  const bmp = await createImageBitmap(file);\n  const ok = bmp.width === bmp.height && bmp.width >= 64;\n  bmp.close();\n  return ok;\n}","typeGuard":null,"tryCatchPattern":"try {\n  const asset = await createBrandAssetDraft(file, \"icon\");\n} catch (error) {\n  showToast(error instanceof Error ? error.message : \"Could not use that image.\");\n}","preventionTips":["Maintain a dedicated square icon mark separate from the horizontal logo","Center-crop to square automatically before uploading when the user picks a rectangular image","Set the design frame to exact square dimensions before export","Verify width === height in preview thumbnails before submission"],"tags":["image-validation","dimensions","icon","aspect-ratio"],"backgroundTag":"invalid-image-dimensions","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}