MaxRectsPacker

repository·master·Indexed 42 days ago

https://github.com/soimy/maxrects-packer

A 2D bin packing library for packing glyphs or images into multiple sprite-sheets or atlases. Version 2.7.4 features a MaxRects algorithm that optimizes for a minimum number of bins under specific size constraints, making it ideal for WebGL and browser assets. It supports power-of-two (POT) rounding, 90-degree rotation, tag-based group packing, and automatic handling of oversized rectangles.

Tokens
6.3K
Snippets
19
Records
28
Agent score
52%

What's inside maxrects-packer

  1. Handling oversized rectangles

    master
    If a rectangle is added that is larger than the specified maxWidth or maxHeight, the packer will create a special bin containing only that single rectangle. This rectangle will have an oversized: true flag in its data. Developers should check for this flag to handle assets that cannot fit within standard atlas constraints.
  2. How tag-based group packing works

    master
    If options.tag is set to true, the packer looks for a tag: string property on the input objects. All objects sharing the same tag value will be packed into the same bin. This is useful for grouping related assets together in a single atlas.
  3. Configure MaxRectsPacker options

    master

    When instantiating new MaxRectsPacker(maxWidth, maxHeight, padding, options), you can provide an options object to control packing behavior:

    • smart: (boolean, default true) Packs with the smallest possible size.
    • pot: (boolean, default true) Rounds bin size up to the smallest power of 2.
    • square: (boolean, default false) Forces bin sizes to always be square.
    • allowRotation: (boolean, default false) Allows 90-degree rotation of rectangles to improve packing efficiency.
    • tag: (boolean, default false) Enables tag-based group packing.
    • exclusiveTag: (boolean, default true) If false, the packer tries to put tagged rectangles into the same bin. If true, tagged rects will have dependent bins.
    • border: (number, default 0) Sets the atlas edge spacing.
    • logic: (number, default 1) Determines how free spaces are selected:
      • 0: MAX_AREA (selects free space with smallest loss of area).
      • 1: MAX_EDGE (selects free space with smallest loss of width or height).
      • 2: FILL_WIDTH (fills complete width first before next row).
  4. Use tag-based group packing

    master

    You can restrict a MaxRectsBin to only accept specific types of rectangles using tags. This is useful when you want to pack different categories of items into different bins.

    1. Set tag: true in the IOption object.
    2. If exclusiveTag is true (default), the bin will only accept rectangles where the rect.tag or rect.data.tag matches the bin.tag.
    3. If a rectangle's tag does not match, bin.add() will return undefined and the rectangle will not be placed.
    // Create a bin specifically for 'blue' items
    const blueBin = new MaxRectsBin(1000, 1000, 0, { tag: true, exclusiveTag: true });
    blueBin.tag = 'blue';
    
    // This will work
    blueBin.add(50, 50, { tag: 'blue' });
    
    // This will return undefined and not be added
    blueBin.add(50, 50, { tag: 'red' });
  5. How tag-based grouping works

    master

    When options.tag is set to true, the packer uses tags to organize rectangles.

    • Tag Detection: The packer looks for a tag in rect.tag or rect.data.tag.
    • Exclusive Tagging (exclusiveTag: true): Each unique tag will trigger the creation of a new bin. This ensures that items with different tags never share a bin.
    • Grouped Tagging (exclusiveTag: false): The packer will attempt to find an existing bin that already contains rectangles with the same tag before creating a new one. This is useful for grouping related assets (like a specific sprite sheet) into a single atlas.

    When using addArray(), the packer will sort the input by tags to optimize this grouping process.

  6. Understand MaxRectsBin packing logic

    master

    The logic option in MaxRectsBin determines how the algorithm selects the best available free rectangle for a new item. This is controlled via the PACKING_LOGIC enum.

    Available Logics

    • MAX_EDGE (Default): Chooses the rectangle that results in the lowest loss of either width or height (minimizes the remaining dimension gap).
    • MAX_AREA: Chooses the free rectangle that results in the smallest remaining area after placement.
    • FILL_WIDTH: A specialized logic that prioritizes rectangle position (lower Y, then higher X) and minimizes the additional height required to accommodate the new rectangle.
  7. Quickstart: Basic usage of MaxRectsPacker

    master

    To use MaxRectsPacker, import the class, initialize it with bin constraints and options, and then add rectangles using addArray or add.

    Important Migration Notes:

    • Since v2.0.0, use import { MaxRectsPacker } from 'maxrects-packer' or require('maxrects-packer').MaxRectsPacker.
    • Since v2.1.0, you can pass any object with width and height properties (no need for a specific schema).
    • The Rectangle constructor order is (width, height, x, y, rotated).
    let MaxRectsPacker = require("maxrects-packer").MaxRectsPacker;
    const options = {
        smart: true,
        pot: true,
        square: false,
        allowRotation: true,
        tag: false,
        border: 5
    };
    
    // width, height, padding, options
    let packer = new MaxRectsPacker(1024, 1024, 2, options);
    
    let input = [
        {width: 600, height: 20, name: "tree"},
        {width: 600, height: 20, name: "flower"},
        {width: 1000, height: 1000, name: "background"}
    ];
    
    packer.addArray(input);
    
    // Access the resulting bins
    packer.bins.forEach(bin => {
        console.log(bin.rects);
    });
  8. MaxRectsPacker API Reference

    master

    The MaxRectsPacker class provides the following methods for managing the packing process:

    • new MaxRectsPacker(maxWidth, maxHeight, [padding, options]): Creates a new packer instance. maxWidth and maxHeight are applied to all bins.
    • add(width, height, data) or add({width, height, ...}): Adds a single rectangle. data can be any object and will be stored with the rectangle's position.
    • addArray(rects[]): Adds multiple rectangles at once. This is more efficient than multiple add() calls because input is automatically sorted.
    • next(): Stops adding elements to the current bin and starts a new bin. Subsequent elements will not be added to previous bins.
    • repack(quick = true): Repacks elements. If quick is true, only dirty bins are repacked. If false, all rects are re-sorted and repacked for higher efficiency (slower).
    • save(): Returns an array of objects representing current bin settings and free areas. Useful for persisting state via JSON.stringify().
    • load(bins): Restores settings from a previously saved array (e.g., from JSON.parse()). Allows continuing packing without overlapping previous areas.

    Properties:

    • bins: An array of bin objects. Each bin has width, height, and a rects array.
    • bins[n].rects: An array of rectangle objects. Each rect contains x, y, width, height, rot, data, and an optional oversized flag (set to true if the rect exceeds maxWidth or maxHeight).
  9. Configure MaxRectsBin options

    master

    The MaxRectsBin constructor accepts an IOption object to control packing behavior.

    OptionTypeDefaultDescription
    smartbooleantrueIf true, the bin automatically expands its width/height to fit rectangles up to maxWidth/maxHeight.
    potbooleantrueIf true, the bin dimensions are always rounded up to the nearest Power of Two.
    squarebooleanfalseIf true, the bin dimensions are always made square (width = height).
    allowRotationbooleanfalseIf true, rectangles can be rotated 90 degrees to fit better.
    tagbooleanfalseEnables tag-based grouping.
    exclusiveTagbooleantrueIf true and tag is enabled, the bin only accepts rectangles with a tag matching the bin's tag.
    bordernumber0Adds a border around the internal packing area.
    logicPACKING_LOGICMAX_EDGEThe algorithm used to select the best free rectangle. See Packing Logic for details.
  10. Configure MaxRect Packer options

    master

    The IOption interface defines the configuration for the MaxRect Packer. You can use these properties to control sizing behavior, rotation, grouping, and spacing.

    Available Options

    PropertyTypeDefaultDescription
    smartbooleantrueEnables smart sizing packer.
    potbooleantrueUses Power of 2 sizing.
    squarebooleanfalseUses square size.
    allowRotationbooleanfalseAllows 90-degree rotation packing.
    tagbooleanfalseEnables auto grouping based on rect.tag.
    exclusiveTagbooleantrueIf true, tagged rectangles get their own dependent bin. If false, the packer tries to put tagged rectangles into the same bin.
    bordernumber0Sets the atlas edge spacing.
    logicPACKING_LOGICMAX_EDGEDetermines the sorting logic used during packing.
    const options: IOption = {
      smart: true,
      pot: true,
      allowRotation: false,
      border: 2,
      logic: PACKING_LOGIC.MAX_AREA
    };
  11. Check for collisions and containment in Rectangle

    master

    The Rectangle class provides static and instance methods to perform geometric tests:

    • collide(rect: IRectangle): Returns true if this rectangle overlaps with the provided rectangle.
    • Rectangle.Collide(first: IRectangle, second: IRectangle): Static method to test collision between two rectangles.
    • contain(rect: IRectangle): Returns true if this rectangle completely encloses the provided rectangle.
    • Rectangle.Contain(first: IRectangle, second: IRectangle): Static method to test if the first rectangle contains the second.
    import { Rectangle, IRectangle } from 'maxrects-packer';
    
    const rect1: IRectangle = { x: 0, y: 0, width: 10, height: 10 };
    const rect2: IRectangle = { x: 5, y: 5, width: 10, height: 10 };
    
    // Instance method
    const isColliding = new Rectangle(0,0).collide(rect1); // Note: logic depends on instance state
    
    // Static methods
    const collision = Rectangle.Collide(rect1, rect2);
    const containment = Rectangle.Contain(rect1, rect2);