Example Articles
Mechanical Advantages of Pulleys Rolling Dice and the Central limit theorem
Examples
let big_rect = square(150).fill('lightblue').stroke('none');
let small_rect = square(20).fill('blue').rotate(Math.PI/4);
let r1 = small_rect.position(big_rect.get_anchor('top-left'));
let r2 = small_rect.translate(V2(75,75)).fill('white');
let r3 = small_rect.position(V2(-75,-75)).fill('black');
let r4 = small_rect.position(big_rect.parametric_point(0.25));
draw(big_rect, r1, r2, r3, r4);
let big_rect = square(150).fill('lightblue').stroke('none');
let small_rect = square(20).fill('blue').rotate(Math.PI/4);
let r1 = small_rect.position(big_rect.get_anchor('top-left'));
let r2 = small_rect.translate(V2(75,75)).fill('white');
let r3 = small_rect.position(V2(-75,-75)).fill('black');
let r4 = small_rect.position(big_rect.parametric_point(0.25));
draw(big_rect, r1, r2, r3, r4);
int.draw_function = (inp) => {
let x = inp['x'];
let big_circ = circle(50);
let small_rect = square(20).fill('blue').translate(V2(x,0));
draw(big_circ, small_rect);
};
int.slider('x', -50, 50, 0);
int.draw();
int.draw_function = (inp) => {
let x = inp['x'];
let big_circ = circle(50);
let small_rect = square(20).fill('blue').translate(V2(x,0));
draw(big_circ, small_rect);
};
int.slider('x', -50, 50, 0);
int.draw();
let opt = {
xrange : [-1.5, 4],
yrange : [-1.5, 4],
}
let ax = xyaxes(opt);
let f = x => x**2;
let g = x => Math.sin(x);
let graph_f = plotf(f, opt).stroke('red').strokewidth(2);
let graph_g = plotf(g, opt).stroke('blue').strokewidth(2);
draw(ax, graph_f, graph_g);
let opt = {
xrange : [-1.5, 4],
yrange : [-1.5, 4],
}
let ax = xyaxes(opt);
let f = x => x**2;
let g = x => Math.sin(x);
let graph_f = plotf(f, opt).stroke('red').strokewidth(2);
let graph_g = plotf(g, opt).stroke('blue').strokewidth(2);
draw(ax, graph_f, graph_g);
let pip_positions = {
1 : [V2(0,0)],
2 : [V2(-1,-1), V2(1,1)],
3 : [V2(-1,-1), V2(0,0), V2(1,1)],
4 : [V2(-1,-1), V2(1,-1), V2(-1,1), V2(1,1)],
5 : [V2(-1,-1), V2(1,-1), V2(0,0), V2(-1,1), V2(1,1)],
6 : [V2(-1,-1), V2(1,-1), V2(-1,0), V2(1,0), V2(-1,1), V2(1,1)],
}
let generate_dice_pips = (n) => {
let positions = pip_positions[n];
let pips = positions.map((p) => circle(0.25).position(p));
return diagram_combine(...pips).fill('black').stroke('none');
}
let generate_dice = (n) => {
let outline = square(4).apply(mod.round_corner(0.5))
.fill('none').stroke('black').strokewidth(2);
let pips = generate_dice_pips(n);
return diagram_combine(outline, pips);
}
let dice = [1,2,3,4,5,6].map((n) => generate_dice(n));
let diceall = distribute_grid_row(dice, 2, 1, 1);
draw(diceall);
let pip_positions = {
1 : [V2(0,0)],
2 : [V2(-1,-1), V2(1,1)],
3 : [V2(-1,-1), V2(0,0), V2(1,1)],
4 : [V2(-1,-1), V2(1,-1), V2(-1,1), V2(1,1)],
5 : [V2(-1,-1), V2(1,-1), V2(0,0), V2(-1,1), V2(1,1)],
6 : [V2(-1,-1), V2(1,-1), V2(-1,0), V2(1,0), V2(-1,1), V2(1,1)],
}
let generate_dice_pips = (n) => {
let positions = pip_positions[n];
let pips = positions.map((p) => circle(0.25).position(p));
return diagram_combine(...pips).fill('black').stroke('none');
}
let generate_dice = (n) => {
let outline = square(4).apply(mod.round_corner(0.5))
.fill('none').stroke('black').strokewidth(2);
let pips = generate_dice_pips(n);
return diagram_combine(outline, pips);
}
let dice = [1,2,3,4,5,6].map((n) => generate_dice(n));
let diceall = distribute_grid_row(dice, 2, 1, 1);
draw(diceall);
let opt = {
xrange : [-2, 2],
yrange : [-1, 2],
}
let axes = axes_empty(opt);
let f = x => Math.cos(x);
let graph_f = plotf(f, opt).stroke('blue').strokewidth(3);
let a = -0.5;
let b = 1.0;
let under_f = under_curvef(f, a, b, opt).fill('blue').opacity(0.5).stroke('none');
let pa = circle(0.05).position(V2(a, f(a)))
.fill('blue').stroke('none');
let pb = circle(0.05).position(V2(b, f(b)))
.fill('blue').stroke('none');
let ticka = xtickmark(a, 0, 'a');
let tickb = xtickmark(b, 0, 'b');
let labela = textvar('f(a)').move_origin_text('bottom-right').position(V2(a, f(a)));
let labelb = textvar('f(b)').move_origin_text('bottom-left').position(V2(b, f(b)));
let labels = labela.combine(labelb).translate(V2(0, 0.1)).textfill('blue');
let texts = diagram_combine(ticka, tickb, labels, pa, pb);
draw(axes, under_f, graph_f, texts);
let opt = {
xrange : [-2, 2],
yrange : [-1, 2],
}
let axes = axes_empty(opt);
let f = x => Math.cos(x);
let graph_f = plotf(f, opt).stroke('blue').strokewidth(3);
let a = -0.5;
let b = 1.0;
let under_f = under_curvef(f, a, b, opt).fill('blue').opacity(0.5).stroke('none');
let pa = circle(0.05).position(V2(a, f(a)))
.fill('blue').stroke('none');
let pb = circle(0.05).position(V2(b, f(b)))
.fill('blue').stroke('none');
let ticka = xtickmark(a, 0, 'a');
let tickb = xtickmark(b, 0, 'b');
let labela = textvar('f(a)').move_origin_text('bottom-right').position(V2(a, f(a)));
let labelb = textvar('f(b)').move_origin_text('bottom-left').position(V2(b, f(b)));
let labels = labela.combine(labelb).translate(V2(0, 0.1)).textfill('blue');
let texts = diagram_combine(ticka, tickb, labels, pa, pb);
draw(axes, under_f, graph_f, texts);
int.draw_function = (inp) => {
let n = inp['n'];
let s0 = regular_polygon_side(3, 50)
.position().fill('lightblue').stroke('none');
let snext = (s) => diagram_combine(
s,
s.translate(V2(50,0)),
s.translate(V2(25,50*Math.sqrt(3)/2)),
).scale(V2(0.5,0.5)).position().flatten();
let sn = (n) => {
if (n == 0) return s0;
else return snext(sn(n-1));
}
let a = sn(n);
draw(a);
};
int.slider('n', 0, 4, 1, 1);
int.draw();
int.draw_function = (inp) => {
let n = inp['n'];
let s0 = regular_polygon_side(3, 50)
.position().fill('lightblue').stroke('none');
let snext = (s) => diagram_combine(
s,
s.translate(V2(50,0)),
s.translate(V2(25,50*Math.sqrt(3)/2)),
).scale(V2(0.5,0.5)).position().flatten();
let sn = (n) => {
if (n == 0) return s0;
else return snext(sn(n-1));
}
let a = sn(n);
draw(a);
};
int.slider('n', 0, 4, 1, 1);
int.draw();
let circ = regular_polygon(100,50).fill('none').stroke('black');
let pA0 = circ.parametric_point(0.4);
let pB0 = circ.parametric_point(0.6);
int.draw_function = (inp) => {
let pA = inp['A'];
let pB = inp['B'];
let p1 = inp['p1'];
let p2 = inp['p2'];
let ang = pA.angle() - pB.angle();
let arcc = arc(50, ang).strokewidth(3).stroke('blue').rotate(pB.angle());
let line1 = curve([pA,p1,pB]).stroke('gray').strokedasharray([5]);
let line2 = curve([pA,p2,pB]).stroke('gray').strokedasharray([5]);
let labels = diagram_combine(
textvar('A').position(pA.scale(1.15)),
textvar('B').position(pB.scale(1.15)),
);
let angles = diagram_combine(
annotation.angle_smaller([pA,p1,pB], '\\theta', 15, 10).fill('lightred'),
annotation.angle_smaller([pA,p2,pB], '\\theta', 15, 10).fill('lightred'),
);
draw(
circ, arcc,
labels, angles,
line1, line2,
);
int.locator_draw();
}
int.locator('A', pA0, 4, 'blue', circ);
int.locator('B', pB0, 4, 'blue', circ);
int.locator('p1', circ.parametric_point(0.2), 4, 'red', circ);
int.locator('p2', circ.parametric_point(0.9), 4, 'red', circ);
int.draw();
let circ = regular_polygon(100,50).fill('none').stroke('black');
let pA0 = circ.parametric_point(0.4);
let pB0 = circ.parametric_point(0.6);
int.draw_function = (inp) => {
let pA = inp['A'];
let pB = inp['B'];
let p1 = inp['p1'];
let p2 = inp['p2'];
let ang = pA.angle() - pB.angle();
let arcc = arc(50, ang).strokewidth(3).stroke('blue').rotate(pB.angle());
let line1 = curve([pA,p1,pB]).stroke('gray').strokedasharray([5]);
let line2 = curve([pA,p2,pB]).stroke('gray').strokedasharray([5]);
let labels = diagram_combine(
textvar('A').position(pA.scale(1.15)),
textvar('B').position(pB.scale(1.15)),
);
let angles = diagram_combine(
annotation.angle_smaller([pA,p1,pB], '\\theta', 15, 10).fill('lightred'),
annotation.angle_smaller([pA,p2,pB], '\\theta', 15, 10).fill('lightred'),
);
draw(
circ, arcc,
labels, angles,
line1, line2,
);
int.locator_draw();
}
int.locator('A', pA0, 4, 'blue', circ);
int.locator('B', pB0, 4, 'blue', circ);
int.locator('p1', circ.parametric_point(0.2), 4, 'red', circ);
int.locator('p2', circ.parametric_point(0.9), 4, 'red', circ);
int.draw();
default_diagram_style['stroke-width'] = 2;
default_textdata['font-size'] = 21;
let angle = to_radian(30);
let horizontal = line(V2(0,0), V2(8,0))
.stroke('gray').strokedasharray([5,5]);
let plane = line(V2(0,0), Vdir(angle).scale(10)).stroke('gray');
let sq = square(4).move_origin('bottom-center')
.position(plane.parametric_point(0.5)).rotate(angle)
.fill('lightblue').stroke('none');
let csq = sq.get_anchor('center-center');
let arrow_head_size = 0.12;
let vx = V2(1,0); let vy = V2(0,1); let vnx = V2(-1,0); let vny = V2(0,-1);
let forces_annotation = diagram_combine(
annotation.vector(vny.scale(3.5), 'Mg', V2(0.6,0.2), arrow_head_size)
.position(csq),
annotation.vector(Vdir(angle + Math.PI/2).scale(5), 'N', V2(0.6,0.2), arrow_head_size)
.position(plane.parametric_point(0.6)),
annotation.vector(Vdir(angle).scale(1.2), 'f', V2(0.0,-0.6), arrow_head_size)
.position(plane.parametric_point(0.6)),
annotation.vector(Vdir(angle).scale(2), 'F', V2(-0.5,-1.0), arrow_head_size)
.move_origin(Vdir(angle).scale(2)).position(sq.parametric_point(0.5,3)),
);
let angle_annotation = annotation.angle([V2(1,0), V2(0,0), Vdir(angle)], '\\theta', 1, 1.5);
draw (horizontal, sq, plane, forces_annotation, angle_annotation);
default_diagram_style['stroke-width'] = 2;
default_textdata['font-size'] = 21;
let angle = to_radian(30);
let horizontal = line(V2(0,0), V2(8,0))
.stroke('gray').strokedasharray([5,5]);
let plane = line(V2(0,0), Vdir(angle).scale(10)).stroke('gray');
let sq = square(4).move_origin('bottom-center')
.position(plane.parametric_point(0.5)).rotate(angle)
.fill('lightblue').stroke('none');
let csq = sq.get_anchor('center-center');
let arrow_head_size = 0.12;
let vx = V2(1,0); let vy = V2(0,1); let vnx = V2(-1,0); let vny = V2(0,-1);
let forces_annotation = diagram_combine(
annotation.vector(vny.scale(3.5), 'Mg', V2(0.6,0.2), arrow_head_size)
.position(csq),
annotation.vector(Vdir(angle + Math.PI/2).scale(5), 'N', V2(0.6,0.2), arrow_head_size)
.position(plane.parametric_point(0.6)),
annotation.vector(Vdir(angle).scale(1.2), 'f', V2(0.0,-0.6), arrow_head_size)
.position(plane.parametric_point(0.6)),
annotation.vector(Vdir(angle).scale(2), 'F', V2(-0.5,-1.0), arrow_head_size)
.move_origin(Vdir(angle).scale(2)).position(sq.parametric_point(0.5,3)),
);
let angle_annotation = annotation.angle([V2(1,0), V2(0,0), Vdir(angle)], '\\theta', 1, 1.5);
draw (horizontal, sq, plane, forces_annotation, angle_annotation);
let x0 = 50;
let amplitude = 25;
let omega = 1;
int.draw_function = (inp) => {
let t = inp['t'];
let x = x0 + amplitude * Math.cos(omega * t);
let wall = line(V2(0,0), V2(0,20)).strokewidth(2);
let floor = line(V2(0,0), V2(100,0)).strokewidth(2);
let box = square(20).position(V2(x,10))
.fill('lightblue').stroke('none');
let p1 = wall.get_anchor('center-right');
let p2 = box.get_anchor('center-left');
let spring = mechanics.spring(p1,p2, 2, 10, 1.2);
draw(box, wall, floor, spring)
}
let period = 2*Math.PI/omega;
int.slider('t', 0, 2*period, period/4, 0.1, 2);
int.draw();
let x0 = 50;
let amplitude = 25;
let omega = 1;
int.draw_function = (inp) => {
let t = inp['t'];
let x = x0 + amplitude * Math.cos(omega * t);
let wall = line(V2(0,0), V2(0,20)).strokewidth(2);
let floor = line(V2(0,0), V2(100,0)).strokewidth(2);
let box = square(20).position(V2(x,10))
.fill('lightblue').stroke('none');
let p1 = wall.get_anchor('center-right');
let p2 = box.get_anchor('center-left');
let spring = mechanics.spring(p1,p2, 2, 10, 1.2);
draw(box, wall, floor, spring)
}
let period = 2*Math.PI/omega;
int.slider('t', 0, 2*period, period/4, 0.1, 2);
int.draw();
// base
let base0 = circle(50);
let base1 = circle(35).translate(V2(-40,-20));
let base2 = circle(35).translate(V2( 40,-20));
let base_raw = diagram_combine(base0, base1, base2);
let base_stroke = base_raw.stroke('black').strokewidth(4);
let base_fill = base_raw.fill('white').stroke('none');
let base_dashed = base_raw.stroke('gray').strokewidth(2).strokedasharray([5,5]).opacity(0.5);
let base = diagram_combine(base_stroke, base_fill, base_dashed);
// beans
let pivot = V2(0,0);
let bean0 = circle(24).scale(V2(1,1.5))
.move_origin('bottom-center').position().translate(V2(0,60))
.strokewidth(2);
let angle_sep = to_radian(36);
let bean1 = bean0.rotate(angle_sep/2*3, pivot);
let bean2 = bean0.rotate(angle_sep/2, pivot);
let bean3 = bean2.hflip(0);
let bean4 = bean1.hflip(0);
let bean_arc_r1 = bean0.origin.length();
let bean_arc1 = arc(bean_arc_r1, 3*angle_sep).rotate(angle_sep)
.strokedasharray([5,5]).stroke('gray').opacity(0.5).strokewidth(2);
let bean_arc_r2 = bean0.get_anchor('center-center').length();
let bean_arc2 = arc(bean_arc_r2, 3*angle_sep).rotate(angle_sep)
.strokedasharray([5,5]).stroke('gray').opacity(0.5).strokewidth(2);
let bean_line_1 = line(V2(0,0), bean2.get_anchor('center-center'));
let bean_line_2 = line(V2(0,0), bean3.get_anchor('center-center'));
let bean_lines = bean_line_1.combine(bean_line_2)
.strokedasharray([5,5]).stroke('gray').opacity(0.5).strokewidth(2);
// accents
let basebg1 = base1.translate(V2(10,-5));
let basebg2 = base2.translate(V2(5,5));
let basebg = basebg1.combine(basebg2).fill('lightblue').stroke('none');
let beanbg = bean2.combine(bean3)
.rotate(to_radian(-4), pivot).fill('lightblue').stroke('none');
draw(
beanbg, basebg,
base, bean1, bean2, bean3, bean4,
bean_arc1, bean_arc2, bean_lines,
);
// base
let base0 = circle(50);
let base1 = circle(35).translate(V2(-40,-20));
let base2 = circle(35).translate(V2( 40,-20));
let base_raw = diagram_combine(base0, base1, base2);
let base_stroke = base_raw.stroke('black').strokewidth(4);
let base_fill = base_raw.fill('white').stroke('none');
let base_dashed = base_raw.stroke('gray').strokewidth(2).strokedasharray([5,5]).opacity(0.5);
let base = diagram_combine(base_stroke, base_fill, base_dashed);
// beans
let pivot = V2(0,0);
let bean0 = circle(24).scale(V2(1,1.5))
.move_origin('bottom-center').position().translate(V2(0,60))
.strokewidth(2);
let angle_sep = to_radian(36);
let bean1 = bean0.rotate(angle_sep/2*3, pivot);
let bean2 = bean0.rotate(angle_sep/2, pivot);
let bean3 = bean2.hflip(0);
let bean4 = bean1.hflip(0);
let bean_arc_r1 = bean0.origin.length();
let bean_arc1 = arc(bean_arc_r1, 3*angle_sep).rotate(angle_sep)
.strokedasharray([5,5]).stroke('gray').opacity(0.5).strokewidth(2);
let bean_arc_r2 = bean0.get_anchor('center-center').length();
let bean_arc2 = arc(bean_arc_r2, 3*angle_sep).rotate(angle_sep)
.strokedasharray([5,5]).stroke('gray').opacity(0.5).strokewidth(2);
let bean_line_1 = line(V2(0,0), bean2.get_anchor('center-center'));
let bean_line_2 = line(V2(0,0), bean3.get_anchor('center-center'));
let bean_lines = bean_line_1.combine(bean_line_2)
.strokedasharray([5,5]).stroke('gray').opacity(0.5).strokewidth(2);
// accents
let basebg1 = base1.translate(V2(10,-5));
let basebg2 = base2.translate(V2(5,5));
let basebg = basebg1.combine(basebg2).fill('lightblue').stroke('none');
let beanbg = bean2.combine(bean3)
.rotate(to_radian(-4), pivot).fill('lightblue').stroke('none');
draw(
beanbg, basebg,
base, bean1, bean2, bean3, bean4,
bean_arc1, bean_arc2, bean_lines,
);