Loaders
three-flatland provides loaders for common 2D asset formats. All loaders share a unified texture configuration system with hierarchical presets.
Available Loaders
| Loader | Format | Use Case |
|---|---|---|
TextureLoader | PNG, JPG, SVG, etc. | Single textures with preset support |
SpriteSheetLoader | TexturePacker JSON | Spritesheets and atlases |
TiledLoader | Tiled .json/.tmj | Tile-based maps |
LDtkLoader | LDtk .ldtk | Level design with entities |
TextureLoader
Load textures with automatic preset application. Works seamlessly with R3F’s useLoader.
import { TextureLoader, Sprite2D } from 'three-flatland';
// Load texture (presets automatically applied)const texture = await TextureLoader.load('/sprites/player.png');
const sprite = new Sprite2D({ texture });import { useLoader } from '@react-three/fiber/webgpu';import { TextureLoader, Sprite2D } from 'three-flatland/react';import { extend } from '@react-three/fiber/webgpu';
extend({ Sprite2D });
function Player() { // Presets automatically applied (pixel-art by default) const texture = useLoader(TextureLoader, '/sprites/player.png');
return <sprite2D texture={texture} />;}Multiple Textures
import { TextureLoader } from 'three-flatland';
// Preload multiple texturesconst textures = await TextureLoader.preload([ '/sprites/player.png', '/sprites/enemy.png', '/sprites/items.png',]);import { useLoader } from '@react-three/fiber/webgpu';import { TextureLoader } from 'three-flatland/react';
// Define URLs at module level for stable referencesconst TEXTURE_URLS = ['/sprites/player.png', '/sprites/enemy.png', '/sprites/items.png'];
function Game() { // Load multiple textures at once const [playerTex, enemyTex, itemsTex] = useLoader(TextureLoader, TEXTURE_URLS); // ...}Override Presets
// Override preset for specific textureconst smoothTexture = await TextureLoader.load('/sprites/hd-ui.png', { texture: 'smooth'});// Override preset via extension callbackconst smoothTexture = useLoader(TextureLoader, '/sprites/hd-ui.png', (loader) => { loader.preset = 'smooth';});SpriteSheetLoader
Load spritesheets exported from TexturePacker or compatible tools.
import { SpriteSheetLoader, Sprite2D } from 'three-flatland';
const sheet = await SpriteSheetLoader.load('/sprites/player.json');
// Access framesconst idleFrame = sheet.getFrame('player_idle_0');const allFrames = sheet.getFrameNames();
// Use with Sprite2Dconst sprite = new Sprite2D({ texture: sheet.texture });sprite.setFrame(idleFrame);import { Suspense } from 'react';import { useLoader } from '@react-three/fiber/webgpu';import { SpriteSheetLoader, Sprite2D } from 'three-flatland/react';import { extend } from '@react-three/fiber/webgpu';
extend({ Sprite2D });
function Player() { // useLoader suspends while loading, presets applied automatically const sheet = useLoader(SpriteSheetLoader, '/sprites/player.json'); const frame = sheet.getFrame('player_idle_0');
return <sprite2D texture={sheet.texture} frame={frame} />;}
// Wrap with Suspense<Suspense fallback={null}> <Player /></Suspense>Multiple Spritesheets
const sheets = await SpriteSheetLoader.preload([ '/sprites/player.json', '/sprites/enemies.json',]);// Define URLs at module level for stable referencesconst SHEET_URLS = ['/sprites/player.json', '/sprites/enemies.json'];
function Game() { const [playerSheet, enemySheet] = useLoader(SpriteSheetLoader, SHEET_URLS); // ...}Supported Formats
- JSON Hash (TexturePacker default) - Frames as object properties
- JSON Array - Frames as array with
filenameproperty
TiledLoader
Load maps from Tiled Map Editor. See the Tilemaps guide for detailed usage.
import { TiledLoader, TileMap2D } from 'three-flatland';
const mapData = await TiledLoader.load('/maps/level1.json');const tilemap = new TileMap2D({ data: mapData });import { Suspense } from 'react';import { useLoader } from '@react-three/fiber/webgpu';import { TiledLoader, TileMap2D } from 'three-flatland/react';import { extend } from '@react-three/fiber/webgpu';
extend({ TileMap2D });
function Level() { const mapData = useLoader(TiledLoader, '/maps/level1.json'); return <tileMap2D data={mapData} />;}
// Wrap with Suspense<Suspense fallback={null}> <Level /></Suspense>Features
- Embedded and external tilesets
- Tile layers with flip flags
- Object layers for entities and collision
- Tile animations
- Infinite maps with chunks
LDtkLoader
Load projects from LDtk. See the Tilemaps guide for detailed usage.
import { LDtkLoader, TileMap2D } from 'three-flatland';
// Load a specific levelconst mapData = await LDtkLoader.load('/maps/world.ldtk', 'Level_0');const tilemap = new TileMap2D({ data: mapData });
// List all levels in projectconst levelIds = await LDtkLoader.getLevelIds('/maps/world.ldtk');import { Suspense } from 'react';import { useLoader } from '@react-three/fiber/webgpu';import { LDtkLoader, TileMap2D } from 'three-flatland/react';import { extend } from '@react-three/fiber/webgpu';
extend({ TileMap2D });
function Level() { // Loads first level by default const mapData = useLoader(LDtkLoader, '/maps/world.ldtk'); return <tileMap2D data={mapData} />;}
// Specify level via extension callbackfunction SpecificLevel() { const mapData = useLoader(LDtkLoader, '/maps/world.ldtk', (loader) => { loader.levelId = 'Level_1'; }); return <tileMap2D data={mapData} />;}
// Wrap with Suspense<Suspense fallback={null}> <Level /></Suspense>Features
- Multi-level projects
- Tile layers (Tiles, AutoLayer, IntGrid)
- Entity layers with custom fields
- IntGrid collision data
- Tile flip flags
Texture Presets
All loaders use a unified texture configuration system. Presets control filtering, wrapping, and mipmaps.
Available Presets
| Preset | Filtering | Wrap | Mipmaps | Best For |
|---|---|---|---|---|
'pixel-art' | Nearest | Clamp | Off | Pixel art, retro games, tilemaps |
'smooth' | Linear | Clamp | On | HD sprites, smooth graphics |
'none' | — | — | — | Full manual control |
Configuration Hierarchy
Texture options follow a hierarchy (highest to lowest priority):
Instance preset/options → Loader.options → TextureConfig.options → 'pixel-art' (highest) (middle) (lowest) (default)For TextureLoader with R3F’s useLoader, the instance preset is set via the extension callback:
// Instance-level override via extensionconst texture = useLoader(TextureLoader, '/sprite.png', (loader) => { loader.preset = 'smooth'; // Highest priority});Each level overrides the ones below it. If nothing is set, 'pixel-art' is used.
Global Configuration
Set a system-wide default for all loaders:
import { TextureConfig } from 'three-flatland';
// Change global defaultTextureConfig.options = 'smooth';
// All loaders now use smooth filteringconst sheet = await SpriteSheetLoader.load('/sprites/player.json');const mapData = await TiledLoader.load('/maps/level.json');
// Reset to system defaultTextureConfig.reset(); // Back to 'pixel-art'Per-Loader Configuration
Override the default for a specific loader type:
import { TextureLoader, SpriteSheetLoader, TiledLoader } from 'three-flatland';
// HD textures with smooth filteringTextureLoader.options = 'smooth';
// HD sprites with smooth filteringSpriteSheetLoader.options = 'smooth';
// Tilemaps stay pixel-perfectTiledLoader.options = 'pixel-art';
// Now these use different settingsconst texture = await TextureLoader.load('/sprites/hd-player.png'); // smoothconst sprites = await SpriteSheetLoader.load('/sprites/ui.json'); // smoothconst mapData = await TiledLoader.load('/maps/dungeon.json'); // pixel-artPer-Instance Configuration
Override for a specific load call:
// One-off overrideconst hdSheet = await SpriteSheetLoader.load('/sprites/hd-ui.json', { texture: 'smooth'});
// Custom optionsconst customSheet = await SpriteSheetLoader.load('/sprites/special.json', { texture: { minFilter: LinearFilter, magFilter: NearestFilter, // Mix filtering modes }});// Override preset via extension callbackconst hdSheet = useLoader(SpriteSheetLoader, '/sprites/hd-ui.json', (loader) => { loader.preset = 'smooth';});
// Custom optionsconst customSheet = useLoader(SpriteSheetLoader, '/sprites/special.json', (loader) => { loader.preset = { minFilter: LinearFilter, magFilter: NearestFilter, };});Full Manual Control
Use 'none' for complete control via .then():
import { RepeatWrapping } from 'three';
const sheet = await SpriteSheetLoader.load('/sprites/tiles.json', { texture: 'none'}).then(s => { // Full manual configuration s.texture.wrapS = RepeatWrapping; s.texture.wrapT = RepeatWrapping; s.texture.anisotropy = 16; return s;});Common Patterns
Pixel Art Game (default)
// Just use defaults - pixel-art is the system defaultconst sheet = await SpriteSheetLoader.load('/sprites/player.json');const mapData = await TiledLoader.load('/maps/level.json');HD Game
// Set global default once at startupTextureConfig.options = 'smooth';
// All loads now use smooth filteringconst sheet = await SpriteSheetLoader.load('/sprites/player.json');Mixed Styles
// Configure each loader typeSpriteSheetLoader.options = 'smooth'; // HD spritesTiledLoader.options = 'pixel-art'; // Pixel tilemaps
// Or override per-instanceconst pixelSprite = await SpriteSheetLoader.load('/sprites/retro.json', { texture: 'pixel-art'});Caching
All loaders cache results by URL and texture options. Subsequent loads return the cached promise:
// First load - fetches from networkconst sheet1 = await SpriteSheetLoader.load('/sprites/player.json');
// Second load - returns cached result instantlyconst sheet2 = await SpriteSheetLoader.load('/sprites/player.json');
console.log(sheet1 === sheet2); // trueDifferent texture options create separate cache entries:
// These are cached separatelyconst pixelSheet = await SpriteSheetLoader.load('/sprites/ui.json', { texture: 'pixel-art' });const smoothSheet = await SpriteSheetLoader.load('/sprites/ui.json', { texture: 'smooth' });
console.log(pixelSheet === smoothSheet); // falseClear the cache when needed:
TextureLoader.clearCache();SpriteSheetLoader.clearCache();TiledLoader.clearCache();LDtkLoader.clearCache();Preloading
Load multiple assets in parallel:
// Preload spritesheetsconst sheets = await SpriteSheetLoader.preload([ '/sprites/player.json', '/sprites/enemies.json', '/sprites/items.json',]);
// Preload mapsconst maps = await TiledLoader.preload([ '/maps/level1.json', '/maps/level2.json',]);With texture options:
const sheets = await SpriteSheetLoader.preload( ['/sprites/ui.json', '/sprites/hud.json'], { texture: 'smooth' });