Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:48:55 +08:00
commit f28999f19c
127 changed files with 62038 additions and 0 deletions

View File

@@ -0,0 +1,505 @@
# Algebra Reference
Algebraic concepts and interactive visualizations for middle school to high school.
## Variables & Expressions
### Visual Variables
```javascript
// Mystery box representation
function drawVariable(name, value, canvas) {
const ctx = canvas.getContext('2d');
// Draw box
ctx.fillStyle = '#667eea';
ctx.fillRect(50, 50, 100, 100);
ctx.strokeStyle = '#333';
ctx.lineWidth = 3;
ctx.strokeRect(50, 50, 100, 100);
// Variable name
ctx.fillStyle = 'white';
ctx.font = 'bold 40px Arial';
ctx.textAlign = 'center';
ctx.fillText(name, 100, 110);
// Value (revealed)
if (value !== undefined) {
ctx.fillStyle = '#FFD700';
ctx.font = 'bold 30px Arial';
ctx.fillText(`= ${value}`, 100, 170);
} else {
ctx.fillStyle = '#FFF';
ctx.font = '20px Arial';
ctx.fillText('?', 100, 170);
}
}
```
### Expression Evaluator
```javascript
function evaluateExpression(expr, variables) {
// Replace variables with values
let result = expr;
for (const [name, value] of Object.entries(variables)) {
result = result.replace(new RegExp(name, 'g'), value);
}
try {
return {
expression: expr,
substituted: result,
result: eval(result),
steps: showSteps(expr, variables)
};
} catch (e) {
return { error: 'Invalid expression' };
}
}
function showSteps(expr, variables) {
const steps = [];
steps.push(`Original: ${expr}`);
let current = expr;
for (const [name, value] of Object.entries(variables)) {
current = current.replace(new RegExp(name, 'g'), value);
steps.push(`Substitute ${name} = ${value}: ${current}`);
}
steps.push(`Evaluate: ${eval(current)}`);
return steps;
}
```
## Linear Equations
### Equation Solver
```javascript
// Solve ax + b = c for x
function solveLinear(a, b, c) {
const x = (c - b) / a;
return {
equation: `${a}x + ${b} = ${c}`,
steps: [
`${a}x + ${b} = ${c}`,
`${a}x = ${c - b}`,
`x = ${(c - b)}/${a}`,
`x = ${x}`
],
solution: x,
verification: `${a}(${x}) + ${b} = ${a * x + b}`
};
}
```
### Balance Scale Visualization
```javascript
function drawBalanceScale(left, right, canvas) {
const ctx = canvas.getContext('2d');
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
// Calculate balance
const diff = left - right;
const angle = Math.atan(diff / 10);
// Draw fulcrum
ctx.fillStyle = '#333';
ctx.beginPath();
ctx.moveTo(centerX - 20, centerY + 50);
ctx.lineTo(centerX, centerY);
ctx.lineTo(centerX + 20, centerY + 50);
ctx.closePath();
ctx.fill();
// Draw beam
ctx.save();
ctx.translate(centerX, centerY);
ctx.rotate(angle);
ctx.fillStyle = '#8B4513';
ctx.fillRect(-150, -10, 300, 20);
// Left side
ctx.fillStyle = '#667eea';
ctx.fillRect(-140, -60, 80, 80);
ctx.fillStyle = 'white';
ctx.font = 'bold 24px Arial';
ctx.textAlign = 'center';
ctx.fillText(left, -100, -10);
// Right side
ctx.fillStyle = '#FF6347';
ctx.fillRect(60, -60, 80, 80);
ctx.fillStyle = 'white';
ctx.fillText(right, 100, -10);
ctx.restore();
// Status
ctx.fillStyle = '#333';
ctx.font = '20px Arial';
ctx.textAlign = 'center';
const status = Math.abs(diff) < 0.1 ? '⚖️ Balanced!' :
diff > 0 ? '⬅️ Left heavier' : '➡️ Right heavier';
ctx.fillText(status, centerX, centerY + 100);
}
```
## Quadratic Equations
### Quadratic Formula
```javascript
function solveQuadratic(a, b, c) {
const discriminant = b * b - 4 * a * c;
const result = {
equation: `${a}x² + ${b}x + ${c} = 0`,
discriminant: discriminant,
a, b, c
};
if (discriminant > 0) {
const x1 = (-b + Math.sqrt(discriminant)) / (2 * a);
const x2 = (-b - Math.sqrt(discriminant)) / (2 * a);
result.solutions = [x1, x2];
result.type = 'Two real solutions';
result.message = '🎉 Two x-intercepts!';
} else if (discriminant === 0) {
const x = -b / (2 * a);
result.solutions = [x];
result.type = 'One real solution';
result.message = '🎯 One x-intercept (vertex on x-axis)!';
} else {
const realPart = -b / (2 * a);
const imagPart = Math.sqrt(-discriminant) / (2 * a);
result.solutions = [
`${realPart} + ${imagPart}i`,
`${realPart} - ${imagPart}i`
];
result.type = 'Two complex solutions';
result.message = '👻 No x-intercepts (complex numbers)!';
}
return result;
}
```
### Parabola Grapher
```javascript
function drawParabola(a, b, c, canvas) {
const ctx = canvas.getContext('2d');
const width = canvas.width;
const height = canvas.height;
// Clear canvas
ctx.clearRect(0, 0, width, height);
// Draw axes
drawAxes(ctx, width, height);
// Calculate vertex
const vertexX = -b / (2 * a);
const vertexY = a * vertexX * vertexX + b * vertexX + c;
// Draw parabola
ctx.beginPath();
ctx.strokeStyle = '#667eea';
ctx.lineWidth = 3;
for (let x = -10; x <= 10; x += 0.1) {
const y = a * x * x + b * x + c;
const px = (x + 10) * (width / 20);
const py = height - ((y + 10) * (height / 20));
if (x === -10) ctx.moveTo(px, py);
else ctx.lineTo(px, py);
}
ctx.stroke();
// Mark vertex
const vx = (vertexX + 10) * (width / 20);
const vy = height - ((vertexY + 10) * (height / 20));
ctx.fillStyle = '#FF6347';
ctx.beginPath();
ctx.arc(vx, vy, 8, 0, Math.PI * 2);
ctx.fill();
// Vertex label
ctx.fillStyle = '#333';
ctx.font = '14px Arial';
ctx.fillText(`Vertex: (${vertexX.toFixed(2)}, ${vertexY.toFixed(2)})`,
vx + 10, vy - 10);
// Draw axis of symmetry
ctx.strokeStyle = '#FFD700';
ctx.setLineDash([5, 5]);
ctx.beginPath();
ctx.moveTo(vx, 0);
ctx.lineTo(vx, height);
ctx.stroke();
ctx.setLineDash([]);
return { vertexX, vertexY };
}
function drawAxes(ctx, width, height) {
ctx.strokeStyle = '#CCC';
ctx.lineWidth = 1;
// X-axis
ctx.beginPath();
ctx.moveTo(0, height / 2);
ctx.lineTo(width, height / 2);
ctx.stroke();
// Y-axis
ctx.beginPath();
ctx.moveTo(width / 2, 0);
ctx.lineTo(width / 2, height);
ctx.stroke();
// Grid
ctx.strokeStyle = '#F0F0F0';
for (let i = 0; i < width; i += width / 20) {
ctx.beginPath();
ctx.moveTo(i, 0);
ctx.lineTo(i, height);
ctx.stroke();
}
for (let i = 0; i < height; i += height / 20) {
ctx.beginPath();
ctx.moveTo(0, i);
ctx.lineTo(width, i);
ctx.stroke();
}
}
```
## Functions
### Function Visualizer
```javascript
const commonFunctions = {
linear: (x, m, b) => m * x + b,
quadratic: (x, a, b, c) => a * x * x + b * x + c,
cubic: (x, a) => a * x * x * x,
exponential: (x, a) => Math.pow(a, x),
logarithmic: (x, a) => Math.log(x) / Math.log(a),
sine: (x, a) => a * Math.sin(x),
cosine: (x, a) => a * Math.cos(x),
absolute: (x) => Math.abs(x),
squareRoot: (x) => Math.sqrt(x)
};
function plotFunction(fn, xMin, xMax, canvas) {
const ctx = canvas.getContext('2d');
const width = canvas.width;
const height = canvas.height;
drawAxes(ctx, width, height);
ctx.beginPath();
ctx.strokeStyle = '#667eea';
ctx.lineWidth = 3;
const step = (xMax - xMin) / width;
for (let x = xMin; x <= xMax; x += step) {
try {
const y = fn(x);
if (!isNaN(y) && isFinite(y)) {
const px = ((x - xMin) / (xMax - xMin)) * width;
const py = height - ((y - (-10)) / 20) * height;
if (x === xMin) ctx.moveTo(px, py);
else ctx.lineTo(px, py);
}
} catch (e) {
// Skip invalid points
}
}
ctx.stroke();
}
```
### Domain & Range Finder
```javascript
function analyzeFunctionDomainRange(type, params) {
const analysis = {
type: type,
params: params
};
switch(type) {
case 'linear':
analysis.domain = '(-∞, ∞)';
analysis.range = '(-∞, ∞)';
break;
case 'quadratic':
const a = params.a;
const vertex = -params.b / (2 * a);
const vertexY = a * vertex * vertex + params.b * vertex + params.c;
analysis.domain = '(-∞, ∞)';
analysis.range = a > 0 ? `[${vertexY.toFixed(2)}, ∞)` :
`(-∞, ${vertexY.toFixed(2)}]`;
analysis.vertex = { x: vertex, y: vertexY };
break;
case 'squareRoot':
analysis.domain = '[0, ∞)';
analysis.range = '[0, ∞)';
break;
case 'logarithmic':
analysis.domain = '(0, ∞)';
analysis.range = '(-∞, ∞)';
break;
}
return analysis;
}
```
## Systems of Equations
### Graphical Solution
```javascript
function solveSystemGraphically(eq1, eq2, canvas) {
// eq1 and eq2 are linear equations in form {m: slope, b: intercept}
const ctx = canvas.getContext('2d');
const width = canvas.width;
const height = canvas.height;
drawAxes(ctx, width, height);
// Plot first equation
ctx.strokeStyle = '#667eea';
ctx.lineWidth = 3;
ctx.beginPath();
for (let x = -10; x <= 10; x += 0.1) {
const y = eq1.m * x + eq1.b;
const px = (x + 10) * (width / 20);
const py = height - ((y + 10) * (height / 20));
if (x === -10) ctx.moveTo(px, py);
else ctx.lineTo(px, py);
}
ctx.stroke();
// Plot second equation
ctx.strokeStyle = '#FF6347';
ctx.beginPath();
for (let x = -10; x <= 10; x += 0.1) {
const y = eq2.m * x + eq2.b;
const px = (x + 10) * (width / 20);
const py = height - ((y + 10) * (height / 20));
if (x === -10) ctx.moveTo(px, py);
else ctx.lineTo(px, py);
}
ctx.stroke();
// Find intersection
// eq1.m * x + eq1.b = eq2.m * x + eq2.b
// (eq1.m - eq2.m) * x = eq2.b - eq1.b
const x = (eq2.b - eq1.b) / (eq1.m - eq2.m);
const y = eq1.m * x + eq1.b;
// Mark intersection
const px = (x + 10) * (width / 20);
const py = height - ((y + 10) * (height / 20));
ctx.fillStyle = '#FFD700';
ctx.beginPath();
ctx.arc(px, py, 10, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#333';
ctx.font = 'bold 16px Arial';
ctx.fillText(`(${x.toFixed(2)}, ${y.toFixed(2)})`, px + 15, py - 15);
return { x, y };
}
```
## Polynomials
### Polynomial Evaluator
```javascript
function evaluatePolynomial(coefficients, x) {
// coefficients = [a0, a1, a2, ...] for a0 + a1*x + a2*x^2 + ...
let result = 0;
let term = 1;
const terms = [];
for (let i = 0; i < coefficients.length; i++) {
const value = coefficients[i] * term;
result += value;
terms.push({
coefficient: coefficients[i],
power: i,
value: value,
display: i === 0 ? `${coefficients[i]}` :
i === 1 ? `${coefficients[i]}x` :
`${coefficients[i]}x^${i}`
});
term *= x;
}
return {
x: x,
result: result,
terms: terms,
polynomial: formatPolynomial(coefficients)
};
}
function formatPolynomial(coefficients) {
return coefficients.map((c, i) => {
if (c === 0) return '';
if (i === 0) return `${c}`;
if (i === 1) return `${c}x`;
return `${c}x^${i}`;
}).filter(t => t).join(' + ');
}
```
## Interactive Elements
### Slider for Coefficients
```javascript
function createCoefficientSliders(equation) {
const sliders = {};
const params = ['a', 'b', 'c'];
params.forEach(param => {
const slider = document.createElement('input');
slider.type = 'range';
slider.min = -10;
slider.max = 10;
slider.step = 0.1;
slider.value = equation[param] || 0;
slider.addEventListener('input', () => {
equation[param] = parseFloat(slider.value);
updateGraph();
updateEquationDisplay();
});
sliders[param] = slider;
});
return sliders;
}
```
## Summary
Algebra patterns provide:
- Visual equation solving with balance scales
- Interactive function graphing
- Step-by-step solutions
- Real-time parameter manipulation
- Geometric representations of algebraic concepts
These tools make abstract algebra concrete and interactive!

View File

@@ -0,0 +1,370 @@
# Basic Math Reference
Elementary mathematics concepts for interactive playgrounds.
## Arithmetic Operations
### Addition
```javascript
// Visual addition with counting blocks
function visualAdd(a, b) {
return {
result: a + b,
visualization: `${'🟦'.repeat(a)} + ${'🟨'.repeat(b)} = ${'🟩'.repeat(a + b)}`
};
}
```
### Multiplication
```javascript
// Array/grid visualization
function visualMultiply(rows, cols) {
let grid = '';
for (let i = 0; i < rows; i++) {
grid += '⬜'.repeat(cols) + '\n';
}
return {
result: rows * cols,
grid: grid,
explanation: `${rows} rows × ${cols} columns = ${rows * cols} squares`
};
}
```
## Fractions
### Visual Representation
```javascript
function drawFraction(numerator, denominator, canvas) {
const ctx = canvas.getContext('2d');
const width = canvas.width;
const height = canvas.height;
const sliceWidth = width / denominator;
for (let i = 0; i < denominator; i++) {
ctx.fillStyle = i < numerator ? '#FF6347' : '#DDD';
ctx.fillRect(i * sliceWidth, 0, sliceWidth - 2, height);
}
}
```
### Equivalent Fractions
```javascript
function findEquivalent(numerator, denominator, multiplier) {
return {
original: `${numerator}/${denominator}`,
equivalent: `${numerator * multiplier}/${denominator * multiplier}`,
explanation: `Multiply both by ${multiplier}`
};
}
function simplify(numerator, denominator) {
const gcd = (a, b) => b === 0 ? a : gcd(b, a % b);
const divisor = gcd(numerator, denominator);
return {
original: `${numerator}/${denominator}`,
simplified: `${numerator / divisor}/${denominator / divisor}`,
divisor: divisor
};
}
```
## Geometry
### Area Calculations
```javascript
// Rectangle
function rectangleArea(length, width) {
return {
area: length * width,
perimeter: 2 * (length + width),
visualization: drawRectangle(length, width)
};
}
// Circle
function circleArea(radius) {
return {
area: Math.PI * radius * radius,
circumference: 2 * Math.PI * radius,
diameter: 2 * radius
};
}
// Triangle
function triangleArea(base, height) {
return {
area: 0.5 * base * height,
explanation: 'Half of base × height'
};
}
```
### Angle Visualizer
```javascript
function drawAngle(degrees, canvas) {
const ctx = canvas.getContext('2d');
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const radius = 100;
// Draw angle arc
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, degrees * Math.PI / 180);
ctx.lineTo(centerX, centerY);
ctx.closePath();
ctx.fillStyle = 'rgba(102, 126, 234, 0.3)';
ctx.fill();
ctx.strokeStyle = '#667eea';
ctx.lineWidth = 3;
ctx.stroke();
// Label
ctx.fillStyle = '#333';
ctx.font = '20px Arial';
ctx.fillText(`${degrees}°`, centerX + 50, centerY - 50);
}
```
## Number Patterns
### Sequences
```javascript
// Arithmetic sequence
function arithmeticSequence(start, difference, terms) {
const sequence = [];
for (let i = 0; i < terms; i++) {
sequence.push(start + (i * difference));
}
return {
sequence: sequence,
rule: `Start at ${start}, add ${difference} each time`,
next: start + (terms * difference)
};
}
// Geometric sequence
function geometricSequence(start, ratio, terms) {
const sequence = [];
for (let i = 0; i < terms; i++) {
sequence.push(start * Math.pow(ratio, i));
}
return {
sequence: sequence,
rule: `Start at ${start}, multiply by ${ratio} each time`,
next: start * Math.pow(ratio, terms)
};
}
```
## Time & Money
### Clock
```javascript
function drawClock(hours, minutes) {
// Draw clock face with hands
const hourAngle = (hours % 12) * 30 + minutes * 0.5;
const minuteAngle = minutes * 6;
return {
hourAngle: hourAngle,
minuteAngle: minuteAngle,
timeString: `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`
};
}
```
### Money
```javascript
function calculateChange(paid, cost) {
const change = paid - cost;
const bills = {
'20': Math.floor(change / 20),
'10': Math.floor((change % 20) / 10),
'5': Math.floor((change % 10) / 5),
'1': Math.floor(change % 5)
};
return {
change: change.toFixed(2),
breakdown: bills,
visualization: visualizeChange(bills)
};
}
```
## Interactive Elements
### Number Line
```javascript
function drawNumberLine(min, max, highlight, canvas) {
const ctx = canvas.getContext('2d');
const width = canvas.width;
const height = canvas.height;
const y = height / 2;
// Draw line
ctx.strokeStyle = '#333';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(20, y);
ctx.lineTo(width - 20, y);
ctx.stroke();
// Draw numbers
const range = max - min;
const step = (width - 40) / range;
for (let i = min; i <= max; i++) {
const x = 20 + (i - min) * step;
// Tick mark
ctx.beginPath();
ctx.moveTo(x, y - 10);
ctx.lineTo(x, y + 10);
ctx.stroke();
// Number label
ctx.fillStyle = i === highlight ? '#FF6347' : '#333';
ctx.font = i === highlight ? 'bold 20px Arial' : '16px Arial';
ctx.textAlign = 'center';
ctx.fillText(i, x, y + 30);
// Highlight
if (i === highlight) {
ctx.beginPath();
ctx.arc(x, y, 8, 0, Math.PI * 2);
ctx.fillStyle = '#FF6347';
ctx.fill();
}
}
}
```
### Counting Blocks
```javascript
function drawCountingBlocks(number, canvas) {
const ctx = canvas.getContext('2d');
const blockSize = 40;
const gap = 10;
const blocksPerRow = 10;
for (let i = 0; i < number; i++) {
const row = Math.floor(i / blocksPerRow);
const col = i % blocksPerRow;
const x = col * (blockSize + gap);
const y = row * (blockSize + gap);
// Draw block
ctx.fillStyle = '#667eea';
ctx.fillRect(x, y, blockSize, blockSize);
ctx.strokeStyle = '#333';
ctx.strokeRect(x, y, blockSize, blockSize);
// Number in block
ctx.fillStyle = 'white';
ctx.font = 'bold 20px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(i + 1, x + blockSize / 2, y + blockSize / 2);
}
}
```
## Word Problems
### Template System
```javascript
const wordProblemTemplates = {
addition: [
"🍎 Sarah has {a} apples. Her friend gives her {b} more. How many apples does Sarah have now?",
"🚗 There are {a} cars in the parking lot. {b} more cars arrive. How many cars are there in total?",
"⭐ Tom collected {a} stars. He then collected {b} more stars. How many stars does Tom have?"
],
subtraction: [
"🍪 Mom baked {a} cookies. The family ate {b} cookies. How many cookies are left?",
"🎈 There were {a} balloons at the party. {b} balloons popped. How many balloons remain?",
"💰 You have ${a}. You spend ${b}. How much money do you have left?"
],
multiplication: [
"📦 Each box contains {a} toys. You have {b} boxes. How many toys do you have in total?",
"🌳 Each tree has {a} apples. There are {b} trees. How many apples are there?",
"👥 Each team has {a} players. There are {b} teams. How many players in total?"
],
division: [
"🍕 You have {a} pizza slices to share equally among {b} friends. How many slices does each friend get?",
"🎁 {a} presents need to be distributed equally to {b} children. How many presents per child?",
"📚 {a} books are arranged into {b} equal stacks. How many books in each stack?"
]
};
function generateWordProblem(type, difficulty) {
const template = wordProblemTemplates[type][
Math.floor(Math.random() * wordProblemTemplates[type].length)
];
const range = difficulty === 'easy' ? 10 : difficulty === 'medium' ? 50 : 100;
const a = Math.floor(Math.random() * range) + 1;
const b = Math.floor(Math.random() * range) + 1;
const problem = template.replace('{a}', a).replace('{b}', b);
const answer = calculateAnswer(type, a, b);
return { problem, answer, a, b };
}
function calculateAnswer(type, a, b) {
switch(type) {
case 'addition': return a + b;
case 'subtraction': return a - b;
case 'multiplication': return a * b;
case 'division': return Math.floor(a / b);
}
}
```
## Game Mechanics
### Points System
```javascript
const scoring = {
correct: {
first_try: 10,
second_try: 7,
third_try: 5,
with_hint: 3
},
streak: {
multiplier: (streak) => Math.min(1 + (streak * 0.1), 3.0)
},
speed: {
bonus: (seconds) => seconds < 5 ? 5 : seconds < 10 ? 3 : 0
}
};
function calculatePoints(attempt, streak, seconds, usedHint) {
let basePoints = scoring.correct.first_try;
if (usedHint) basePoints = scoring.correct.with_hint;
else if (attempt === 2) basePoints = scoring.correct.second_try;
else if (attempt >= 3) basePoints = scoring.correct.third_try;
const streakMultiplier = scoring.streak.multiplier(streak);
const speedBonus = scoring.speed.bonus(seconds);
return Math.floor(basePoints * streakMultiplier) + speedBonus;
}
```
## Summary
These basic math patterns provide:
- Visual representations for concrete understanding
- Interactive manipulatives for hands-on learning
- Gamification elements for engagement
- Progressive difficulty scaffolding
- Clear explanations with every calculation
Use these as building blocks for creating engaging math playgrounds!

View File

@@ -0,0 +1,565 @@
# Calculus Reference
Advanced calculus concepts with interactive visualizations.
## Derivatives
### Derivative Calculator
```javascript
// 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
```javascript
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
```javascript
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
```javascript
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
```javascript
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
```javascript
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
```javascript
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
```javascript
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
```javascript
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
```javascript
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
```javascript
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!

View File

@@ -0,0 +1,635 @@
# Gamification Reference
Game mechanics, reward systems, and engagement techniques for math learning.
## Points System
### Base Points
```javascript
const POINTS = {
// Correctness
CORRECT_FIRST_TRY: 10,
CORRECT_SECOND_TRY: 7,
CORRECT_THIRD_TRY: 5,
CORRECT_WITH_HINT: 3,
// Exploration
TRY_DIFFERENT_VALUE: 2,
DISCOVER_PATTERN: 15,
FIND_SPECIAL_CASE: 20,
// Speed
SPEED_BONUS_5SEC: 5,
SPEED_BONUS_10SEC: 3,
SPEED_BONUS_30SEC: 1,
// Completion
COMPLETE_LEVEL: 50,
COMPLETE_CHALLENGE: 100,
PERFECT_SCORE: 200,
// Daily
DAILY_LOGIN: 10,
DAILY_CHALLENGE: 25
};
```
### Multipliers
```javascript
function calculateMultiplier(state) {
let multiplier = 1.0;
// Streak multiplier
if (state.streak >= 3) multiplier += 0.5;
if (state.streak >= 5) multiplier += 0.5;
if (state.streak >= 10) multiplier += 1.0;
// Difficulty multiplier
multiplier *= {
'easy': 1.0,
'medium': 1.5,
'hard': 2.0,
'expert': 3.0
}[state.difficulty] || 1.0;
// Level multiplier
multiplier *= (1 + (state.level * 0.1));
return Math.min(multiplier, 5.0); // Cap at 5x
}
```
### Total Score Calculation
```javascript
function awardPoints(basePoints, state) {
const multiplier = calculateMultiplier(state);
const speedBonus = calculateSpeedBonus(state.timeSpent);
const total = Math.floor(basePoints * multiplier) + speedBonus;
return {
base: basePoints,
multiplier: multiplier,
speedBonus: speedBonus,
total: total,
breakdown: `${basePoints} × ${multiplier.toFixed(1)} + ${speedBonus}`
};
}
function calculateSpeedBonus(seconds) {
if (seconds < 5) return POINTS.SPEED_BONUS_5SEC;
if (seconds < 10) return POINTS.SPEED_BONUS_10SEC;
if (seconds < 30) return POINTS.SPEED_BONUS_30SEC;
return 0;
}
```
## Achievements
### Achievement Definitions
```javascript
const ACHIEVEMENTS = {
first_steps: {
id: 'first_steps',
name: '🌟 First Steps',
description: 'Complete your first problem',
condition: (stats) => stats.problemsCompleted >= 1,
points: 10,
rarity: 'common'
},
hot_streak: {
id: 'hot_streak',
name: '🔥 Hot Streak',
description: 'Get 5 correct answers in a row',
condition: (stats) => stats.currentStreak >= 5,
points: 25,
rarity: 'uncommon'
},
speed_demon: {
id: 'speed_demon',
name: '⚡ Speed Demon',
description: 'Solve 10 problems in under 5 seconds each',
condition: (stats) => stats.fastSolves >= 10,
points: 50,
rarity: 'rare'
},
perfectionist: {
id: 'perfectionist',
name: '💯 Perfectionist',
description: 'Get 100% on a challenge',
condition: (stats) => stats.perfectScores >= 1,
points: 100,
rarity: 'epic'
},
math_master: {
id: 'math_master',
name: '🏆 Math Master',
description: 'Reach 1000 total points',
condition: (stats) => stats.totalPoints >= 1000,
points: 200,
rarity: 'legendary'
},
explorer: {
id: 'explorer',
name: '🔍 Explorer',
description: 'Try 50 different values',
condition: (stats) => stats.valuesExplored >= 50,
points: 30,
rarity: 'uncommon'
},
pattern_finder: {
id: 'pattern_finder',
name: '🧩 Pattern Finder',
description: 'Discover 5 mathematical patterns',
condition: (stats) => stats.patternsFound >= 5,
points: 75,
rarity: 'rare'
},
night_owl: {
id: 'night_owl',
name: '🦉 Night Owl',
description: 'Practice after midnight',
condition: (stats) => stats.lateNightSessions >= 1,
points: 15,
rarity: 'common'
},
early_bird: {
id: 'early_bird',
name: '🐦 Early Bird',
description: 'Practice before 6 AM',
condition: (stats) => stats.earlyMorningSessions >= 1,
points: 15,
rarity: 'common'
},
week_warrior: {
id: 'week_warrior',
name: '📅 Week Warrior',
description: 'Practice 7 days in a row',
condition: (stats) => stats.dailyStreak >= 7,
points: 150,
rarity: 'epic'
}
};
```
### Achievement Checker
```javascript
function checkAchievements(stats, unlockedAchievements) {
const newAchievements = [];
for (const [id, achievement] of Object.entries(ACHIEVEMENTS)) {
if (!unlockedAchievements.includes(id)) {
if (achievement.condition(stats)) {
newAchievements.push(achievement);
unlockedAchievements.push(id);
}
}
}
return newAchievements;
}
```
### Achievement Display
```javascript
function showAchievementPopup(achievement) {
const popup = document.createElement('div');
popup.className = 'achievement-popup';
popup.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: linear-gradient(135deg, ${getRarityColor(achievement.rarity)});
color: white;
padding: 20px 30px;
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0,0,0,0.3);
animation: slideIn 0.5s ease, pulse 0.5s ease 0.5s;
z-index: 1000;
font-weight: bold;
min-width: 250px;
`;
popup.innerHTML = `
<div style="font-size: 2em; text-align: center;">${achievement.name}</div>
<div style="margin-top: 10px; text-align: center;">${achievement.description}</div>
<div style="margin-top: 10px; text-align: center; font-size: 1.5em;">
+${achievement.points} points
</div>
`;
document.body.appendChild(popup);
// Play sound
playAchievementSound(achievement.rarity);
// Remove after 4 seconds
setTimeout(() => {
popup.style.animation = 'slideOut 0.5s ease';
setTimeout(() => popup.remove(), 500);
}, 4000);
}
function getRarityColor(rarity) {
const colors = {
common: '#909090, #606060',
uncommon: '#4CAF50, #388E3C',
rare: '#2196F3, #1565C0',
epic: '#9C27B0, #6A1B9A',
legendary: '#FFC107, #F57C00'
};
return colors[rarity] || colors.common;
}
```
## Progress Tracking
### Stats Structure
```javascript
const playerStats = {
// Basic counts
problemsAttempted: 0,
problemsCompleted: 0,
correctAnswers: 0,
incorrectAnswers: 0,
// Streaks
currentStreak: 0,
longestStreak: 0,
dailyStreak: 0,
// Performance
averageTime: 0,
fastestTime: Infinity,
fastSolves: 0,
perfectScores: 0,
// Exploration
valuesExplored: 0,
patternsFound: 0,
// Points & Level
totalPoints: 0,
level: 1,
pointsToNextLevel: 100,
// Time tracking
totalTimeSpent: 0,
sessionsCount: 0,
lastSessionDate: null,
lateNightSessions: 0,
earlyMorningSessions: 0,
// Achievements
achievementsUnlocked: [],
achievementPoints: 0
};
```
### Level System
```javascript
function calculateLevel(points) {
// Level 1: 0-100 points
// Level 2: 100-300 points
// Level 3: 300-600 points
// Formula: points_needed = 100 * level * (level + 1) / 2
let level = 1;
let pointsNeeded = 100;
let totalPointsForLevel = 0;
while (points >= totalPointsForLevel + pointsNeeded) {
totalPointsForLevel += pointsNeeded;
level++;
pointsNeeded = 100 * level;
}
return {
level: level,
currentPoints: points,
pointsInLevel: points - totalPointsForLevel,
pointsToNextLevel: pointsNeeded,
progress: (points - totalPointsForLevel) / pointsNeeded
};
}
function checkLevelUp(oldPoints, newPoints) {
const oldLevel = calculateLevel(oldPoints).level;
const newLevel = calculateLevel(newPoints).level;
if (newLevel > oldLevel) {
showLevelUpAnimation(newLevel);
return true;
}
return false;
}
```
### Progress Visualization
```javascript
function drawProgressBar(progress, canvas) {
const ctx = canvas.getContext('2d');
const width = canvas.width;
const height = 40;
// Background
ctx.fillStyle = '#E0E0E0';
ctx.fillRect(0, 0, width, height);
// Progress fill
const gradient = ctx.createLinearGradient(0, 0, width * progress, 0);
gradient.addColorStop(0, '#667eea');
gradient.addColorStop(1, '#764ba2');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, width * progress, height);
// Border
ctx.strokeStyle = '#333';
ctx.lineWidth = 2;
ctx.strokeRect(0, 0, width, height);
// Text
ctx.fillStyle = '#333';
ctx.font = 'bold 18px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(`${Math.floor(progress * 100)}%`, width / 2, height / 2);
}
```
## Reward Animations
### Confetti
```javascript
function createConfetti() {
const colors = ['#FF6347', '#FFD700', '#4CAF50', '#2196F3', '#9C27B0'];
const confettiCount = 50;
const confetti = [];
for (let i = 0; i < confettiCount; i++) {
confetti.push({
x: Math.random() * window.innerWidth,
y: -20,
vx: (Math.random() - 0.5) * 5,
vy: Math.random() * 3 + 2,
color: colors[Math.floor(Math.random() * colors.length)],
size: Math.random() * 10 + 5,
rotation: Math.random() * 360,
rotationSpeed: (Math.random() - 0.5) * 10
});
}
return confetti;
}
function animateConfetti(confetti, ctx) {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
let active = 0;
confetti.forEach(piece => {
piece.x += piece.vx;
piece.y += piece.vy;
piece.vy += 0.1; // Gravity
piece.rotation += piece.rotationSpeed;
if (piece.y < ctx.canvas.height) {
active++;
ctx.save();
ctx.translate(piece.x, piece.y);
ctx.rotate(piece.rotation * Math.PI / 180);
ctx.fillStyle = piece.color;
ctx.fillRect(-piece.size / 2, -piece.size / 2, piece.size, piece.size);
ctx.restore();
}
});
if (active > 0) {
requestAnimationFrame(() => animateConfetti(confetti, ctx));
}
}
function celebrateWithConfetti() {
const canvas = document.createElement('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.style.cssText = `
position: fixed;
top: 0;
left: 0;
pointer-events: none;
z-index: 9999;
`;
document.body.appendChild(canvas);
const ctx = canvas.getContext('2d');
const confetti = createConfetti();
animateConfetti(confetti, ctx);
setTimeout(() => canvas.remove(), 5000);
}
```
### Score Popup
```javascript
function showScorePopup(points, x, y) {
const popup = document.createElement('div');
popup.textContent = `+${points}`;
popup.style.cssText = `
position: absolute;
left: ${x}px;
top: ${y}px;
color: #FFD700;
font-size: 2em;
font-weight: bold;
animation: floatUp 1s ease-out forwards;
pointer-events: none;
text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
z-index: 1000;
`;
document.body.appendChild(popup);
setTimeout(() => popup.remove(), 1000);
}
// Add CSS animation
const style = document.createElement('style');
style.textContent = `
@keyframes floatUp {
from {
transform: translateY(0) scale(1);
opacity: 1;
}
to {
transform: translateY(-100px) scale(1.5);
opacity: 0;
}
}
`;
document.head.appendChild(style);
```
## Challenge Modes
### Time Attack
```javascript
class TimeAttackMode {
constructor(duration = 60) {
this.duration = duration;
this.timeRemaining = duration;
this.problemsSolved = 0;
this.totalPoints = 0;
this.isActive = false;
}
start() {
this.isActive = true;
this.timer = setInterval(() => {
this.timeRemaining--;
this.updateDisplay();
if (this.timeRemaining <= 0) {
this.end();
}
}, 1000);
}
solve(points) {
if (this.isActive) {
this.problemsSolved++;
this.totalPoints += points;
this.generateNewProblem();
}
}
end() {
this.isActive = false;
clearInterval(this.timer);
this.showResults();
}
showResults() {
const results = {
problemsSolved: this.problemsSolved,
totalPoints: this.totalPoints,
averageTime: this.duration / this.problemsSolved,
rating: this.calculateRating()
};
displayResults(results);
}
calculateRating() {
if (this.problemsSolved >= 30) return '🏆 Master';
if (this.problemsSolved >= 20) return '⭐ Expert';
if (this.problemsSolved >= 15) return '👍 Good';
if (this.problemsSolved >= 10) return '✓ Average';
return '💪 Keep Practicing';
}
}
```
### Accuracy Challenge
```javascript
class AccuracyChallenge {
constructor(problemCount = 10) {
this.problemCount = problemCount;
this.currentProblem = 0;
this.correctAnswers = 0;
this.mistakes = 0;
this.maxMistakes = 3;
}
checkAnswer(userAnswer, correctAnswer) {
if (userAnswer === correctAnswer) {
this.correctAnswers++;
this.currentProblem++;
celebrateCorrect();
if (this.currentProblem >= this.problemCount) {
this.complete();
} else {
this.nextProblem();
}
} else {
this.mistakes++;
if (this.mistakes >= this.maxMistakes) {
this.fail();
} else {
showMistakeWarning(this.maxMistakes - this.mistakes);
}
}
}
complete() {
const accuracy = (this.correctAnswers / this.problemCount) * 100;
showCompletionScreen({
success: true,
accuracy: accuracy,
perfect: accuracy === 100,
reward: this.calculateReward(accuracy)
});
}
fail() {
showCompletionScreen({
success: false,
correctAnswers: this.correctAnswers,
totalProblems: this.problemCount
});
}
calculateReward(accuracy) {
if (accuracy === 100) return 200;
if (accuracy >= 90) return 150;
if (accuracy >= 80) return 100;
if (accuracy >= 70) return 75;
return 50;
}
}
```
## Sound Effects
### Audio System
```javascript
const sounds = {
correct: 'data:audio/wav;base64,...', // Positive chime
incorrect: 'data:audio/wav;base64,...', // Gentle buzz
achievement: 'data:audio/wav;base64,...', // Fanfare
levelUp: 'data:audio/wav;base64,...', // Ascending notes
click: 'data:audio/wav;base64,...' // Click sound
};
function playSound(soundName) {
if (!sounds[soundName]) return;
const audio = new Audio(sounds[soundName]);
audio.volume = 0.3;
audio.play().catch(() => {
// Ignore if user hasn't interacted yet
});
}
```
## Summary
These gamification patterns provide:
- Comprehensive points and achievement systems
- Progressive difficulty with level systems
- Engaging reward animations
- Multiple challenge modes
- Progress tracking and visualization
- Sound effects and celebrations
Use these to make math learning addictively fun!