From fbe46b8215b432630c57fd4124f025a4f77acd75 Mon Sep 17 00:00:00 2001 From: Accusedbold Date: Sun, 3 May 2026 20:24:24 -0400 Subject: [PATCH] Fade in and fade out --- __pycache__/algebraic_steps.cpython-313.pyc | Bin 27343 -> 27573 bytes __pycache__/main.cpython-313.pyc | Bin 5380 -> 5891 bytes __pycache__/problem_generator.cpython-313.pyc | Bin 13436 -> 13436 bytes algebraic_steps.py | 18 ++-- main.py | 17 +++- start.bat | 1 + www/favicon.png | Bin 0 -> 10665 bytes www/index.html | 9 +- www/scripts/problem.js | 76 +++++++++++++++-- www/scripts/web_sockets.js | 2 +- www/style/styles.css | 77 +++++++++++++++++- 11 files changed, 178 insertions(+), 22 deletions(-) create mode 100644 start.bat create mode 100644 www/favicon.png diff --git a/__pycache__/algebraic_steps.cpython-313.pyc b/__pycache__/algebraic_steps.cpython-313.pyc index 36092b7eecd8724c13863ea6c8466628c4d2c381..b02f8cde895967af228c044f3c3bb13305530855 100644 GIT binary patch delta 1518 zcmZ8geN0x%M@&{vimwhJEXo{|x-#eb0I}1v-eCvvF|Q_&nqb=G=UZrqAd$)}7X9L?@Gp z+n~xBC_|-CGLy&bhPr-c*CHpIyR%fU9mdEQL5+co4t-o2#%cSE`0q1qM=WI)({?7z zx|1oHHCX}6I%vUy@f#EnpFrrJb?e-wT5UB!O{0@|T1yWBNkRg_&qw%(j_RzN%kKSNOGwTip8DZym*Nx?|3bzB?ry zn~u&oYuvnR;gq@`j>@&|=I{K1#jC@r|tH zX)OCDd|}zET(e!|^i51(RGKmuIsPCM-#{}kbCQwPfEQ4XQp0=}K8pRg52XvIfv~4}WQ3}@?Tk?ipk9>f(Sc_U za!8(%Xo#{))=(F+7REjm3I`&ArzKi}bR_~_UYRXfyo5v!!fpg!15F(!G6kdcu05@c zNu>CKk|=xpqAwDnluf9Hjv@qLwZ2L}&qSZ{bNx#O(gWvO_UW)(_&q&?ql55qONng= zebv*-*iHzu_5#Rib>>f^Np0Z_lM+^0I_(Kc{)i_c(eW^yfTOKJ{Sq_1t=wp>(b+L{ zvhRnOv~&6ri&qK_Z4KmmWwPxGXN#iS%m4EzgszTSavvt!PAETi{HiB2aJ%OOIRX{E z=SVHA^!g8|;oWRsLOT@-B{;UUvM47rp2v8}4ib7A3Pr+Hf+qK;L{NmsH?-s^e17aO z=}@x!cM-?47{nl*iAeHDLMPIb$y=lYaB$#J(ycr<;MJv|(+Zd1D)-Y-xHr^Dmf*l} zX|qq=%kHgfB1kuwLeWv3g5>SrLmn;K?X4%Tzz5zu@|N$;Y;eO+lc$-r%lY)i#C3UhygRQ3ngHPmgcdu?A!p?lTa zF8mRNMI}_?92^#l$TEpB7!wkGYV?DK$OrvEf(yw7v_$zZ={>b{G1)i78=v6r6eFGXqGrxslA|}``HceV0 zrm(R)$}loVd`LBqa1qqPsOCr&@gFDtTH>z?n{>UJVJ66~tms_W5UzTHQ-u+Wj((U$ z(6hkZS`TNQ5Mjt8nS~wXRJfX0IgbR3);D3p?lc(_vYJq`FkI6uJVpSA$t_3ce8IQw-dYqlC11&SUfeX*EM2^+&5nf^F8J3aU(veh@t2(Et@q(~hf`a&t+2vgQf8Kxx=l*$(5^eqv3w7) zi&~rWA}jP0^(qYm2@h#?QXPx>pu^V+`y5`t^)7xtiQd%a>o2nQ08z1RqdT!^OmZEL@hJ8 z3p)2)?VF+omsQjkfIt9hPCcdI96k&+!3L3b zw%J~}UGh@MjZQ)&*g~FkHs~^@>A@p#E!fGwPSgqQ``~3GIs}>iM-8;#C0`vHhY$Ok z?2{C!zjVugxuCti5x4WT#|;(=`hYF7yV`LY z)~5EMd2q(I_r~?Jd8aYOd+0Swf+Bd^cK#EAeYYe>~BG-i3H#54r+N2|rrWzDl?_^acEo3VJA; zEA-*yY_?LF_5jbp&a@Y$A(UcIZqoB7Yon_-_`dNM1WcswF7 z+j~7MfAs82L2~>d`Gs7}2g5)U8-aW%eGgz$0N6M`15237EDj}7B1*VDAa4ZnTi+Km z^nJRcnNu;K><=D4IbtIie&8kZ>*6bR#;XbOJlu2^0p+46|tjb z7(pj*x5yz`%%S(4A+N+T`B5IrIHO+?ryKa1^E9?Tu0HLb0EN%3(M6`ys|ehaUPD}G zP#hG8q8wtGq3fv7vR3QL6}nZcJytDGt=6_GRhnjc)y5Ey(;((@+nZ&rK{M>WirO~A zE_|O1@8*uAb3J*+loL(97g1VCGqTX+pYw(g?1hpo{ylG`mJehjwQ{g-q*g!ee61VV z2WF_)l#aa7o_nI>PqhLqXGdQ6=3X4Sz#DC9za((SUX|XKjM%K{n(J_LGyu?k;ks`V zadvBg+wGyJVI#Nn9iQgEgHhbLZcE1%j^1Eb{f{r>qBl`N6x(+v=82d^AMr?kCa<`= zf~w+js;XRQAIf3k!zHZ;Mx|N(=h>*Ju^|4)>R&zR?_PG2`N5PxrUz3V5*frCWU}uA V&fTn=_RtSb*jww{feYi%@DIIKkD34g delta 209 zcmZqHYtiES%*)Hg00eFI-!dO_PvnzeJhoB&I3r6sqo%}W5vF+@j8&62bJ;U$PX5ew zbaNeVI1`sSPo|rdC)D%cmFk9p$Pz0dIxs^ delta 20 acmey9@h5}(GcPX}0}%L|eBH=hXaWFH1qQ?b diff --git a/algebraic_steps.py b/algebraic_steps.py index 4ebb369..82d0c5e 100644 --- a/algebraic_steps.py +++ b/algebraic_steps.py @@ -95,19 +95,27 @@ def multiply_both_sides(equation, value): left_expr = parse_expr(left, transformations=transformations, evaluate=False) right_expr = parse_expr(right, transformations=transformations, evaluate=False) - if left_expr != 1 and left_expr != -1: + if left_expr != 1 and left_expr != -1 and value != 1 and value != -1: new_left_expr = cancel(left_expr * value) elif left_expr == 1: new_left_expr = value - else: + elif value == 1: + new_left_expr = left_expr + elif left_expr == -1: new_left_expr = -value + else: + new_left_expr = -left_expr - if right_expr != 1 and right_expr != -1: - new_right_expr = Mul(right_expr, value, evaluate=False) + if right_expr != 1 and right_expr != -1 and value != 1 and value != -1: + new_right_expr = safe_format(Mul(right_expr, value, evaluate=False)) elif right_expr == 1: new_right_expr = value - else: + elif value == 1: + new_right_expr = right_expr + elif right_expr == -1: new_right_expr = -value + else: + new_right_expr = -right_expr step["after"] = f"{sstr(new_left_expr)} = {sstr(new_right_expr)}" step["step"] = f"Multiply both sides by {sstr(value)}" diff --git a/main.py b/main.py index 3773f47..1193273 100644 --- a/main.py +++ b/main.py @@ -66,6 +66,17 @@ def generate_problem_message(): return problem +def main(): + problem_solved = False + while not problem_solved: + problem = generate_problem() + problem["steps"] = generate_steps(problem); + problem_solved = check_solution(problem["steps"][-1]["after"], problem["solution"]) + if not problem_solved: + print(f"issue with problem: {problem}") + + return pretty_print_steps(problem["steps"]) + def check_solution(got, solution): values = set([sympify(r.split("=")[1].strip()) for r in got.split(",")]) if is_iterable(solution) and not isinstance(solution, str): @@ -97,4 +108,8 @@ def is_iterable(obj): iter(obj) return True except TypeError: - return False \ No newline at end of file + return False + +#Starts the program +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/start.bat b/start.bat new file mode 100644 index 0000000..0494049 --- /dev/null +++ b/start.bat @@ -0,0 +1 @@ +uvicorn main:app --reload --host 0.0.0.0 --port 8000 \ No newline at end of file diff --git a/www/favicon.png b/www/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..9b5c211befe40b8d3f5e3773a21f1ef87b0879ad GIT binary patch literal 10665 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 literal 0 HcmV?d00001 diff --git a/www/index.html b/www/index.html index 187503f..4ff39fb 100644 --- a/www/index.html +++ b/www/index.html @@ -1,14 +1,17 @@ - + + -
Loading...
-
+ +
+
+
diff --git a/www/scripts/problem.js b/www/scripts/problem.js index 3b2d947..bbd77b7 100644 --- a/www/scripts/problem.js +++ b/www/scripts/problem.js @@ -1,15 +1,55 @@ -let state = "problem"; // problem | steps | done function showProblem() { const problemEl = document.getElementById("problem"); - const stepsEl = document.getElementById("steps"); + const stepsEl = document.getElementById("equation"); - problemEl.innerHTML = `\\(${problemData.problem}\\)`; + const formatted = formatMath(problemData.problem); + problemEl.innerHTML = `\\(${formatted}\\)`; stepsEl.innerHTML = ""; MathJax.typesetPromise(); } +function showStep() { + if (stepIndex >= problemData.steps.length) { + setTimeout(requestNextProblem, 3000); + return; + } + + const eqEl = document.getElementById("equation"); + const expEl = document.getElementById("explanation"); + + const step = problemData.steps[stepIndex]; + + expEl.innerHTML = step.step; + + // STEP 1: fade out + eqEl.classList.remove("fade-in"); + eqEl.classList.add("fade-out"); + + setTimeout(() => { + // STEP 2: update content + eqEl.innerHTML = `\\(${formatMath(step.after)}\\)`; + MathJax.typesetPromise(); + + // STEP 3: force reflow (CRUCIAL) + void eqEl.offsetWidth; + + // STEP 4: fade back in + eqEl.classList.remove("fade-out"); + eqEl.classList.add("fade-in"); + + stepIndex++; + + setTimeout(showStep, 2000); + }, 500); +} + +function startSteps() { + stepIndex = 0; + showStep(); +} + function startSequence() { setTimeout(() => { showNextStep(); @@ -29,17 +69,19 @@ function showNextStep() { } const s = problemData.steps[stepIndex]; + const formatted_step_before = formatMath(s.before); + const formatted_step_after = formatMath(s.after); const html = ` -
-
\\(${s.before}\\)
-
${s.step}
-
\\(${s.after}\\)
-

+
+
\\(${formatted_step_before}\\)
+
${s.step}
+
\\(${formatted_step_after}\\)
+
`; - stepsEl.innerHTML += html; + stepsEl.innerHTML = html; MathJax.typesetPromise(); @@ -48,3 +90,19 @@ function showNextStep() { setTimeout(showNextStep, 2000); // time between steps } +function formatMath(str) { + return str + .replace(/\*\*/g, "^") // Exponent Fix + .replace(/(\d+)\s*\*\s*x/g, "$1x") // 4*x -> 4x + .replace(/x\s*\*\s*(\d+)/g, "$1x") // x*4 -> 4x + .replace(/\b1x\b/g, "x") // 1x -> x + .replace(/(\d+)\s*\*\s*\(/g, "$1(") // 4*( -> 4( + .replace(/\)\s*\*\s*\(/g, ")(") // )*( -> )( + .replace(/x\s*\*\s*\(/g, "x(") // x*( -> x( + + // FRACTIONS (order matters!) + .replace(/\(([^()]+)\)\s*\/\s*\(([^()]+)\)/g, "\\frac{$1}{$2}") + .replace(/\(([^()]+)\)\s*\/\s*([a-zA-Z0-9]+)/g, "\\frac{$1}{$2}") + .replace(/([a-zA-Z0-9]+)\s*\/\s*\(([^()]+)\)/g, "\\frac{$1}{$2}") + .replace(/([a-zA-Z0-9]+)\s*\/\s*([a-zA-Z0-9]+)/g, "\\frac{$1}{$2}"); +} \ No newline at end of file diff --git a/www/scripts/web_sockets.js b/www/scripts/web_sockets.js index b0c997a..58b4f62 100644 --- a/www/scripts/web_sockets.js +++ b/www/scripts/web_sockets.js @@ -21,7 +21,7 @@ socket.onmessage = (event) => { showProblem(); // start animation sequence - startSequence(); + startSteps(); } }; diff --git a/www/style/styles.css b/www/style/styles.css index 4da1c9d..a64deee 100644 --- a/www/style/styles.css +++ b/www/style/styles.css @@ -1,4 +1,4 @@ -body { +html, body { margin: 0; height: 100vh; overflow: hidden; @@ -11,20 +11,91 @@ body { font-family: Arial; } -#waveCanvas { +#problem { position: absolute; + top: 10%; + left: 50%; + transform: translateX(-50%); + + font-size: 76px; + text-align: center; +} + +#equation { + position: absolute; + top: 30%; + left: 50%; + transform: translateX(-50%); + font-size: 32px; + + font-family: "Comic Sans MS", cursive; /* surprisingly effective */ + text-shadow: + 0 0 2px rgba(255,255,255,0.8), + 0 0 6px rgba(255,255,255,0.4); + transition: opacity 0.5s ease, transform 0.5s ease; +} + +#explanation { + position: absolute; + top: 45%; + left: 50%; + transform: translateX(-50%); + font-size: 24px; + opacity: 0.8; +} 28px; + +#steps { + position: absolute; + top: 27%; /* below the problem */ + left: 50%; + transform: translateX(-50%); + + width: 800px; + text-align: center; + font-size: 28px; +} + +#waveCanvas { + position: fixed; top: 0; left: 0; + width: 100%; + height: 100%; z-index: 0; } #particleCanvas { - position: absolute; + position: fixed; top: 0; left: 0; + width: 100%; + height: 100%; z-index: 0; } +.fade-out { + opacity: 0; + transform: translateX(-50%) scale(0.95); +} + +.fade-in { + opacity: 1; + transform: translateX(-50%) scale(1); +} + +.chalk-in { + opacity: 0; + transform: scale(1.05); + filter: blur(6px); +} + +.chalk-in-active { + opacity: 1; + transform: scale(1); + filter: blur(0px); + transition: all 0.4s ease; +} + @keyframes gradientShift { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; }