Foundations Updated 2026-09 View as Markdown

ml5.js

ml5.js is a friendly JavaScript library for the browser that makes machine learning accessible to artists and creative coders.

ml5.js Tutorial#

ml5.js is a friendly JavaScript library for the browser that makes machine learning accessible to artists and creative coders. Built on top of TensorFlow.js, it provides high-level functions for common ML tasks.

What You'll Learn#

  • Image classification and object detection
  • Pose estimation and body tracking
  • Style transfer and image generation
  • Text analysis and sentiment detection
  • Sound classification and pitch detection

Installation#

You can include ml5.js in your project via a CDN:

javascript
<script src="https://unpkg.com/ml5@latest/dist/ml5.min.js"></script>

1. Understanding Pre-trained Models#

ml5.js specializes in making pre-trained models easy to use. Let's understand what this means:

javascript
<script>
function explainPretrainedModels() {
  const explanation = `
    <h4>Pre-trained Models in ml5.js:</h4>
    <ul>
      <li><strong>MobileNet:</strong> Trained on ImageNet (1000+ object classes)</li>
      <li><strong>PoseNet:</strong> Detects human poses and body keypoints</li>
      <li><strong>COCO-SSD:</strong> Object detection for 80 common objects</li>
      <li><strong>BodyPix:</strong> Person segmentation and body part detection</li>
      <li><strong>StyleTransfer:</strong> Artistic style transfer</li>
    </ul>
    <p><strong>Benefits:</strong></p>
    <ul>
      <li>No training required - models work immediately</li>
      <li>High accuracy from professional training</li>
      <li>Optimized for web performance</li>
      <li>Easy to integrate and use</li>
    </ul>
  `;
  
  document.getElementById('explanation-output').innerHTML = explanation;
}

explainPretrainedModels();
</script>
<div id="explanation-output"></div>

2. Image Classification with MobileNet#

Let's start with the classic example of classifying images using MobileNet.

javascript
<script>
// Global variables
let classifier;
let isModelLoaded = false;

async function initializeClassifier() {
  const statusDiv = document.getElementById('classifier-status');
  statusDiv.innerHTML = '<p>๐Ÿ”„ Loading MobileNet model...</p>';
  
  try {
    classifier = await ml5.imageClassifier('MobileNet');
    isModelLoaded = true;
    statusDiv.innerHTML = '<p>โœ… Model loaded! Click buttons below to classify images.</p>';
    console.log('MobileNet model loaded successfully!');
  } catch (error) {
    statusDiv.innerHTML = '<p>โŒ Error loading model. Please refresh and try again.</p>';
    console.error('Error loading model:', error);
  }
}

async function classifyImage(imageSrc, imageName) {
  if (!isModelLoaded) {
    alert('Model is still loading. Please wait...');
    return;
  }
  
  const img = document.getElementById('classify-img');
  const output = document.getElementById('classification-output');
  
  output.innerHTML = '<p>๐Ÿ”„ Loading and classifying image...</p>';
  
  img.onload = async () => {
    try {
      output.innerHTML = '<p>๐Ÿง  Analyzing image...</p>';
      
      const results = await classifier.classify(img);
      
      let resultHTML = `<h4>Classification Results for "${imageName}":</h4>`;
      resultHTML += '<div style="background: #f0f8ff; padding: 15px; border-radius: 8px; margin: 10px 0;">';
      resultHTML += '<ol>';
      
      results.slice(0, 3).forEach((result, index) => {
        const confidence = (result.confidence * 100).toFixed(1);
        const emoji = index === 0 ? '๐Ÿฅ‡' : (index === 1 ? '๐Ÿฅˆ' : '๐Ÿฅ‰');
        resultHTML += `<li>${emoji} <strong>${result.label}</strong> (${confidence}% confidence)</li>`;
      });
      
      resultHTML += '</ol></div>';
      
      output.innerHTML = resultHTML;
    } catch (error) {
      output.innerHTML = '<p>โŒ Error classifying image. Please try again.</p>';
      console.error('Classification error:', error);
    }
  };
  
  img.onerror = () => {
    output.innerHTML = '<p>โŒ Error loading image. Please try again.</p>';
  };
  
  img.src = imageSrc;
}

// Initialize the classifier when the page loads
initializeClassifier();
</script>

<div id="classifier-status"></div>

<div style="margin: 20px 0;">
  <h4>๐Ÿ–ผ๏ธ Choose an image to classify:</h4>
  <div style="display: flex; gap: 10px; flex-wrap: wrap; margin: 10px 0;">
    <button onclick="classifyImage('https://images.unsplash.com/photo-1546598300-f5d62e0b7b9b?w=400&q=80', 'Golden Retriever')" 
            style="padding: 8px 16px; background: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer;">
      ๐Ÿ• Dog
    </button>
    <button onclick="classifyImage('https://images.unsplash.com/photo-1495052384700-271d7c5f5e8c?w=400&q=80', 'Orange Cat')" 
            style="padding: 8px 16px; background: #FF9800; color: white; border: none; border-radius: 4px; cursor: pointer;">
      ๐Ÿฑ Cat
    </button>
    <button onclick="classifyImage('https://images.unsplash.com/photo-1503803548695-c2a7b4a5b875?w=400&q=80', 'Sports Car')" 
            style="padding: 8px 16px; background: #2196F3; color: white; border: none; border-radius: 4px; cursor: pointer;">
      ๐Ÿš— Car
    </button>
    <button onclick="classifyImage('https://images.unsplash.com/photo-1541963463532-d68292c34d19?w=400&q=80', 'Flowers')" 
            style="padding: 8px 16px; background: #E91E63; color: white; border: none; border-radius: 4px; cursor: pointer;">
      ๐ŸŒธ Flowers
    </button>
  </div>
</div>

<div style="text-align: center; margin: 20px 0;">
  <img id="classify-img" crossorigin="anonymous" width="300" height="200" 
       style="object-fit: cover; border: 3px solid #ddd; border-radius: 8px; display: none;"/>
</div>

<div id="classification-output"></div>

<script>
// Show image when it loads
document.getElementById('classify-img').addEventListener('load', function() {
  this.style.display = 'block';
});
</script>

3. Pose Estimation with PoseNet#

PoseNet can detect human poses and track body keypoints in real-time. Let's explore this capability:

javascript
<script>
let poseNet;
let isPoseModelLoaded = false;

async function initializePoseNet() {
  const statusDiv = document.getElementById('pose-status');
  statusDiv.innerHTML = '<p>๐Ÿ”„ Loading PoseNet model...</p>';
  
  try {
    poseNet = await ml5.poseNet();
    isPoseModelLoaded = true;
    statusDiv.innerHTML = '<p>โœ… PoseNet loaded! Click a button to analyze poses.</p>';
    console.log('PoseNet model loaded successfully!');
  } catch (error) {
    statusDiv.innerHTML = '<p>โŒ Error loading PoseNet. Please refresh and try again.</p>';
    console.error('Error loading PoseNet:', error);
  }
}

async function analyzePose(imageSrc, imageName) {
  if (!isPoseModelLoaded) {
    alert('PoseNet is still loading. Please wait...');
    return;
  }
  
  const img = document.getElementById('pose-img');
  const canvas = document.getElementById('pose-canvas');
  const ctx = canvas.getContext('2d');
  const output = document.getElementById('pose-output');
  
  output.innerHTML = '<p>๐Ÿ”„ Loading image and detecting poses...</p>';
  
  img.onload = async () => {
    try {
      // Set canvas size to match image
      canvas.width = 400;
      canvas.height = 300;
      
      // Draw the image on canvas
      ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
      
      output.innerHTML = '<p>๐Ÿง  Analyzing pose keypoints...</p>';
      
      // Get pose estimation
      const poses = await poseNet.singlePose(img);
      
      if (poses.pose) {
        drawKeypoints(ctx, poses.pose.keypoints, canvas.width / img.naturalWidth, canvas.height / img.naturalHeight);
        displayPoseInfo(poses.pose, output, imageName);
      } else {
        output.innerHTML = '<p>โŒ No pose detected in this image.</p>';
      }
      
    } catch (error) {
      output.innerHTML = '<p>โŒ Error analyzing pose. Please try again.</p>';
      console.error('Pose analysis error:', error);
    }
  };
  
  img.src = imageSrc;
}

function drawKeypoints(ctx, keypoints, scaleX, scaleY) {
  // Draw keypoints
  ctx.fillStyle = '#FF0000';
  ctx.strokeStyle = '#00FF00';
  ctx.lineWidth = 2;
  
  keypoints.forEach(keypoint => {
    if (keypoint.score > 0.3) { // Only draw confident keypoints
      const x = keypoint.position.x * scaleX;
      const y = keypoint.position.y * scaleY;
      
      // Draw point
      ctx.beginPath();
      ctx.arc(x, y, 5, 0, 2 * Math.PI);
      ctx.fill();
      
      // Draw label
      ctx.fillStyle = '#FFFFFF';
      ctx.font = '12px Arial';
      ctx.fillText(keypoint.part, x + 8, y - 8);
      ctx.fillStyle = '#FF0000';
    }
  });
}

function displayPoseInfo(pose, output, imageName) {
  const keypoints = pose.keypoints.filter(kp => kp.score > 0.3);
  
  let resultHTML = `<h4>Pose Analysis for "${imageName}":</h4>`;
  resultHTML += `<p><strong>Confidence Score:</strong> ${(pose.score * 100).toFixed(1)}%</p>`;
  resultHTML += `<p><strong>Detected Keypoints:</strong> ${keypoints.length}/17</p>`;
  
  resultHTML += '<details style="margin: 10px 0;">';
  resultHTML += '<summary style="cursor: pointer; font-weight: bold;">View Keypoint Details</summary>';
  resultHTML += '<div style="background: #f9f9f9; padding: 10px; margin: 5px 0; border-radius: 4px;">';
  
  keypoints.forEach(keypoint => {
    resultHTML += `<p><strong>${keypoint.part}:</strong> (${keypoint.position.x.toFixed(0)}, ${keypoint.position.y.toFixed(0)}) - ${(keypoint.score * 100).toFixed(1)}% confidence</p>`;
  });
  
  resultHTML += '</div></details>';
  
  output.innerHTML = resultHTML;
}

// Initialize PoseNet
initializePoseNet();
</script>

<div id="pose-status"></div>

<div style="margin: 20px 0;">
  <h4>๐Ÿ•บ Choose a pose to analyze:</h4>
  <div style="display: flex; gap: 10px; flex-wrap: wrap; margin: 10px 0;">
    <button onclick="analyzePose('https://images.unsplash.com/photo-1571019613454-1cb2f99b2d8b?w=400&q=80', 'Yoga Pose')" 
            style="padding: 8px 16px; background: #9C27B0; color: white; border: none; border-radius: 4px; cursor: pointer;">
      ๐Ÿง˜ Yoga
    </button>
    <button onclick="analyzePose('https://images.unsplash.com/photo-1571019613454-1cb2f99b2d8b?w=400&q=80', 'Dancing')" 
            style="padding: 8px 16px; background: #FF5722; color: white; border: none; border-radius: 4px; cursor: pointer;">
      ๐Ÿ’ƒ Dance
    </button>
    <button onclick="analyzePose('https://images.unsplash.com/photo-1544717297-fa95b6ee9643?w=400&q=80', 'Running')" 
            style="padding: 8px 16px; background: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer;">
      ๐Ÿƒ Running
    </button>
  </div>
</div>

<div style="text-align: center; margin: 20px 0;">
  <img id="pose-img" crossorigin="anonymous" width="400" height="300" style="display: none;"/>
  <canvas id="pose-canvas" style="border: 2px solid #333; border-radius: 8px;"></canvas>
</div>

<div id="pose-output"></div>
Exercise

Try it

ready

Get the JavaScript agent pack

A battle-tested AGENTS.md, the review checklist, and the failure-mode cheat sheet for JavaScript. One email, then occasional updates when the tooling shifts. No course pitch.

Unsubscribe in one click. We never sell the list. Or just take the AGENTS.md now โ€” no email needed.