Skip to content
filedom
Esc
↑↓navigate↵open⌘Jpreview
On this page

Layout

fitIconSize, centerBoard, createGrid, distribute: sizing and point math for boards made of icons.

Desktop icons are placed at absolute x/y points, so layout in filedom means computing points: pick an icon size, center a board, then map cells to points. These helpers do that math.

fitIconSize

Returns the largest icon size that fits cols × rows icon units inside a fraction of the desktop, clamped to [min, max]. It takes the smaller of the width-limited and height-limited sizes, so the board fits on both axes.

import { fitIconSize, MAX_DESKTOP_ICON_SIZE } from 'filedom';

const iconSize = fitIconSize({
  metrics,               // SystemMetrics (width/height used)
  widthFraction: 0.6,    // board may occupy 60% of screen width…
  heightFraction: 0.8,   // …and 80% of its height
  cols: 10,
  rows: 20,
  min: 24,
  // max defaults to MAX_DESKTOP_ICON_SIZE (128)
  // gap: px shaved off so the *icon* (not the cell) is the fitted size
});

cols and rows are icon units and may be fractional. Solitaire passes cols * cardAspect * 1.18 to allow for non-square cards and spacing.

centerBoard

Returns the top-left offset that centers a boardW × boardH box on the desktop. top reserves that many pixels at the top (for the menu bar or a HUD row) and excludes them from centering. Results are floored to whole pixels.

const { offsetX, offsetY } = centerBoard({ metrics, boardW, boardH, top: 64 });

createGrid

A uniform grid addressed by cell. cellCenter(col, row) gives the point to move a sprite to, and pointToCell(x, y) reverses it for click hit-testing. Both are pure functions. The grid has no knowledge of icons, stages or parking, and computing a point never mounts or unmounts anything.

import { createGrid } from 'filedom';

const grid = createGrid({
  cols: 8, rows: 8,
  cell: iconSize + gap,             // per-cell pitch, not the icon size
  origin: { x: offsetX, y: offsetY }, // top-left of cell (0,0)'s box
});

grid.cellCenter(3, 4);       // -> { x, y } for a sprite's `at`
grid.indexCenter(12);        // row-major flat index variant
grid.pointToCell(px, py);    // -> { col, row } | null (outside the board)
grid.boardRect;              // { x, y, width, height } for frames/backgrounds

boardRect spans cols × rows whole cells. If cell includes a gap, the rectangle includes the gap after the last cell too.

distribute

Returns count evenly spaced points centered on center along one axis, each at the fixed cross coordinate on the other axis. Spacing is center to center, so a step smaller than the item width gives an overlapping fan, such as a hand of cards. Flexbox can’t express this because its gap is positive only.

import { distribute } from 'filedom';

const handSlots = distribute({ count: 5, step: iconSize * 0.55, center: cx, cross: handY });
// axis: 'x' (default) or 'y'

Was this page helpful?