<!DOCTYPE html><html><head><meta charset="utf-8" /><meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline' https://cdn.jsdelivr.net; style-src 'unsafe-inline'; img-src https: data:; font-src https: data:; media-src https: data:; connect-src https://cdn.jsdelivr.net; frame-src 'none'" /><script>
(function(){
var nav=navigator;
var reduced=matchMedia("(prefers-reduced-motion: reduce)").matches;
var conn=nav.connection||{};
var saveData=!!conn.saveData;
var slow=/(^|[^a-z])(2g|slow-2g)$/.test(conn.effectiveType||"");
var mem=nav.deviceMemory||8;
var cores=nav.hardwareConcurrency||8;
var webgl2=false;
try{var c=document.createElement("canvas");webgl2=!!(c.getContext("webgl2")||c.getContext("webgl"));}catch(e){}
var tier=1;
if(reduced||saveData||slow)tier=4;
else if(mem<=2||cores<=2||!webgl2)tier=3;
else if(mem<=4||cores<=4||conn.effectiveType==="3g")tier=2;
var q=new URLSearchParams(location.search||"");
var forced=parseInt(document.documentElement.getAttribute("data-te-tier")||q.get("tier")||"",10);
if(forced>=1&&forced<=4)tier=forced;
var listeners={tier:[],scroll:[],visible:[],copy:[]};
var copy=null;
document.documentElement.style.setProperty("--te-band","0.5");
var visible=true,hidden=document.hidden;
var loops=[];var loopHandle=0;var last=0;
var nativeRAF=window.requestAnimationFrame.bind(window);
var pending=[];
function active(){return visible&&!hidden&&tier<4}
function pump(now){
loopHandle=0;
if(!active())return;
var dt=last?Math.min(64,now-last):16;last=now;
for(var i=0;i<loops.length;i++){try{loops[i](dt,now)}catch(e){if(!loops[i].te_err){loops[i].te_err=1;console.error("TE.loop",e)}}}
var queued=pending;pending=[];
for(var j=0;j<queued.length;j++){try{queued[j](now)}catch(e){if(!queued[j].te_err){queued[j].te_err=1;console.error("TE.raf",e)}}}
// A callback above may already have scheduled the next frame through the
// wrapped requestAnimationFrame; never queue pump twice for one frame.
if(!loopHandle&&(loops.length||pending.length))loopHandle=nativeRAF(pump);
}
function schedule(){if(!loopHandle&&active())loopHandle=nativeRAF(pump)}
window.requestAnimationFrame=function(fn){pending.push(fn);schedule();return pending.length};
window.cancelAnimationFrame=function(){};
var videoState=new Map();
function pauseAll(){
document.querySelectorAll("video").forEach(function(v){videoState.set(v,!v.paused);if(!v.paused)v.pause()});
}
function resumeAll(){
document.querySelectorAll("video").forEach(function(v){if(videoState.get(v)){var p=v.play();if(p&&p.catch)p.catch(function(){})}});
last=0;schedule();
}
function setVisible(v){
if(v===visible)return;visible=v;
if(v)resumeAll();else pauseAll();
listeners.visible.forEach(function(f){f(v)});
}
document.addEventListener("visibilitychange",function(){hidden=document.hidden;if(hidden)pauseAll();else resumeAll()});
var frames=0,slowSince=0,checked=0;
loops.push(function(dt,now){
frames++;
if(now-checked<1000)return;
var fps=frames*1000/(now-checked);frames=0;checked=now;
if(fps<40){if(!slowSince)slowSince=now;else if(now-slowSince>2000){degrade();slowSince=0}}
else slowSince=0;
});
function degrade(){
if(tier>=3)return;tier++;
document.documentElement.setAttribute("data-te-tier",String(tier));
listeners.tier.forEach(function(f){f(tier)});
}
var pointer={x:0.5,y:0.5,vx:0,vy:0,down:false,fine:matchMedia("(pointer:fine)").matches,active:false};
var px=0,py=0,pt=0;
function onMove(e){
var w=innerWidth||1,h=innerHeight||1,now=performance.now();
var x=e.clientX/w,y=e.clientY/h;
if(pt){var s=Math.max(1,now-pt);pointer.vx=(x-px)*1000/s;pointer.vy=(y-py)*1000/s}
px=x;py=y;pt=now;pointer.x=x;pointer.y=y;pointer.active=true;
}
addEventListener("pointermove",onMove,{passive:true});
addEventListener("pointerdown",function(e){pointer.down=true;onMove(e)},{passive:true});
addEventListener("pointerup",function(){pointer.down=false},{passive:true});
addEventListener("pointerleave",function(){pointer.active=false;pointer.vx=0;pointer.vy=0});
addEventListener("message",function(e){
var d=e.data;if(!d||typeof d!=="object")return;
if(d.type==="te:scroll"&&typeof d.t==="number")listeners.scroll.forEach(function(f){f(d.t)});
if(d.type==="te:visible")setVisible(!!d.visible);
if(d.type==="te:copy"&&typeof d.y0==="number"){copy={x0:d.x0,y0:d.y0,x1:d.x1,y1:d.y1};document.documentElement.style.setProperty("--te-band",String(Math.round(d.y0*1000)/1000));listeners.copy.forEach(function(f){f(copy)})}
if(d.type==="te:tier"&&d.tier>=1&&d.tier<=4){tier=d.tier;document.documentElement.setAttribute("data-te-tier",String(tier));listeners.tier.forEach(function(f){f(tier)})}
});
document.documentElement.setAttribute("data-te-tier",String(tier));
window.TE={
get tier(){return tier},
get visible(){return visible&&!hidden},
get reduced(){return reduced},
get dpr(){return tier===1?Math.min(devicePixelRatio||1,2):tier===2?Math.min(devicePixelRatio||1,1.5):1},
caps:{memory:mem,cores:cores,webgl:webgl2,saveData:saveData,effectiveType:conn.effectiveType||"",reduced:reduced},
pointer:pointer,
loop:function(fn){loops.push(fn);schedule();return function(){var i=loops.indexOf(fn);if(i>=0)loops.splice(i,1)}},
onScroll:function(fn){listeners.scroll.push(fn)},
onTier:function(fn){listeners.tier.push(fn)},
onVisible:function(fn){listeners.visible.push(fn)},
onCopy:function(fn){listeners.copy.push(fn);if(copy)fn(copy)},
get copy(){return copy},
get band(){return copy?copy.y0:0.5},
degrade:degrade,
video:function(el,src){
if(tier>=4)return false;
var small=tier>=2||Math.min(innerWidth,innerHeight)<700;
el.src=small?src.replace(/\.mp4$/,"-sm.mp4"):src;
if(tier>=3)el.preload="metadata";
return true;
},
rendition:function(){return tier>=2||Math.min(innerWidth,innerHeight)<700?"-sm":""},
debug:function(){return {handle:loopHandle,loops:loops.length,pending:pending.length,visible:visible,hidden:hidden,tier:tier,active:active()}}
};
})();
</script><style>html,body{margin:0;padding:0;overflow:hidden;background:transparent}</style><script src="https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.min.js"></script></head><body><style>
html,body{margin:0;height:100%;background:#0f2b30;overflow:hidden;font-family:ui-monospace,Menlo,Consolas,monospace;color:#e6f4f4}
#g{position:absolute;inset:0;width:100%;height:100%;display:none}
#paper{position:absolute;left:50%;top:24px;transform:translateX(-50%);transform-origin:top center;width:min(90vw,880px);padding:clamp(18px,3vw,36px);background:#f7fbfb;color:#0f2b30;border-radius:6px;box-shadow:0 30px 80px rgba(0,0,0,.45);background-image:repeating-linear-gradient(transparent 0 31px,rgba(13,154,166,.14) 31px 32px);background-size:100% 32px}
#q{font-size:clamp(18px,2.6vw,28px);font-weight:700;line-height:32px;margin-bottom:16px}
.way{position:relative;opacity:0;transform:translateY(8px);transition:opacity .5s ease,transform .5s ease;padding-left:clamp(28px,4vw,48px);line-height:32px;font-size:clamp(13px,1.7vw,18px);min-height:64px}
.way.on{opacity:1;transform:none}
.way b{position:absolute;left:0;top:0;font-size:11px;letter-spacing:.2em;color:#0d9aa6}
.way span{visibility:hidden}
.way span.t{visibility:visible}
#stamp{position:absolute;right:clamp(14px,3vw,30px);bottom:clamp(14px,3vw,30px);font-size:clamp(12px,1.4vw,15px);letter-spacing:.24em;text-transform:uppercase;color:#c4622d;border:2px solid #c4622d;padding:6px 12px;transform:rotate(-6deg) scale(.8);opacity:0;transition:opacity .4s ease,transform .4s cubic-bezier(.34,1.56,.64,1)}
#stamp.on{opacity:1;transform:rotate(-6deg) scale(1)}
#soal{position:absolute;left:24px;top:16px;max-width:min(54ch,44vw);font-size:12px;line-height:1.75;letter-spacing:.02em;color:rgba(230,244,244,.8);display:none}
#cara{position:absolute;left:24px;right:24px;top:calc(var(--te-band,.5)*100% - 66px);text-align:center;font-size:12px;line-height:1.7;color:rgba(230,244,244,.62);display:none}
#cara b{color:#0d9aa6;font-weight:400;letter-spacing:.2em}
#hint{position:absolute;left:0;right:0;top:calc(var(--te-band,.5)*100% - 34px);text-align:center;font-size:11px;letter-spacing:.24em;text-transform:uppercase;color:rgba(230,244,244,.6);transition:opacity .6s}
@media (max-width:640px){#soal{max-width:82vw;font-size:10px;left:14px}#cara{font-size:10px;left:14px;right:14px}}
</style>
<div id=paper>
<div id=q>Sebuah toko menjual 3 buku seharga Rp90.000. Berapa harga 7 buku?</div>
<div class=way id=w1><b>CARA 1</b><span>Harga satu buku 90.000 : 3 = 30.000. Tujuh buku berarti 30.000 x 7 = Rp210.000.</span></div>
<div class=way id=w2><b>CARA 2</b><span>7 buku = 3 buku + 3 buku + 1 buku. 90.000 + 90.000 + 30.000 = Rp210.000.</span></div>
<div class=way id=w3><b>CARA 3</b><span>Perbandingan: 3 : 90.000 = 7 : x, jadi x = 90.000 x 7 : 3 = Rp210.000.</span></div>
<div id=stamp>Paham, bukan hafal</div>
</div>
<canvas id=g></canvas>
<div id=soal></div><div id=cara></div>
<p id=hint>Gulir pelan, soalnya dikerjakan tiga cara</p>
<script>
window.TE3=function(o){
var TE=window.TE;
if(!TE||!TE.caps||!TE.caps.webgl)return false;
if(TE.tier>(o.tier||2))return false;
if(typeof THREE==="undefined")return false;
var gc=document.getElementById(o.canvas||"g");
if(!gc)return false;
var ren;
try{ren=new THREE.WebGLRenderer({canvas:gc,antialias:o.aa!==false,alpha:!!o.alpha})}catch(e){return false}
if(THREE.SRGBColorSpace)ren.outputColorSpace=THREE.SRGBColorSpace;
if(o.tone){ren.toneMapping=THREE.ACESFilmicToneMapping;ren.toneMappingExposure=o.tone}
if(!o.alpha)ren.setClearColor(o.clear===undefined?0x000000:o.clear,1);
var scene=new THREE.Scene();
var cam=new THREE.PerspectiveCamera(o.fov||32,1,0.05,160);
cam.position.set(o.camX||0,o.camY||0,o.dist||4);
cam.lookAt(o.lookX||0,o.lookY||0,0);
var root=new THREE.Group();scene.add(root);
var k={THREE:THREE,ren:ren,scene:scene,cam:cam,root:root,band:0.5,w:0,h:0,
narrow:false,px:0,py:0,pw:0,t:0,visW:0,visH:0,tier:TE.tier,dpr:1,time:0};
// A scene that throws while it is being built must not take the stage down
// with it: the 2D canvas is still there and still correct, so we hand back
// false and let it boot. Same for the frame loop, which freezes on the last
// good frame rather than throwing sixty times a second.
try{if(o.build&&o.build(k)===false)return false}catch(e){return false}
var dead=o.replace===null?null:document.getElementById(o.replace||"c");
if(dead&&dead.parentNode)dead.parentNode.removeChild(dead);
gc.style.display="block";
function layout(){
k.w=innerWidth;k.h=innerHeight;k.narrow=k.w<(o.narrow||640);
if(o.host){var hb=o.host.getBoundingClientRect();if(hb.width>1&&hb.height>1){k.w=hb.width;k.h=hb.height}}
// A hero shares its frame with the headline, so the subject is fitted into
// the band the parent reports. An embed owns its whole box, so it passes
// band:1 and gets all of it.
k.band=o.band!==undefined?o.band:Math.max(TE.band||0.5,o.minBand||0.24);
k.dpr=Math.min(TE.dpr,o.maxDpr||1.75);
ren.setPixelRatio(k.dpr);ren.setSize(k.w,k.h,false);
cam.aspect=k.w/Math.max(1,k.h);cam.updateProjectionMatrix();
k.visH=2*Math.tan(cam.fov*Math.PI/360)*cam.position.z;
k.visW=k.visH*cam.aspect;
if(o.fit!==false){
var size=o.size||1;
var s=Math.min(k.band*k.visH*(o.fitH||0.74)/size,k.visW*(o.fitW||0.84)/size);
root.scale.setScalar(Math.max(o.minScale||0.12,s));
root.position.y=(0.5-k.band*0.5)*k.visH+(o.lift||0)*root.scale.x;
}
try{if(o.layout)o.layout(k)}catch(e){}
}
layout();addEventListener("resize",layout);
if(TE.onCopy)TE.onCopy(layout);
var frozen=false;
if(TE.onTier)TE.onTier(function(n){k.tier=n;if(n>=3)frozen=true});
addEventListener("pointermove",function(e){
k.px=(e.clientX/Math.max(1,innerWidth))*2-1;
k.py=-((e.clientY/Math.max(1,innerHeight))*2-1);
k.pw=1;
try{if(o.onPointer)o.onPointer(k)}catch(e){}
},{passive:true});
if(o.onScroll){
var os=function(v){k.t=Math.min(1,Math.max(0,v));try{o.onScroll(k)}catch(e){}};
if(TE.onScroll)TE.onScroll(os);
else addEventListener("message",function(e){if(e.data&&e.data.type==="te:scroll")os(e.data.t)});
}
TE.loop(function(dt){
if(frozen)return;
k.time+=dt;
k.pw*=Math.pow(0.988,dt/16);
try{
if(o.frame)o.frame(dt,k);
ren.render(scene,cam);
}catch(e){frozen=true}
});
return true;
};
</script>
<script>
(function(){
var TE=window.TE,hint=document.getElementById("hint"),stamp=document.getElementById("stamp");
var soalEl=document.getElementById("soal"),caraEl=document.getElementById("cara");
var t=0,LAB=["CARA 1","CARA 2","CARA 3"],SENT=[],lastWay=-1;
// Three.js, tier 1 and 2: the working is cut out of solid material. Every
// glyph is traced from its own outline, extruded and lit, so the three
// routes are three lines of real type standing in space at three depths.
// The scroll types them out one character at a time and all three end on
// the same answer, set in one column so the reader can see the three ways
// land on the same number.
function initGL(){
var FONT="700 64px ui-monospace,Menlo,Consolas,monospace",PX=64,PAD=16,BASE=PAD+83;
var cache={},rows=[],stampM=null,G=null,mcx=null;
var EQ=["30.000 x 7 = Rp210.000","90.000 + 90.000 + 30.000 = Rp210.000","90.000 x 7 : 3 = Rp210.000"];
function readout(){
if(t>0.02)hint.style.opacity="0";
var i=Math.min(2,Math.max(0,Math.floor(t/0.3)));
if(i!==lastWay){lastWay=i;caraEl.innerHTML="<b>"+LAB[i]+"</b> "+SENT[i]}
}
function rdp(p,eps){
if(p.length<5)return p;
var keep=new Uint8Array(p.length);keep[0]=1;keep[p.length-1]=1;
var st=[[0,p.length-1]];
while(st.length){
var sg=st.pop(),a=sg[0],b=sg[1];
if(b-a<2)continue;
var ax=p[a][0],ay=p[a][1],dx=p[b][0]-ax,dy=p[b][1]-ay;
var L=Math.sqrt(dx*dx+dy*dy)||1,best=-1,bd=eps;
for(var i=a+1;i<b;i++){
var d=Math.abs((p[i][0]-ax)*dy-(p[i][1]-ay)*dx)/L;
if(d>bd){bd=d;best=i}
}
if(best>0){keep[best]=1;st.push([a,best]);st.push([best,b])}
}
var out=[];
for(var j=0;j<p.length;j++)if(keep[j])out.push(p[j]);
return out;
}
// a closed outline has to be simplified in two halves: its first and last
// point sit on top of each other, and one anchored segment between them
// measures every deviation as zero
function rdpClosed(p,eps){
if(p.length<9)return p;
var m=p.length>>1;
var A=rdp(p.slice(0,m+1),eps),B=rdp(p.slice(m),eps);
B.shift();
return A.concat(B);
}
// an outline with two points on top of each other makes the bevel divide
// by nothing, so the duplicates go before the shape is ever built
function clean(p){
var out=[],i;
for(i=0;i<p.length;i++){
var q=out.length?out[out.length-1]:null;
if(q&&Math.abs(q[0]-p[i][0])<0.03&&Math.abs(q[1]-p[i][1])<0.03)continue;
out.push(p[i]);
}
while(out.length>3&&Math.abs(out[0][0]-out[out.length-1][0])<0.03&&Math.abs(out[0][1]-out[out.length-1][1])<0.03)out.pop();
return out;
}
function inside(pt,poly){
var c=false,n=poly.length;
for(var i=0,j=n-1;i<n;j=i++){
var yi=poly[i][1],yj=poly[j][1];
if((yi>pt[1])!==(yj>pt[1])&&
pt[0]<(poly[j][0]-poly[i][0])*(pt[1]-yi)/(yj-yi)+poly[i][0])c=!c;
}
return c;
}
// one glyph, traced off its own rendered outline by marching squares
function trace(ch){
if(cache[ch])return cache[ch];
var adv=mcx.measureText(ch).width;
var w=Math.ceil(adv)+PAD*2,h=PX*2+PAD*2;
var res={adv:adv,loops:[]};
if(ch===" "){cache[ch]=res;return res}
var c2=document.createElement("canvas");c2.width=w;c2.height=h;
var g=c2.getContext("2d");
if(!g){cache[ch]=res;return res}
g.font=FONT;g.textBaseline="alphabetic";g.fillStyle="#fff";
g.fillText(ch,PAD,BASE);
var D=g.getImageData(0,0,w,h).data,A=new Float32Array(w*h);
for(var q=0;q<w*h;q++)A[q]=D[q*4+3];
var HE=w*h,pts={},adj={},thr=128;
function put(id,x,y){if(pts[id]===undefined)pts[id]=[x,y]}
function link(a,b){(adj[a]||(adj[a]=[])).push(b);(adj[b]||(adj[b]=[])).push(a)}
for(var y=0;y<h-1;y++){
for(var x=0;x<w-1;x++){
var a1=A[y*w+x],b1=A[y*w+x+1],c1=A[(y+1)*w+x+1],d1=A[(y+1)*w+x];
var code=(a1>thr?1:0)|(b1>thr?2:0)|(c1>thr?4:0)|(d1>thr?8:0);
if(code===0||code===15)continue;
var TOP=y*w+x,BOT=(y+1)*w+x,LEFT=HE+y*w+x,RIGHT=HE+y*w+x+1;
if(b1!==a1)put(TOP,x+(thr-a1)/(b1-a1),y);
if(c1!==d1)put(BOT,x+(thr-d1)/(c1-d1),y+1);
if(d1!==a1)put(LEFT,x,y+(thr-a1)/(d1-a1));
if(c1!==b1)put(RIGHT,x+1,y+(thr-b1)/(c1-b1));
if(code===1||code===14)link(LEFT,TOP);
else if(code===2||code===13)link(TOP,RIGHT);
else if(code===3||code===12)link(LEFT,RIGHT);
else if(code===4||code===11)link(RIGHT,BOT);
else if(code===6||code===9)link(TOP,BOT);
else if(code===7||code===8)link(LEFT,BOT);
else if(code===5){link(LEFT,TOP);link(RIGHT,BOT)}
else if(code===10){link(TOP,RIGHT);link(BOT,LEFT)}
}
}
var seen={};
for(var id in adj){
if(seen[id])continue;
var loop=[],cur=+id,nx;
while(cur!==undefined&&!seen[cur]&&pts[cur]){
seen[cur]=1;loop.push(pts[cur]);
nx=undefined;
var nb=adj[cur];
for(var z=0;z<nb.length;z++)if(!seen[nb[z]]){nx=nb[z];break}
cur=nx;
}
if(loop.length>7){
var sm=clean(rdpClosed(loop,0.9));
if(sm.length>3)res.loops.push(sm);
}
}
cache[ch]=res;
return res;
}
// a line of type, every glyph on the same pen, extruded in one body so
// it costs one draw call and can be typed out with a draw range
function lineGeo(T,txt,scale,depth){
var pen=0,shapes=[];
for(var i=0;i<txt.length;i++){
var gl=trace(txt.charAt(i));
if(gl.loops.length){
var ls=[],j,q,m,n,o,p2;
for(j=0;j<gl.loops.length;j++){
var v=[];
for(q=0;q<gl.loops[j].length;q++){
v.push(new T.Vector2((pen+gl.loops[j][q][0]-PAD)*scale,(BASE-gl.loops[j][q][1])*scale));
}
ls.push({v:v,raw:gl.loops[j],hole:false});
}
// a counter is whatever sits inside an odd number of other outlines
for(m=0;m<ls.length;m++){
var dep=0;
for(n=0;n<ls.length;n++)if(n!==m&&inside(ls[m].raw[0],ls[n].raw))dep++;
ls[m].hole=(dep%2)===1;
}
for(o=0;o<ls.length;o++){
if(ls[o].hole)continue;
var sh=new T.Shape(ls[o].v);
for(p2=0;p2<ls.length;p2++){
if(ls[p2].hole&&inside(ls[p2].raw[0],ls[o].raw))sh.holes.push(new T.Path(ls[p2].v));
}
shapes.push(sh);
}
}
pen+=gl.adv;
}
if(!shapes.length)return null;
// the bevel is what makes the type catch the light, but a bevel on a
// bad outline writes NaN, so the line is checked and rebuilt flat if so
function ex(bev){
var g2=new T.ExtrudeGeometry(shapes,{depth:depth,bevelEnabled:bev,
bevelThickness:depth*0.16,bevelSize:scale*1.1,bevelSegments:1,curveSegments:1});
var ar=g2.attributes.position.array;
for(var z2=0;z2<ar.length;z2++)if(!isFinite(ar[z2]))return null;
return g2;
}
var geo=ex(true)||ex(false);
if(!geo)return null;
// where each glyph ends, so the line can type itself
var ends=[],gs=geo.groups;
for(var s2=0;s2<gs.length;s2++)if(gs[s2].materialIndex===1)ends.push(gs[s2].start+gs[s2].count);
geo.setDrawRange(0,0);
return {geo:geo,w:pen*scale,ends:ends};
}
function sync(){
// the same three windows the sheet uses: each way works itself out
// over its own stretch of the scroll
for(var i=0;i<3;i++){
var local=Math.min(1,Math.max(0,(t-i*0.3)/0.28)),r=rows[i];
var n=Math.floor(local*r.ends.length);
r.geo.setDrawRange(0,n>0?r.ends[n-1]:0);
r.row.visible=local>0;
}
if(stampM)stampM.visible=t>0.94;
readout();
}
return TE3({
tier:2,clear:0x0f2b30,fov:30,dist:5,fit:false,tone:1.12,maxDpr:1.75,replace:"paper",
build:function(k){
var T=k.THREE;
var qEl=document.getElementById("q");
if(!qEl)return false;
soalEl.textContent=qEl.textContent;
for(var s=1;s<=3;s++){
var sp=document.getElementById("w"+s).querySelector("span");
SENT.push(sp?sp.textContent:"");
}
soalEl.style.display="block";caraEl.style.display="block";
var mc=document.createElement("canvas");mc.width=8;mc.height=8;
mcx=mc.getContext("2d");
if(!mcx)return false;
mcx.font=FONT;
G=new T.Group();G.position.x=0.55;k.root.add(G);
var ink=new T.MeshPhongMaterial({color:0xf7fbfb,shininess:54,specular:0xbfe7ea});
var flank=new T.MeshPhongMaterial({color:0x6ba7ad,shininess:30,specular:0x8fd2d7});
var labF=new T.MeshPhongMaterial({color:0x0d9aa6,shininess:40,specular:0x7fe0e6});
var labS=new T.MeshPhongMaterial({color:0x086068,shininess:24,specular:0x4fb0b8});
var SC=0.0062,RIGHT=4.5;
for(var i=0;i<3;i++){
var L=lineGeo(T,EQ[i],SC,0.11);
if(!L)return false;
var m=new T.Mesh(L.geo,[ink,flank]);
m.position.set(RIGHT-L.w,0,0);
var row=new T.Group();
row.add(m);
var lab=lineGeo(T,LAB[i],0.0038,0.07);
if(lab){
var lm=new T.Mesh(lab.geo,[labF,labS]);
lm.position.set(RIGHT-L.w-lab.w-0.38,0.03,0);
lab.geo.setDrawRange(0,Infinity);
row.add(lm);
}
row.position.set(0,0.62-i*0.62,0.42-i*0.42);
row.rotation.y=0.06-i*0.06;
row.visible=false;
G.add(row);
rows.push({geo:L.geo,ends:L.ends,row:row});
}
// the stamp the sheet ends on, cut from the same material
var S2=lineGeo(T,"Paham, bukan hafal",0.0052,0.09);
if(S2){
var sf=new T.MeshPhongMaterial({color:0xc4622d,shininess:46,specular:0xffd0a8});
var ss=new T.MeshPhongMaterial({color:0x7d3a16,shininess:24,specular:0xc09070});
stampM=new T.Mesh(S2.geo,[sf,ss]);
stampM.position.set(RIGHT-S2.w,-1.22,0.12);
stampM.rotation.z=-0.105;
stampM.visible=false;
S2.geo.setDrawRange(0,Infinity);
G.add(stampM);
}
k.scene.add(new T.AmbientLight(0x4e8f96,0.72));
var key=new T.DirectionalLight(0xffffff,1.9);key.position.set(-3.2,4,5);k.scene.add(key);
var rim=new T.DirectionalLight(0x0d9aa6,1.2);rim.position.set(3.6,-1.6,2.4);k.scene.add(rim);
sync();
return true;
},
layout:function(k){
var S=Math.min(k.band*k.visH*0.9/2.4,k.visW*(k.narrow?0.96:0.88)/10.4);
k.root.scale.setScalar(Math.max(0.03,S));
k.root.position.y=(0.5-k.band*0.5)*k.visH+0.25*S;
},
onScroll:function(k){t=k.t;sync()},
frame:function(dt,k){
G.rotation.y=-0.16+k.px*0.09;
G.rotation.x=0.05-k.py*0.05;
}
});
}
if(!initGL()){
var ways=[1,2,3].map(function(i){var w=document.getElementById("w"+i),sp=w.querySelector("span"),text=sp.textContent;sp.innerHTML=text.split("").map(function(c){return "<span>"+(c===" "?" ":c)+"</span>"}).join("");return {el:w,chars:sp.children,n:text.length}});
var paper=document.getElementById("paper");
var place=function(){var band=TE&&TE.band||0.5,H=innerHeight,ph=paper.offsetHeight||1,k=Math.min(1,band*H*0.9/ph);paper.style.transform="translateX(-50%) scale("+k.toFixed(3)+")";paper.style.top=Math.max(10,(band*H-ph*k)/2)+"px"};
place();addEventListener("resize",place);if(TE&&TE.onCopy)TE.onCopy(place);
var render=function(v){
t=v;
if(t>0.02)hint.style.opacity="0";
for(var i=0;i<3;i++){
var local=Math.min(1,Math.max(0,(t-i*0.3)/0.28));
var w=ways[i];w.el.classList.toggle("on",local>0);
var k=Math.floor(local*w.n);
for(var j=0;j<w.n;j++)w.chars[j].classList.toggle("t",j<k);
}
stamp.classList.toggle("on",t>0.94);
};
if(TE&&TE.onScroll)TE.onScroll(render);else addEventListener("message",function(e){if(e.data&&e.data.type==="te:scroll")render(e.data.t)});
render(0);
}
})();
</script></body></html>
Bimbel kelas kecil, Bogor, sejak 2017
Paham, bukan hafal
Gulir pelan: satu soal dikerjakan tiga cara di kertas itu. Begitu cara kami mengajar, karena anak yang paham bisa memilih caranya sendiri saat soalnya berubah di ujian.
Maksimal 6 anak per kelasTes diagnosa gratisLaporan tiap dua minggu
Dari diagnosa sampai laporan
01
Tes diagnosa 45 menit
Bukan untuk menilai, tetapi untuk tahu di mana pemahaman terputus. Hasilnya dibahas dengan orang tua.
02
Kelas maksimal enam anak
Tutor melihat pekerjaan setiap anak, bukan hanya papan tulis. Soal dikerjakan dengan lebih dari satu cara.
03
Laporan tiap dua minggu
Apa yang sudah paham, apa yang belum, dan latihan apa yang bisa dibantu di rumah. Dikirim lewat WhatsApp.
Laporan dua mingguan, dan apa yang ada di dalamnya
Yang membedakan kelas kecil
Tutor yang menjelaskan ulang, bukan mengulang
Kalau cara pertama tidak masuk, dicari cara kedua. Anak tidak dianggap lambat, hanya belum ketemu jalannya.
Latihan yang berubah bentuk
Soal yang sama diubah angkanya, ceritanya, lalu bentuknya, supaya yang tinggal adalah pemahaman.
Orang tua tahu, bukan menebak
Laporan dua mingguan menyebut bab dan contoh soal, bukan sekadar nilai.
6
anak paling banyak dalam satu kelas
8
tahun mengajar di Jalan Cendana
92
persen murid naik minimal satu tingkat nilai dalam satu semester
14
tutor tetap, semuanya lulusan pendidikan
Anak saya dulu bilang matematika itu hafalan rumus. Tiga bulan di sini dia yang menjelaskan ke saya kenapa rumusnya begitu.Ibu Ratna, orang tua murid kelas 8
Laporannya menyebut bab yang belum paham dan latihan yang bisa saya dampingi. Itu yang tidak pernah saya dapat dari bimbel lain.Pak Hendra, orang tua murid kelas 5
Kelasnya kecil jadi aku berani bertanya. Di sekolah aku diam saja.Nadia, kelas 9
Tesnya di awal kaget, ternyata untuk tahu aku putusnya di pecahan, bukan di aljabar.Bima, kelas 7
Yang sering ditanyakan orang tua
Kelas percobaannya benar gratis?
Satu sesi 90 menit tanpa biaya, termasuk tes diagnosa. Setelah itu orang tua memutuskan.
Bagaimana kalau anak tertinggal jauh?
Diagnosa menemukan titik putusnya, dan kelas dimulai dari sana, bukan dari bab sekolah saat ini.
Ada kelas online?
Ada untuk privat. Kelas kecil tetap tatap muka karena tutor perlu melihat pekerjaan anak.
Bisa berhenti kapan saja?
Bisa. Biaya dihitung per bulan, tidak ada kontrak semester.
Daftar kelas percobaan
Jalan Cendana No 15, Bogor. Dekat SMPN 2, parkir di halaman.