All skills
jamesrochabrun avatar

/math-teacher

@98139d5

Interactive math teacher that instantly generates playful, gamified learning experiences. Creates visual playgrounds, interactive artifacts, and engaging games for kids and adults to learn math concepts from basic arithmetic to advanced calculus.

Use this Skill: https://skilld.dev/gh/jamesrochabrun/skills/math-teacher

This session only. Nothing lands on disk.

referencescalculus.md

≈3.4k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Calculus Reference

Advanced calculus concepts with interactive visualizations.

Derivatives

Derivative Calculator

// Numerical derivative using limit definition
function numericalDerivative(f, x, h = 0.0001) {
  return (f(x + h) - f(x - h)) / (2 * h);
}

// Common derivatives
const derivatives = {
  power: (n) => (x) => n * Math.pow(x, n - 1),
  exponential: (a) => (x) => a * Math.pow(Math.E, a * x),
  logarithmic: (x) => 1 / x,
  sine: (x) => Math.cos(x),
  cosine: (x) => -Math.sin(x),
  tangent: (x) => 1 / Math.pow(Math.cos(x), 2)
};

Tangent Line Visualizer

function drawTangentLine(f, x0, canvas) {
  const ctx = canvas.getContext('2d');
  const width = canvas.width;
  const height = canvas.height;

  // Calculate derivative at x0
  const slope = numericalDerivative(f, x0);
  const y0 = f(x0);

  // Draw function
  ctx.strokeStyle = '#667eea';
  ctx.lineWidth = 3;
  ctx.beginPath();

  for (let x = -5; x <= 5; x += 0.1) {
    const y = f(x);
    const px = (x + 5) * (width / 10);
    const py = height - ((y + 5) * (height / 10));

    if (x === -5) ctx.moveTo(px, py);
    else ctx.lineTo(px, py);
  }
  ctx.stroke();

  // Draw tangent line
  ctx.strokeStyle = '#FF6347';
  ctx.lineWidth = 2;
  ctx.beginPath();

  for (let x = -5; x <= 5; x += 0.1) {
    const y = y0 + slope * (x - x0); // Point-slope form
    const px = (x + 5) * (width / 10);
    const py = height - ((y + 5) * (height / 10));

    if (x === -5) ctx.moveTo(px, py);
    else ctx.lineTo(px, py);
  }
  ctx.stroke();

  // Mark point of tangency
  const px0 = (x0 + 5) * (width / 10);
  const py0 = height - ((y0 + 5) * (height / 10));

  ctx.fillStyle = '#FFD700';
  ctx.beginPath();
  ctx.arc(px0, py0, 8, 0, Math.PI * 2);
  ctx.fill();

  // Display slope
  ctx.fillStyle = '#333';
  ctx.font = 'bold 16px Arial';
  ctx.fillText(`Slope = ${slope.toFixed(3)}`, 20, 30);
  ctx.fillText(`f'(${x0.toFixed(2)}) = ${slope.toFixed(3)}`, 20, 50);

  return { slope, y0, x0 };
}

Secant Line Animation

function animateSecantToTangent(f, x0, canvas) {
  const ctx = canvas.getContext('2d');
  let h = 2; // Start with h = 2

  function animate() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    // Draw function
    drawFunction(f, canvas);

    // Calculate secant slope
    const y0 = f(x0);
    const y1 = f(x0 + h);
    const slope = (y1 - y0) / h;

    // Draw secant line
    drawSecantLine(x0, y0, x0 + h, y1, canvas);

    // Display values
    ctx.fillStyle = '#333';
    ctx.font = 'bold 16px Arial';
    ctx.fillText(`h = ${h.toFixed(4)}`, 20, 30);
    ctx.fillText(`Secant slope = ${slope.toFixed(4)}`, 20, 50);

    if (h > 0.0001) {
      h *= 0.95; // Gradually decrease h
      setTimeout(animate, 50);
    } else {
      ctx.fillText('→ Tangent line!', 20, 70);
      const derivative = numericalDerivative(f, x0);
      ctx.fillText(`Derivative = ${derivative.toFixed(4)}`, 20, 90);
    }
  }

  animate();
}

Rate of Change Explorer

function exploreRateOfChange(scenario, canvas) {
  // Scenarios: distance-time → velocity, velocity-time → acceleration, etc.
  const scenarios = {
    position: {
      f: (t) => 5 * t * t, // Position function
      derivative: 'Velocity',
      units: 'm/s',
      explanation: 'How fast position changes = velocity'
    },
    velocity: {
      f: (t) => 10 * t, // Velocity function
      derivative: 'Acceleration',
      units: 'm/s²',
      explanation: 'How fast velocity changes = acceleration'
    },
    population: {
      f: (t) => 1000 * Math.exp(0.1 * t), // Exponential growth
      derivative: 'Growth Rate',
      units: 'people/year',
      explanation: 'How fast population changes = growth rate'
    }
  };

  const s = scenarios[scenario];
  const ctx = canvas.getContext('2d');

  // Draw both function and derivative
  drawTwoGraphs(s.f, (x) => numericalDerivative(s.f, x), canvas);

  return s;
}

Integrals

Riemann Sum Visualizer

function drawRiemannSum(f, a, b, n, method, canvas) {
  const ctx = canvas.getContext('2d');
  const width = canvas.width;
  const height = canvas.height;
  const dx = (b - a) / n;

  let sum = 0;

  // Draw function
  ctx.strokeStyle = '#667eea';
  ctx.lineWidth = 3;
  ctx.beginPath();

  for (let x = a; x <= b; x += 0.01) {
    const y = f(x);
    const px = ((x - a) / (b - a)) * width;
    const py = height - (y / 10) * height;

    if (x === a) ctx.moveTo(px, py);
    else ctx.lineTo(px, py);
  }
  ctx.stroke();

  // Draw rectangles
  for (let i = 0; i < n; i++) {
    const x = a + i * dx;
    let sampleX;

    switch(method) {
      case 'left':
        sampleX = x;
        break;
      case 'right':
        sampleX = x + dx;
        break;
      case 'midpoint':
        sampleX = x + dx / 2;
        break;
      case 'trapezoid':
        // Will handle separately
        break;
    }

    if (method !== 'trapezoid') {
      const height_rect = f(sampleX);
      sum += height_rect * dx;

      // Draw rectangle
      const px = ((x - a) / (b - a)) * width;
      const pw = (dx / (b - a)) * width;
      const ph = (height_rect / 10) * height;

      ctx.fillStyle = 'rgba(102, 126, 234, 0.3)';
      ctx.fillRect(px, height - ph, pw, ph);
      ctx.strokeStyle = '#667eea';
      ctx.strokeRect(px, height - ph, pw, ph);
    }
  }

  // Display sum
  ctx.fillStyle = '#333';
  ctx.font = 'bold 18px Arial';
  ctx.fillText(`Rectangles: ${n}`, 20, 30);
  ctx.fillText(`Approximate Area: ${sum.toFixed(4)}`, 20, 55);

  return sum;
}

function animateRiemannIncrease(f, a, b, canvas) {
  let n = 1;

  function animate() {
    const sum = drawRiemannSum(f, a, b, n, 'midpoint', canvas);

    if (n < 100) {
      n++;
      setTimeout(animate, 100);
    } else {
      // Show exact integral
      const exact = exactIntegral(f, a, b);
      const ctx = canvas.getContext('2d');
      ctx.fillStyle = '#FF6347';
      ctx.font = 'bold 18px Arial';
      ctx.fillText(`Exact Area: ${exact.toFixed(4)}`, 20, 80);
    }
  }

  animate();
}

Area Under Curve

function calculateDefiniteIntegral(f, a, b, method = 'simpson') {
  const n = 1000; // Number of subdivisions
  const h = (b - a) / n;
  let sum = 0;

  switch(method) {
    case 'simpson':
      // Simpson's Rule (most accurate)
      sum = f(a) + f(b);
      for (let i = 1; i < n; i++) {
        const x = a + i * h;
        sum += (i % 2 === 0 ? 2 : 4) * f(x);
      }
      sum *= h / 3;
      break;

    case 'trapezoidal':
      sum = (f(a) + f(b)) / 2;
      for (let i = 1; i < n; i++) {
        sum += f(a + i * h);
      }
      sum *= h;
      break;

    case 'midpoint':
      for (let i = 0; i < n; i++) {
        sum += f(a + (i + 0.5) * h);
      }
      sum *= h;
      break;
  }

  return sum;
}

Accumulation Function

function drawAccumulationFunction(f, a, canvas) {
  // Draw A(x) = ∫[a to x] f(t) dt
  const ctx = canvas.getContext('2d');
  const width = canvas.width;
  const height = canvas.height;

  // Original function f
  ctx.strokeStyle = '#667eea';
  ctx.lineWidth = 2;
  ctx.beginPath();

  for (let x = -5; x <= 5; x += 0.1) {
    const y = f(x);
    const px = (x + 5) * (width / 10);
    const py = height / 2 - y * 20;

    if (x === -5) ctx.moveTo(px, py);
    else ctx.lineTo(px, py);
  }
  ctx.stroke();

  // Accumulation function A(x)
  ctx.strokeStyle = '#FF6347';
  ctx.lineWidth = 3;
  ctx.beginPath();

  for (let x = -5; x <= 5; x += 0.1) {
    const y = calculateDefiniteIntegral(f, a, x);
    const px = (x + 5) * (width / 10);
    const py = height / 2 - y * 20;

    if (x === -5) ctx.moveTo(px, py);
    else ctx.lineTo(px, py);
  }
  ctx.stroke();

  // Labels
  ctx.fillStyle = '#333';
  ctx.font = '16px Arial';
  ctx.fillText('f(x) - Original function', 20, 30);
  ctx.fillStyle = '#FF6347';
  ctx.fillText('A(x) = ∫f(t)dt - Accumulation', 20, 55);
}

Limits

Limit Visualizer

function visualizeLimit(f, a, canvas) {
  const ctx = canvas.getContext('2d');
  const width = canvas.width;
  const height = canvas.height;

  // Draw function
  ctx.strokeStyle = '#667eea';
  ctx.lineWidth = 3;
  ctx.beginPath();

  let leftLimit = null;
  let rightLimit = null;

  for (let x = -5; x <= 5; x += 0.01) {
    if (Math.abs(x - a) > 0.001) { // Skip the point
      const y = f(x);
      if (isFinite(y)) {
        const px = (x + 5) * (width / 10);
        const py = height / 2 - y * 20;

        if (x === -5) ctx.moveTo(px, py);
        else ctx.lineTo(px, py);

        // Track limits
        if (x < a && x > a - 0.1) leftLimit = y;
        if (x > a && x < a + 0.1) rightLimit = y;
      }
    }
  }
  ctx.stroke();

  // Mark point of interest
  const px = (a + 5) * (width / 10);
  const py_left = height / 2 - leftLimit * 20;
  const py_right = height / 2 - rightLimit * 20;

  // Open circles for limit points
  ctx.strokeStyle = '#FF6347';
  ctx.lineWidth = 3;
  ctx.beginPath();
  ctx.arc(px, py_left, 6, 0, Math.PI * 2);
  ctx.stroke();

  // Display limit values
  ctx.fillStyle = '#333';
  ctx.font = 'bold 16px Arial';
  ctx.fillText(`lim (x→${a}⁻) = ${leftLimit?.toFixed(3)}`, 20, 30);
  ctx.fillText(`lim (x→${a}⁺) = ${rightLimit?.toFixed(3)}`, 20, 55);

  const limitExists = Math.abs(leftLimit - rightLimit) < 0.01;
  if (limitExists) {
    ctx.fillStyle = '#4CAF50';
    ctx.fillText(`Limit exists: ${leftLimit.toFixed(3)}`, 20, 80);
  } else {
    ctx.fillStyle = '#FF6347';
    ctx.fillText('Limit does not exist', 20, 80);
  }

  return { leftLimit, rightLimit, limitExists };
}

Interactive Epsilon-Delta

function visualizeEpsilonDelta(f, a, L, epsilon, canvas) {
  const ctx = canvas.getContext('2d');

  // Draw function
  drawFunction(f, canvas);

  // Draw epsilon band
  const py_upper = height / 2 - (L + epsilon) * 20;
  const py_lower = height / 2 - (L - epsilon) * 20;

  ctx.fillStyle = 'rgba(255, 99, 71, 0.2)';
  ctx.fillRect(0, py_upper, width, py_lower - py_upper);

  // Find delta
  let delta = 0.1;
  for (let d = 0.01; d < 5; d += 0.01) {
    const y_left = f(a - d);
    const y_right = f(a + d);

    if (Math.abs(y_left - L) < epsilon && Math.abs(y_right - L) < epsilon) {
      delta = d;
    } else {
      break;
    }
  }

  // Draw delta interval
  const px_left = (a - delta + 5) * (width / 10);
  const px_right = (a + delta + 5) * (width / 10);

  ctx.fillStyle = 'rgba(102, 126, 234, 0.2)';
  ctx.fillRect(px_left, 0, px_right - px_left, height);

  // Labels
  ctx.fillStyle = '#333';
  ctx.font = 'bold 16px Arial';
  ctx.fillText(`ε = ${epsilon.toFixed(3)}`, 20, 30);
  ctx.fillText(`δ = ${delta.toFixed(3)}`, 20, 55);
  ctx.fillText(`For |x - ${a}| < δ, |f(x) - ${L}| < ε`, 20, 80);

  return delta;
}

Optimization

Critical Points Finder

function findCriticalPoints(f, a, b) {
  const points = [];
  const step = (b - a) / 1000;

  for (let x = a; x <= b; x += step) {
    const derivative = numericalDerivative(f, x);

    // Check if derivative is close to zero
    if (Math.abs(derivative) < 0.01) {
      const secondDerivative = numericalDerivative(
        (t) => numericalDerivative(f, t),
        x
      );

      points.push({
        x: x,
        y: f(x),
        type: secondDerivative < 0 ? 'local maximum' :
              secondDerivative > 0 ? 'local minimum' :
              'inflection point',
        derivative: derivative,
        secondDerivative: secondDerivative
      });
    }
  }

  return points;
}

function visualizeOptimization(f, a, b, canvas) {
  const ctx = canvas.getContext('2d');

  // Draw function
  drawFunction(f, canvas);

  // Find and mark critical points
  const criticalPoints = findCriticalPoints(f, a, b);

  criticalPoints.forEach(point => {
    const px = (point.x + 5) * (width / 10);
    const py = height / 2 - point.y * 20;

    // Different colors for different types
    ctx.fillStyle = point.type.includes('maximum') ? '#4CAF50' :
                    point.type.includes('minimum') ? '#FF6347' :
                    '#FFD700';

    ctx.beginPath();
    ctx.arc(px, py, 8, 0, Math.PI * 2);
    ctx.fill();

    // Label
    ctx.fillStyle = '#333';
    ctx.font = '12px Arial';
    ctx.fillText(`${point.type}`, px + 10, py - 10);
    ctx.fillText(`(${point.x.toFixed(2)}, ${point.y.toFixed(2)})`,
                 px + 10, py + 5);
  });

  return criticalPoints;
}

Related Rates

Related Rates Visualizer

function visualizeRelatedRates(scenario, rate, time, canvas) {
  const scenarios = {
    ladder: {
      // Ladder sliding down wall
      length: 10, // Ladder length
      rate: rate, // dx/dt (horizontal speed)
      draw: function(t) {
        const x = rate * t;
        const y = Math.sqrt(this.length * this.length - x * x);
        const dy_dt = -(x * rate) / y; // dy/dt calculated

        drawLadder(x, y, canvas);
        return { x, y, dx_dt: rate, dy_dt };
      }
    },
    balloon: {
      // Expanding balloon
      rate: rate, // dr/dt (radius growth rate)
      draw: function(t) {
        const r = 1 + rate * t;
        const V = (4/3) * Math.PI * r * r * r;
        const dV_dt = 4 * Math.PI * r * r * rate; // dV/dt

        drawBalloon(r, canvas);
        return { r, V, dr_dt: rate, dV_dt };
      }
    }
  };

  return scenarios[scenario].draw(time);
}

Summary

Calculus patterns provide:

  • Visual derivative calculations with tangent lines
  • Riemann sum animations showing integral approximation
  • Limit visualization with epsilon-delta
  • Critical point finding for optimization
  • Related rates scenarios with animations

These tools make abstract calculus concepts concrete and interactive!

Source: SKILL.md on GitHub

3 warnings16d5 checks · Risk MEDIUM
  • Gen Agent Trust Hub16d

    The math-teacher skill provides a platform for generating interactive educational tools but exhibits several security risks, most notably the inclusion of templates that use the unsafe `eval()` function. Additionally, it exposes local system paths and utilizes scripts that bridge the agent's environment to the host operating system, creating potential vectors for code execution and data exposure.

  • Socket16d

    1 alert: gptSecurity

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer7mo

    7/7 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 98139d5. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Dormantupdated 11 months ago

README badge

README badge for jamesrochabrun/skills/math-teacher