Skip to main content

Overview

The getVisualCenterTransform() function computes a CSS transform string that shifts a logo to align by its visual center rather than its geometric bounds. Use this when rendering normalized logos to achieve better optical alignment, especially for logos with asymmetric visual weight distribution.

Signature

function getVisualCenterTransform(
  logo: NormalizedLogo,
  alignBy?: AlignmentMode
): string | undefined

Parameters

The normalized logo object returned from the engine’s normalizedLogos array.Must include the visualCenter property (computed during processing if densityAware is enabled).
alignBy
AlignmentMode
default:"'bounds'"
The alignment mode to use:
  • 'bounds' — No transform, align by geometric center (bounding box)
  • 'visual-center' — Align by visual weight center on both X and Y axes
  • 'visual-center-x' — Align by visual center horizontally only
  • 'visual-center-y' — Align by visual center vertically only (recommended for horizontal logo strips)

Return Value

Returns a CSS transform string in the format translate(Xpx, Ypx), or undefined if:
  • alignBy is 'bounds'
  • The logo has no visualCenter data
  • The computed offset is too small to matter (< 0.5px)

Alignment Modes

bounds
No transformation. Logos align by their geometric bounding box center.Use when you want consistent mathematical spacing without optical adjustments.
visual-center
Full visual alignment. Shifts logos both horizontally and vertically to align by visual weight center.Best for grid layouts or centered single logos.
visual-center-x
Horizontal visual alignment only. Shifts logos left/right to align by visual weight center, but maintains geometric vertical alignment.Useful for vertical logo stacks.
visual-center-y
Vertical visual alignment only (recommended default). Shifts logos up/down to align by visual weight center, but maintains geometric horizontal alignment.Perfect for horizontal logo strips — the most common layout. Prevents heavy/bold logos from appearing to sink and light/thin logos from appearing to float.

Usage Examples

Basic Usage

import {
  createLogoSoup,
  getVisualCenterTransform,
} from '@sanity-labs/logo-soup';

const engine = createLogoSoup();

engine.subscribe(() => {
  const { normalizedLogos } = engine.getSnapshot();
  
  normalizedLogos.forEach((logo) => {
    const transform = getVisualCenterTransform(logo, 'visual-center-y');
    console.log(`${logo.alt}: ${transform ?? 'none'}`);
    // Output: "Acme Corp: translate(0px, -2.3px)"
  });
});

engine.process({
  logos: ['/acme.svg', '/globex.svg'],
  densityAware: true, // Required for visual center computation
});

React Component

import { useLogoSoup } from '@sanity-labs/logo-soup/react';
import { getVisualCenterTransform } from '@sanity-labs/logo-soup';

function LogoGrid() {
  const { isReady, normalizedLogos } = useLogoSoup({
    logos: ['/logo1.svg', '/logo2.svg', '/logo3.svg'],
    baseSize: 64,
  });
  
  if (!isReady) return <div>Loading...</div>;
  
  return (
    <div className="grid grid-cols-3 gap-8">
      {normalizedLogos.map((logo) => (
        <img
          key={logo.src}
          src={logo.src}
          alt={logo.alt}
          width={logo.normalizedWidth}
          height={logo.normalizedHeight}
          style={{
            transform: getVisualCenterTransform(logo, 'visual-center'),
          }}
        />
      ))}
    </div>
  );
}
import { useLogoSoup } from '@sanity-labs/logo-soup/react';
import { getVisualCenterTransform } from '@sanity-labs/logo-soup';

function LogoStrip() {
  const { isReady, normalizedLogos } = useLogoSoup({
    logos: ['/acme.svg', '/globex.svg', '/initech.svg'],
    baseSize: 48,
  });
  
  if (!isReady) return null;
  
  return (
    <div className="flex items-center gap-6">
      {normalizedLogos.map((logo) => (
        <img
          key={logo.src}
          src={logo.src}
          alt={logo.alt}
          width={logo.normalizedWidth}
          height={logo.normalizedHeight}
          style={{
            // Align by visual center vertically, bounds horizontally
            transform: getVisualCenterTransform(logo, 'visual-center-y'),
          }}
        />
      ))}
    </div>
  );
}

Vue Component

<script setup>
import { useLogoSoup } from '@sanity-labs/logo-soup/vue';
import { getVisualCenterTransform } from '@sanity-labs/logo-soup';

const { isReady, normalizedLogos } = useLogoSoup({
  logos: ['/logo1.svg', '/logo2.svg'],
  baseSize: 56,
});
</script>

<template>
  <div v-if="isReady" class="flex gap-4">
    <img
      v-for="logo in normalizedLogos"
      :key="logo.src"
      :src="logo.src"
      :alt="logo.alt"
      :width="logo.normalizedWidth"
      :height="logo.normalizedHeight"
      :style="{
        transform: getVisualCenterTransform(logo, 'visual-center-y'),
      }"
    />
  </div>
</template>

Conditional Transform

const logo = normalizedLogos[0];
const transform = getVisualCenterTransform(logo, 'visual-center-y');

if (transform) {
  // Apply transform — logo needs adjustment
  element.style.transform = transform;
} else {
  // No transform needed — logo is already well-aligned
  element.style.transform = 'none';
}

How It Works

  1. Computes scale factors based on the logo’s normalized dimensions and original/cropped size
  2. Calculates offsets from the visual center data (stored in logo.visualCenter.offsetX and offsetY)
  3. Applies axis filtering based on the alignment mode
  4. Rounds offsets to 0.1px precision to avoid subpixel rendering issues
  5. Returns undefined if the offset is negligible (< 0.5px)

Visual Center Data

The visualCenter property is computed during processing when densityAware: true (default):
type VisualCenter = {
  x: number;       // Visual center X coordinate in pixels
  y: number;       // Visual center Y coordinate in pixels
  offsetX: number; // Horizontal offset from geometric center
  offsetY: number; // Vertical offset from geometric center
};
If densityAware is false or visual center detection fails, the logo will not have this property and the function returns undefined.

When to Use Each Mode

LayoutRecommended ModeReason
Horizontal stripvisual-center-yPrevents sinking/floating effect
Vertical stackvisual-center-xAligns asymmetric logos
Gridvisual-centerFull optical alignment
Tight mathematical layoutboundsConsistent geometric spacing

Performance

This function performs simple arithmetic operations and is safe to call on every render. The computation is deterministic and does not trigger any side effects.

Build docs developers (and LLMs) love