npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ollow-engine

v5.6.5

Published

OLLOW Engine V5.6 — 2D/3D/vectoriel/rigging/physique pour le web moderne

Readme

OLLOW Engine V5.6 Ultra Web — Documentation complète

Moteur standalone 2D + 3D + vectoriel + rigging + physique avancée pour le web moderne. Script unique, détection automatique PC/mobile, aucune étape de build, aucune dépendance à un framework.

Version : 5.6.0 Profil : détecté automatiquement (pc ou mobile) Dépendances : Three.js 0.160 (chargé via esm.sh) Fonctionnalités énumérables : plus de 720 000


Table des matières

  1. Installation
  2. Démarrage rapide
  3. Profil et configuration
  4. Engine
  5. Scène 3D
  6. Géométries 3D
  7. Matériaux
  8. Lumières
  9. Physique avancée 3D
  10. Formes physiques
  11. Matériaux physiques
  12. Joints et contraintes
  13. Character Controller
  14. Véhicules
  15. Fluides
  16. Tissus et cordes
  17. Ragdolls
  18. Champs de force
  19. Customisation physique
  20. Requêtes physiques
  21. Debug physique
  22. Physique 2D
  23. Sprites 2D
  24. Animations 2D
  25. Tilemaps 2D
  26. Formes et texte 2D
  27. Camera 2D
  28. Scène 2D
  29. Vectoriel 3D
  30. Rigging squelettique
  31. Audio
  32. Contrôles
  33. Pathfinding A*
  34. ECS
  35. Plugins
  36. Bus d'événements
  37. Maths et bruit
  38. Easing
  39. Post-processing
  40. Manifeste
  41. PC vs Mobile
  42. Performance
  43. Dépannage

1. Installation

Copie ollow.js à côté de ton HTML, puis importe-le comme module ES.

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <style>
    html, body { margin: 0; height: 100%; overflow: hidden; background: #000; }
    canvas { display: block; width: 100%; height: 100%; }
  </style>
</head>
<body>
  <canvas id="c"></canvas>
  <script type="module">
    import OLLOW from './ollow.js';

    const engine = new OLLOW.Engine({ canvas3D: document.getElementById('c') });
    const scene  = engine.createScene3D();
    engine.createCamera(70);
    engine.createControls('orbit');

    scene.addLight({ type: 'hemisphere', intensity: 0.7 });
    scene.addLight({ type: 'directional', intensity: 1.2, position: [10, 20, 10] });
    scene.addMesh({ geometry: 'box', position: [0, 0.5, 0] });

    engine.start();
  </script>
</body>
</html>

Le CDN esm.sh doit être joignable au chargement. Pour un fonctionnement hors-ligne, héberge Three.js localement et remplace les imports en haut du fichier moteur.


2. Démarrage rapide

import OLLOW from './ollow.js';

const engine = new OLLOW.Engine({ canvas3D });
const scene  = engine.createScene3D();
const camera = engine.createCamera(70);
const ctrl   = engine.createControls('third-person');

scene.addLight({ type: 'hemisphere', color: 0x88aaff, groundColor: 0x222233, intensity: 0.7 });
scene.addLight({ type: 'directional', color: 0xfff0d0, intensity: 1.2, position: [30, 50, 20], shadowSize: 80 });
scene.setBackground(0x0a0a14);
scene.setFog(0x0a0a14, 40, 220);

scene.addMesh({
  geometry: 'box',
  size: [40, 0.5, 40],
  position: [0, -0.25, 0],
  material: { type: 'concrete' },
  physics: { type: 'static', shape: OLLOW.PhysicsShape.aabb(40, 0.5, 40) },
});

const playerMesh = scene.addMesh({
  geometry: 'capsule',
  radius: 0.4, height: 1,
  position: [0, 3, 0],
  material: { type: 'standard', color: 0x60a5fa, emissive: 0x1e3a8a, emissiveIntensity: 0.3 },
});
const playerBody = new OLLOW.Rigidbody3D(playerMesh, {
  shape: OLLOW.PhysicsShape.capsule(0.4, 1),
  type: 'dynamic', mass: 1, fixedRotation: true,
});
scene.physics.add(playerBody);

engine.onUpdate((dt) => {
  const axis = ctrl.getMoveAxis2D();
  playerBody.velocity.x = axis.x * 8;
  playerBody.velocity.z = axis.y * 8;
});

engine.start();

3. Profil et configuration

Détection automatique :

console.log(OLLOW.BUILD);            // 'pc' ou 'mobile'
console.log(OLLOW.CONFIG.profile);   // idem

| Réglage | PC | Mobile | |---|---|---| | Antialiasing | MSAA | désactivé | | Pixel ratio max | 2.0 | 1.5 | | Tone mapping | ACES | aucun | | Ombres | PCFSoft 2048 | désactivées | | Matériau défaut | standard (PBR) | lambert | | Post-processing | bloom + SSAO | désactivé | | Pas physique | 60 Hz | 30 Hz | | Substeps physiques | 4 | 2 | | Itérations solveur | 8 | 4 | | Particules max | 5 000 | 1 000 | | Plan lointain | 900 | 300 | | Contrôles | clavier + souris + manette | tactile + manette |

Tout est modifiable :

OLLOW.CONFIG.shadows = false;
OLLOW.CONFIG.physics.substeps = 6;
OLLOW.CONFIG.physics.integrator = 'rk4';
OLLOW.CONFIG.physics.gravity = { x: 0, y: -9.8, z: 0 };

4. Engine

new OLLOW.Engine({ mode, canvas2D, canvas3D })

| Méthode | Retour | Description | |---|---|---| | createScene3D() | OllowScene3D | Crée une scène 3D. La première devient active. | | createScene2D() | Scene2D | Crée une scène 2D. La première devient active. | | createCamera(fov) | PerspectiveCamera | Caméra 3D. | | createControls(type) | Controls | 'fps', 'orbit', 'third-person', '2d'. | | setMode('2d'\|'3d') | this | Bascule entre canvas 2D et 3D. | | enableBloom(strength) | UnrealBloomPass | PC uniquement. | | shake(mag) | — | Secousse caméra 3D. | | onUpdate(fn) | unsubscribe | Callback par frame. | | start() / stop() | — | Boucle RAF. | | loadGLTF(url) | Promise<GLTF> | Charge un glTF/glb. | | loadImage(url) | Promise<Image> | Charge une image 2D. | | stats | { fps } | FPS. | | audio | AudioBus | Web Audio. | | plugins | PluginHost | Système de plugins. | | ecs | ECS | Entity-Component-System. | | events | EventBus | Événements globaux. |


5. Scène 3D

scene.addMesh({
  geometry: 'sphere',
  radius: 0.5,
  position: [0, 1, 0],
  rotation: [0, Math.PI / 2, 0],
  scale: [1, 1, 1],
  material: { type: 'metal', color: 0xff6600 },
  physics: { type: 'dynamic', mass: 1, restitution: 0.4, tag: 'ball' },
  tag: 'enemy', name: 'sphereA', group: 'level1',
  castShadow: true, receiveShadow: true,
});

| Méthode | Description | |---|---| | addLight(spec) | Ajoute une lumière. | | removeMesh(mesh) | Retire un mesh. | | removeGroup(name) | Retire tous les meshes d'un groupe. | | clear() | Vide la scène. | | setBackground(couleur) | Fond uni. | | setFog(couleur, near, far) | Brouillard linéaire. | | setFogExp(couleur, densité) | Brouillard exponentiel. | | raycast(origine, direction, dist, tag) | Raycast Three.js. | | findByName(name) | Cherche un mesh par nom. | | findByTag(tag) | Filtre par tag. | | physics | Instance Physics3D de la scène. | | particles | Particules 3D. | | vector | Outils vectoriels 3D. |


6. Géométries 3D

spec.geometry accepte :

Primitives : box, sphere, plane, circle, cylinder, cone, torus, torusKnot, capsule, lathe, tube, extrude, ring, dodeca, icosa, octa, tetra.

Procédurales : terrain, rock, tree.

Utilitaires : crate, platform, wall, grid, merged.


7. Matériaux

spec.material.type accepte :

Base : standard, physical, lambert, phong, basic, toon, matcap, depth, normal, wireframe, points, line, dashed, sprite, shadow.

Presets : water, glass, metal, gold, silver, copper, iron, chrome, emissive, neon, glow, hologram, lava, ice, plasma, toxic, wood, marble, granite, concrete, brick, sand, grass, dirt, rock, rubber, plastic, ceramic, paper, bone, flesh, blood, oil, crystal, diamond, obsidian, amber.

Sur mobile, les matériaux PBR basculent automatiquement en Lambert.


8. Lumières

scene.addLight({ type: 'ambient', color: 0xffffff, intensity: 0.5 });
scene.addLight({ type: 'hemisphere', color: 0x88aaff, groundColor: 0x222233, intensity: 0.7 });
scene.addLight({ type: 'directional', color: 0xfff0d0, intensity: 1.2, position: [30, 50, 20], shadowSize: 80 });
scene.addLight({ type: 'point', color: 0xffaa00, intensity: 2, position: [0, 5, 0], distance: 30, decay: 2 });
scene.addLight({ type: 'spot', color: 0xffffff, intensity: 3, position: [0, 10, 0], target: [0, 0, 0], distance: 40, angle: Math.PI / 6, penumbra: 0.3 });

Sur mobile, les ombres sont ignorées.


9. Physique avancée 3D

Le module Physics3D remplace le moteur AABB simple de la V5.5.

Caractéristiques

  • Bodies : static, dynamic, kinematic.
  • Formes : AABB, sphère, capsule, OBB, convex hull, triangle mesh, heightfield, compound.
  • Intégrateurs : Euler, semi-implicite (défaut), Verlet, RK4, PBD, XPBD.
  • Solveurs : impulsion (défaut), Gauss-Seidel, Jacobi, LCP.
  • Broadphase : brute, grid, sweep-and-prune.
  • Substeps configurables (4 par défaut sur PC).
  • CCD (continuous collision detection).
  • Sleep automatique.
  • Events : onBeginContact, onEndContact, onPreSolve, onPostSolve.
  • Filtres de collision par callback.
  • Matériaux par paire.

Rigidbody3D

const rb = new OLLOW.Rigidbody3D(mesh, {
  shape: OLLOW.PhysicsShape.aabb(1, 1, 1),
  type: 'dynamic',           // 'static' | 'dynamic' | 'kinematic'
  mass: 2,
  material: new OLLOW.PhysicsMaterial({ friction: 0.6, restitution: 0.4, density: 1 }),
  gravityScale: 1,
  useGravity: true,
  ccd: true,
  fixedRotation: false,
  layer: 0, mask: 0xFFFF,
  tag: 'enemy',
  userData: { hp: 100 },
  onBeginContact: (other, point, normal) => { /* ... */ },
  onEndContact:   (other) => { /* ... */ },
  onPreSolve:     (other, point, normal) => { /* ... */ },
  onPostSolve:    (other, point, normal, impulse) => { /* ... */ },
});
scene.physics.add(rb);

Méthodes de Rigidbody3D

| Méthode | Description | |---|---| | applyForce(f) | Force au centre. | | applyForceAt(f, point) | Force + couple. | | applyImpulse(j) | Impulsion linéaire. | | applyImpulseAt(j, point) | Impulsion + couple. | | applyTorque(t) | Couple. | | setVelocity(v) | Vitesse linéaire. | | setAngularVelocity(v) | Vitesse angulaire. | | wake() / sleep() | Force le réveil / sommeil. | | worldAABB | Boîte englobante actuelle. | | speed | Norme de la vélocité. | | kineticEnergy | Énergie cinétique. |

Physics3D — API

scene.physics.add(body);
scene.physics.remove(body);
scene.physics.addJoint(joint);
scene.physics.addForceField(field);
scene.physics.addMaterial('glace', mat);
scene.physics.setPairMaterial('glace', 'caoutchouc', mat);
scene.physics.registerForce(name, fn);
scene.physics.registerBodyType(name, def);
scene.physics.registerIntegrator(name, fn);
scene.physics.registerFilter(fn);
scene.physics.applyForce(name, body, dt);
scene.physics.gravitySet(x, y, z);
scene.physics.pause() / resume();
scene.physics.step(dt);   // appelé automatiquement par le moteur

10. Formes physiques

OLLOW.PhysicsShape.aabb(w, h, d)
OLLOW.PhysicsShape.sphere(r)
OLLOW.PhysicsShape.capsule(r, h)
OLLOW.PhysicsShape.obb(w, h, d, quat)
OLLOW.PhysicsShape.convex(points)
OLLOW.PhysicsShape.mesh(vertices, indices)
OLLOW.PhysicsShape.heightfield(heights, sx, sz)
OLLOW.PhysicsShape.compound([shape1, shape2])

11. Matériaux physiques

const glace = new OLLOW.PhysicsMaterial({
  friction: 0.05,
  restitution: 0.1,
  density: 0.9,
  linearDamping: 0.01,
  angularDamping: 0.02,
});

scene.physics.addMaterial('glace', glace);
scene.physics.setPairMaterial('glace', 'metal', new OLLOW.PhysicsMaterial({ friction: 0.3, restitution: 0.4 }));

12. Joints et contraintes

new OLLOW.Joint3D(bodyA, bodyB, {
  type: 'spring',           // 'distance', 'spring', 'hinge', 'ball', 'slider',
                            // 'wheel', 'gear', 'pulley', 'point', 'magnet',
                            // 'breakable', 'motor'
  anchorA: new THREE.Vector3(0, 0, 0),
  anchorB: new THREE.Vector3(0, 0, 0),
  length: 2,
  stiffness: 40,
  damping: 4,
  min: -Math.PI / 4,
  max: Math.PI / 4,
  motorSpeed: 0,
  motorForce: 0,
  breakForce: 500,
});
scene.physics.addJoint(joint);

Types disponibles :

| Type | Description | |---|---| | distance | Distance fixe entre deux points. | | spring | Ressort de Hooke (raideur + amortissement). | | hinge | Charnière (1 axe libre). | | ball | Rotule (3 axes libres). | | slider | Glissière (1 axe libre). | | wheel | Roue (rotation + suspension). | | gear | Engrenage. | | pulley | Poulie. | | point | Point-à-point. | | magnet | Ressort vers une cible. | | breakable | Cassable au-delà d'une force. | | motor | Moteur avec vitesse cible. |


13. Character Controller

const char = new OLLOW.CharacterController3D(body, {
  maxSlope: Math.PI / 4,
  stepHeight: 0.4,
  snapToGround: true,
  coyoteTime: 0.15,
  jumpBuffer: 0.2,
  airControl: 0.4,
  wallSlide: 0.2,
  ledgeGrab: true,
});

engine.onUpdate((dt) => {
  char.update(dt, scene.physics);
  if (controls.isDown('Space')) char.jump();
});

14. Véhicules

const chassis = new OLLOW.Rigidbody3D(mesh, {
  shape: OLLOW.PhysicsShape.aabb(2, 0.5, 4),
  type: 'dynamic', mass: 500,
});
scene.physics.add(chassis);

const car = new OLLOW.Vehicle3D(chassis, {
  wheelBase: 2.5, track: 1.8,
  wheelRadius: 0.3,
  suspensionRest: 0.4,
  suspensionStiffness: 30,
  suspensionDamping: 4,
  maxEngineForce: 3000,
  maxBrakeForce: 5000,
  maxSteeringAngle: Math.PI / 6,
});

car.addWheel('FL', new THREE.Vector3(-0.9, 0, 1.2), { isSteering: true });
car.addWheel('FR', new THREE.Vector3(0.9, 0, 1.2), { isSteering: true });
car.addWheel('RL', new THREE.Vector3(-0.9, 0, -1.2), { isDriven: true });
car.addWheel('RR', new THREE.Vector3(0.9, 0, -1.2), { isDriven: true });

engine.onUpdate((dt) => {
  car.throttle(controls.isDown('KeyW') ? 1 : 0);
  car.brake(controls.isDown('Space') ? 1 : 0);
  car.steer(controls.getMoveAxis2D().x * 0.5);
  car.update(dt);
});

15. Fluides

SPH (Smoothed Particle Hydrodynamics).

const fluid = new OLLOW.Fluid3D({
  count: 800,
  radius: 3,
  restDensity: 1000,
  gasConstant: 2000,
  viscosity: 0.1,
  color: 0x2266aa,
  bounds: { minX: -10, maxX: 10, minY: 0, maxY: 20, minZ: -10, maxZ: 10 },
});

const points = fluid.toPoints();
scene.three.add(points);

engine.onUpdate((dt) => {
  fluid.step(dt);
  const pos = points.geometry.attributes.position;
  for (let i = 0; i < fluid.particles.length; i++) {
    pos.setXYZ(i, fluid.particles[i].position.x, fluid.particles[i].position.y, fluid.particles[i].position.z);
  }
  pos.needsUpdate = true;
});

16. Tissus et cordes

const cloth = new OLLOW.Cloth3D({
  cols: 20, rows: 20,
  size: 4, mass: 0.1,
  stiffness: 1, damping: 0.1,
  anchors: ['0,0', '19,0'],
});

const clothMesh = cloth.toMesh();
scene.three.add(clothMesh);

engine.onUpdate((dt) => {
  cloth.step(dt);
  const pos = clothMesh.geometry.attributes.position;
  for (let i = 0; i < cloth.particles.length; i++) pos.setXYZ(i, cloth.particles[i].position.x, cloth.particles[i].position.y, cloth.particles[i].position.z);
  pos.needsUpdate = true;
  clothMesh.geometry.computeVertexNormals();
});

17. Ragdolls

const skel = OLLOW.buildHumanoidSkeleton();
const ragdoll = new OLLOW.Ragdoll3D(skel);
ragdoll.build(scene.physics);

// Activation
ragdoll.activate();

// Désactivation
ragdoll.deactivate();

18. Champs de force

const wind = new OLLOW.ForceField3D({
  type: 'wind',                     // 'wind', 'gravity', 'attract', 'repel',
                                    // 'vortex'
  position: new THREE.Vector3(0, 10, 0),
  direction: new THREE.Vector3(1, 0, 0),
  strength: 20,
  radius: 30,
  falloff: 1,
});
scene.physics.addForceField(wind);

19. Customisation physique

Force custom

scene.physics.registerForce('tornade', (body, dt) => {
  const toCenter = body.position.clone().negate();
  const dist = toCenter.length();
  if (dist > 20) return null;
  const s = 50 / Math.max(dist, 1);
  return { x: toCenter.x * s, y: 5, z: toCenter.z * s };
});

scene.physics.applyForce('tornade', body, dt);

Intégrateur custom

scene.physics.registerIntegrator('verletMaison', (body, dt, world) => {
  const prevPos = body.userData.prevPos || body.position.clone();
  body.userData.prevPos = body.position.clone();
  body.position.addScaledVector(body.velocity, dt);
  body.velocity.addScaledVector(world.gravity, dt);
});

OLLOW.CONFIG.physics.integrator = 'verletMaison';

Filtre de collision

scene.physics.registerFilter((a, b) => {
  if (a.tag === 'projectile' && b.isTrigger) return false;
  if (b.tag === 'projectile' && a.isTrigger) return false;
  return true;
});

Type de body custom

scene.physics.registerBodyType('monstre', {
  integrate: (body, dt) => { /* ... */ },
  collide: (body, other) => { /* ... */ },
  solve: (body, dt) => { /* ... */ },
});

20. Requêtes physiques

const hit = scene.physics.raycast(
  new THREE.Vector3(0, 10, 0),
  new THREE.Vector3(0, -1, 0),
  100, 'enemy'
);

const inSphere = scene.physics.overlapSphere(new THREE.Vector3(0, 0, 0), 5);

const inBox = scene.physics.overlapAABB({
  min: { x: -5, y: 0, z: -5 },
  max: { x: 5, y: 10, z: 5 },
});

21. Debug physique

scene.physics.debug.wireframe = true;
scene.physics.debug.contacts = true;
scene.physics.debug.aabb = true;
scene.physics.debug.joints = true;
scene.physics.debug.forces = true;
scene.physics.debug.sleep = true;
scene.physics.debug.velocity = true;
scene.physics.debug.mass = true;

22. Physique 2D

const scene2 = engine.createScene2D();

const sprite = new OLLOW.Sprite2D({ image, x: 100, y: 100 });
scene2.addSprite(sprite);

const body = new OLLOW.Body2D(sprite, {
  type: 'dynamic',
  width: 32, height: 32,
  mass: 1,
  restitution: 0.2,
  friction: 0.9,
  useGravity: true,
  isTrigger: false,
  tag: 'player',
  layer: 0, mask: 0xFFFF,
  onCollision: (other) => { /* ... */ },
});

scene2.physics.add(body);

engine.onUpdate((dt) => {
  const axis = engine.controls.getMoveAxis2D();
  body.velocity.x = axis.x * 200;
});

// Requêtes
const hit = scene2.physics.raycast(x, y, dx, dy, maxDist);
const inAABB = scene2.physics.overlapAABB({ minX: 0, minY: 0, maxX: 100, maxY: 100 });

// Custom
scene2.physics.registerForce('vent', (body, dt) => ({ x: 100, y: 0 }));
scene2.physics.registerIntegrator('verlet2D', (b, dt) => { /* ... */ });
scene2.physics.registerFilter((a, b) => true);

23. Sprites 2D

const sprite = new OLLOW.Sprite2D({
  image: monImage,
  x: 100, y: 100,
  scaleX: 2, scaleY: 2,
  rotation: 0,
  anchorX: 0.5, anchorY: 0.5,
  opacity: 1,
  tint: null,
  visible: true,
  zIndex: 0,
  blendMode: 'source-over',
  tag: 'player',
});

sprite.setFrame(sx, sy, sw, sh);
sprite.setPosition(200, 300);
sprite.getBounds();         // { x, y, w, h, minX, minY, maxX, maxY }
sprite.contains(px, py);    // bool
sprite.draw(ctx);

24. Animations 2D

const anim = new OLLOW.AnimatedSprite2D({ image: spritesheet, x: 0, y: 0 });

anim.addAnimation('idle', [
  { x: 0, y: 0, w: 32, h: 32 },
  { x: 32, y: 0, w: 32, h: 32 },
], 8);

anim.addAnimation('run', [
  { x: 0, y: 32, w: 32, h: 32 },
  { x: 32, y: 32, w: 32, h: 32 },
], 12);

anim.play('idle', { loop: true });
anim.play('run', { loop: false });

engine.onUpdate((dt) => anim.update(dt));

25. Tilemaps 2D

const map = new OLLOW.Tilemap2D({
  tileSize: 32,
  width: 100,
  height: 100,
  tileset: monTileset,
});

map.addLayer('background');
map.addLayer('solids');
map.setCollisionLayer('solids');

map.setTile('solids', x, y, tileIndex);
map.getTile('solids', x, y);
map.isSolid(x, y);

scene2.addTilemap(map);

26. Formes et texte 2D

// Formes
const rect = new OLLOW.Shape2D('rect', { x: 0, y: 0, w: 100, h: 50, fill: 'red' });
const circle = new OLLOW.Shape2D('circle', { x: 100, y: 100, radius: 25, fill: 'blue' });
const poly = new OLLOW.Shape2D('polygon', { points: [[0,0],[50,0],[25,50]], fill: 'green' });

// Texte
const label = new OLLOW.Text2D('Score : 0', {
  x: 20, y: 20,
  font: 'bold 24px monospace',
  fill: '#fff',
  stroke: '#000', lineWidth: 3,
  align: 'left', baseline: 'top',
});

27. Camera 2D

const cam = scene2.camera;
cam.follow(player, 0.1);
cam.shake(15);
cam.setBounds(-1000, -1000, 1000, 1000);
cam.zoom = 2;

cam.update(dt);
cam.apply(ctx);
cam.screenToWorld(sx, sy);
cam.worldToScreen(wx, wy);

28. Scène 2D

const scene2 = engine.createScene2D();
scene2.background = '#000';

scene2.addSprite(sprite);
scene2.addShape(shape);
scene2.addText(text);
scene2.addTilemap(tilemap);
scene2.addHud(element);

scene2.removeSprite(sprite);
scene2.removeGroup('enemies');
scene2.clear();

29. Vectoriel 3D

VectorPath

const path = new OLLOW.VectorPath();
path.moveTo(0, 0);
path.lineTo(10, 0);
path.quadTo(15, 5, 20, 0);
path.bezierTo(25, -5, 30, 5, 35, 0);
path.close();

path.rect(0, 0, 10, 5);
path.circle(0, 0, 5);
path.polygon([[0,0],[10,0],[10,10],[0,10]]);
path.star(0, 0, 10, 4, 5);

path.toPoints();
path.toShape();   // THREE.Shape

Vector3D

const v = scene.vector;

v.extrude(path, { depth: 0.5, bevel: true, material: { type: 'gold' } });
v.vectorPlane(drawFn, { width: 4, height: 2, resolution: 1024 });
v.tube([[0,0,0],[1,1,0],[2,0,0]], { radius: 0.1, material: { type: 'neon' } });
v.lines3D([[[0,0,0],[1,1,1]]], { color: 0xff0000 });
v.groundGrid(20, 20, 0x444444);

vectorDraw (helpers canvas)

OLLOW.vectorDraw.clear(ctx, w, h);
OLLOW.vectorDraw.path(ctx, path, { fill: 'red', stroke: 'black' });
OLLOW.vectorDraw.circle(ctx, x, y, r, { fill: 'blue' });
OLLOW.vectorDraw.rect(ctx, x, y, w, h, { fill: 'green' });
OLLOW.vectorDraw.text(ctx, 'texte', x, y, { fill: 'white' });

30. Rigging squelettique

const skel = OLLOW.buildHumanoidSkeleton();
const hips = skel.find('Hips');
const head = skel.find('Head');

head.setLocalEuler(0, 0, Math.PI / 4);
skel.update();

Bone

const bone = new OLLOW.Bone('UpperArm', 0.3);
bone.setLocalPosition(0, 0, 0);
bone.setLocalEuler(0, 0, -Math.PI / 2);
bone.reset();
bone.captureBindPose();
bone.updateWorld();
bone.find('Hand');
bone.flatten();

Skeleton

const skel = new OLLOW.Skeleton('perso');
const root = new OLLOW.Bone('Hips');
skel.addBone(root);
skel.addBone(new OLLOW.Bone('Spine'), root);
skel.captureBindPose();
skel.update();
skel.resetPose();

31. Audio

await engine.audio.unlock();
await engine.audio.load('/sfx/hit.wav', 'hit');
engine.audio.play('hit', { volume: 1, loop: false, position: [x, y, z], rate: 1 });
engine.audio.setMasterVolume(0.8);
engine.audio.beep({ freq: 440, duration: 0.1, type: 'sine' });

32. Contrôles

controls.setSensitivity(0.0022);
controls.setSpeed(8);
controls.setTarget(mesh);
controls.vibrate(30);
controls.isDown('Space');
controls.isPressed(0);

const axis = controls.getMoveAxis2D();

Gestes tactiles :

controls.gestures.tap = (e) => {};
controls.gestures.doubleTap = (e) => {};
controls.gestures.longPress = (e) => {};
controls.gestures.swipe = ({ dx, dy, direction }) => {};
controls.gestures.pinch = (scale) => {};

33. Pathfinding A*

const nav = new OLLOW.NavGrid({ width: 120, depth: 120, cell: 1, heightFn: (x, z) => 0 });
nav.block(5, 5);
nav.unblock(5, 5);
const path = nav.findPath([0, 0, 0], [10, 0, 10]);

34. ECS

const id = engine.ecs.createEntity('player');
engine.ecs.addComponent(id, 'position', { x: 0, y: 0, z: 0 });
engine.ecs.addComponent(id, 'health', { hp: 100 });

engine.ecs.addSystem((ecs, dt) => {
  for (const e of ecs.query('position', 'health')) {
    const p = ecs.getComponent(e, 'position');
    const h = ecs.getComponent(e, 'health');
  }
});

engine.ecs.destroyEntity(id);

35. Plugins

engine.plugins.use({
  name: 'mon-plugin',
  setup(api) {
    api.on('update', dt => {});
    api.on('render', () => {});
  }
});

36. Bus d'événements

const off = engine.events.on('update', dt => {});
engine.events.emit('custom', { data: 1 });
off();

37. Maths et bruit

Math : clamp, lerp, invLerp, remap, rand, randI, pick, shuffle, damp, smoothstep, smootherstep, pingpong, wrap, angleLerp, deg2rad, rad2deg, dist, dist2, dist2D, uuid, sleep.

Bruit : noise1, noise2, fbm2, perlin2, gaussian.


38. Easing

30 fonctions : linear, quadIn/Out/InOut, cubicIn/Out/InOut, quartIn/Out, quintIn/Out, expoIn/Out, circIn/Out, backIn/Out, elasticIn/Out, bounceIn/Out, sineIn/Out, smoothstep, spring.


39. Post-processing

engine.enableBloom(0.6);

PC uniquement.


40. Manifeste

OLLOW.features.count();               // > 720 000
OLLOW.features.list();
OLLOW.features.categories();
OLLOW.features.stats();
OLLOW.features.query(f => f.category === 'physicsShape3D');
OLLOW.features.find('physicsJoint3D', 'spring');

Catégories principales :

  • primitive3D, material3D, light3D, postfx, particle3D
  • physicsShape3D, physicsJoint3D, physicsIntegrator, physicsSolver, physicsBroadphase, physicsMaterial, forceField, fluid, cloth, characterController, ragdoll, customPhysics, debugPhysics
  • sprite2D, anim2D, tile2D, physics2D, shape2D, text2D, camera2D, hud2D, gesture
  • vector, rig, input, event, camera3D, uiPreset, biome, easing, noise
  • combo3D-*, comboPhysics-*, combo2D-*, comboCross-*, bigInput3D, bigPhysics, bigPhysicsCore, hueVariant3D, physicsMatVariant

41. PC vs Mobile

| Réglage | PC | Mobile | |---|---|---| | Antialiasing | MSAA | désactivé | | Pixel ratio max | 2.0 | 1.5 | | Tone mapping | ACES | aucun | | Ombres | PCFSoft 2048 | désactivées | | Matériau défaut | standard (PBR) | lambert | | Post-processing | bloom + SSAO | désactivé | | Pas physique | 60 Hz | 30 Hz | | Substeps physiques | 4 | 2 | | Itérations solveur | 8 | 4 | | Particules max | 5 000 | 1 000 | | Plan lointain | 900 | 300 |


42. Performance

  • Limite les draw calls < 100 mobile, < 200 PC.
  • Réutilise reuseGeometry / reuseMaterial.
  • Utilise isInstanced: true + count pour les objets répétés.
  • Ne crée jamais de mesh dans onUpdate.
  • Réduis CONFIG.physics.substeps si la physique saccade.
  • Bascule en physics.integrator = 'semi-implicit' si rk4 coûte trop.
  • Utilise physics.broadphase = 'sweep' au-delà de 100 bodies.
  • Active ccd uniquement sur les projectiles rapides.
  • Désactive les onBeginContact / onPostSolve sur les bodies qui n'en ont pas besoin.

43. Dépannage

| Symptôme | Cause | Solution | |---|---|---| | Canvas noir | Pas de caméra ou de lumière | createCamera() + au moins une lumière. | | Le joueur traverse le sol | Pas de body physique | Ajoute physics: { type: 'static' } au sol. | | Objets qui s'enfoncent | Substeps trop bas | Augmente CONFIG.physics.substeps. | | Tremblements | Solveur instable | Augmente les itérations solveur. | | Meshes invisibles mobile | Matériau PBR | Utilise lambert / basic / toon. | | Pointer lock refusé | Pas un geste utilisateur | Appelle depuis un clic. | | Audio silencieux | Context verrouillé | engine.audio.unlock() depuis un clic. | | THREE is not defined | Import séparé | Utilise OLLOW.THREE. | | Joints qui explosent | Stiffness trop haut | Réduis stiffness et augmente les itérations. | | Fluides très lents | Trop de particules | Réduis count ou passe à count: 300. | | Ragdoll mou | Masses incohérentes | Aligne masses avec les os. | | Character qui grimpe aux murs | maxSlope trop grand | Réduis maxSlope à π/6. |


Licence

Livré tel quel pour le projet du destinataire. Three.js est sous licence MIT ; conserve son en-tête si tu redistribues le moteur.