new BABYLON.Texture(url, scene, noMipmap, invertY, samplingMode) loads asynchronously and returns at once. The defaults follow Textures: mipmaps, trilinear filtering, invertY true, repeat wrapping, and gammaSpace true, marking the image as sRGB so shaders linearize it before lighting (sRGB); set it false for normal, roughness and metallic maps:
const cover = new BABYLON.Texture('booknest-cover-3.png', scene);
cover.wrapU = BABYLON.Texture.MIRROR_ADDRESSMODE; // 2: flip every other tile
cover.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE; // 0: stretch the edge texels
cover.uScale = 3; // three tiles across
cover.onLoadObservable.addOnce(() => {
const { width, height } = cover.getSize();
console.log(`${width} x ${height}, hasAlpha ${cover.hasAlpha}, ` +
`gammaSpace ${cover.gammaSpace}, sampling ${cover.samplingMode}`);
});Output
256 x 384, hasAlpha false, gammaSpace true, sampling 3
The PNG has an alpha channel, but hasAlpha stays false until you set it, so a cover never blends by accident. .ktx2 files (Basis Universal 3,114 , Compressed Textures) load through the same constructor and transcode per device.
<!doctype html>
<style>
body { margin: 0; background: #f7f3ec; font: 13px system-ui, sans-serif; color: #333; }
canvas { width: 100%; max-width: 600px; height: 300px; display: block; touch-action: none; outline: none; }
#info { max-width: 600px; padding: 4px 8px; font-family: monospace; }
</style>
<canvas id="view"></canvas>
<div id="info">Loading…</div>
<script src="https://cdn.jsdelivr.net/npm/babylonjs@9.28.0/babylon.js"></script>
<script src="https://cdn.jsdelivr.net/npm/babylonjs-gui@9.28.0/babylon.gui.min.js"></script>
<script>
// The book loads 'booknest-cover-3.png'. Here the PNG is drawn on a canvas and handed to
// BABYLON.Texture as a data: URL, so it still goes through the normal asynchronous loader.
const art = document.createElement('canvas');
art.width = 256; art.height = 384;
const c = art.getContext('2d');
c.fillStyle = '#e09a10'; c.fillRect(0, 0, 256, 384);
c.fillStyle = '#7a4a00'; c.fillRect(0, 0, 40, 384); // a band on the left edge
c.fillStyle = '#fff8e1'; c.textAlign = 'center'; c.font = 'bold 36px Georgia';
c.fillText('Salt and', 148, 150); c.fillText('Saffron', 148, 192);
c.beginPath(); c.arc(148, 280, 40, 0, Math.PI * 2); c.fill();
const url = art.toDataURL('image/png');
const canvas = document.getElementById('view');
const engine = new BABYLON.Engine(canvas, true);
const scene = new BABYLON.Scene(engine);
scene.clearColor = BABYLON.Color4.FromHexString('#f7f3ecff');
const camera = new BABYLON.ArcRotateCamera('cam', -Math.PI / 2, Math.PI / 2, 7, new BABYLON.Vector3(0, 0.1, 0), scene);
camera.attachControl(canvas, true);
new BABYLON.HemisphericLight('sky', new BABYLON.Vector3(0, 0, -1), scene);
const ui = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI('ui');
const MODES = [['WRAP (repeat)', BABYLON.Texture.WRAP_ADDRESSMODE],
['MIRROR', BABYLON.Texture.MIRROR_ADDRESSMODE], ['CLAMP', BABYLON.Texture.CLAMP_ADDRESSMODE]];
MODES.forEach(([name, mode], i) => {
// new BABYLON.Texture(url, scene, noMipmap, invertY, samplingMode) returns at once
const cover = new BABYLON.Texture(url, scene);
cover.wrapU = mode;
cover.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE; // stretch the edge texels vertically
cover.uScale = 3; // three tiles across
cover.uOffset = -1; // centered, so clamp shows both edges
const panel = BABYLON.MeshBuilder.CreatePlane(name, { width: 1.8, height: 1.8 }, scene);
panel.position.x = (i - 1) * 2;
panel.material = new BABYLON.StandardMaterial(name, scene);
panel.material.diffuseTexture = cover;
panel.material.specularColor = BABYLON.Color3.Black();
const label = new BABYLON.GUI.TextBlock('', name);
Object.assign(label, { color: '#333', fontSize: 12, resizeToFit: true });
ui.addControl(label);
label.linkWithMesh(panel);
label.linkOffsetY = 95;
if (i === 0) cover.onLoadObservable.addOnce(() => {
const { width, height } = cover.getSize();
document.getElementById('info').textContent = `${width} x ${height}, hasAlpha ${cover.hasAlpha}, ` +
`gammaSpace ${cover.gammaSpace}, samplingMode ${cover.samplingMode} (trilinear)`;
});
});
engine.runRenderLoop(() => scene.render());
addEventListener('resize', () => engine.resize());
</script>