Fade in and fade out
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -95,19 +95,27 @@ def multiply_both_sides(equation, value):
|
|||||||
left_expr = parse_expr(left, transformations=transformations, evaluate=False)
|
left_expr = parse_expr(left, transformations=transformations, evaluate=False)
|
||||||
right_expr = parse_expr(right, 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)
|
new_left_expr = cancel(left_expr * value)
|
||||||
elif left_expr == 1:
|
elif left_expr == 1:
|
||||||
new_left_expr = value
|
new_left_expr = value
|
||||||
else:
|
elif value == 1:
|
||||||
|
new_left_expr = left_expr
|
||||||
|
elif left_expr == -1:
|
||||||
new_left_expr = -value
|
new_left_expr = -value
|
||||||
|
else:
|
||||||
|
new_left_expr = -left_expr
|
||||||
|
|
||||||
if right_expr != 1 and right_expr != -1:
|
if right_expr != 1 and right_expr != -1 and value != 1 and value != -1:
|
||||||
new_right_expr = Mul(right_expr, value, evaluate=False)
|
new_right_expr = safe_format(Mul(right_expr, value, evaluate=False))
|
||||||
elif right_expr == 1:
|
elif right_expr == 1:
|
||||||
new_right_expr = value
|
new_right_expr = value
|
||||||
else:
|
elif value == 1:
|
||||||
|
new_right_expr = right_expr
|
||||||
|
elif right_expr == -1:
|
||||||
new_right_expr = -value
|
new_right_expr = -value
|
||||||
|
else:
|
||||||
|
new_right_expr = -right_expr
|
||||||
|
|
||||||
step["after"] = f"{sstr(new_left_expr)} = {sstr(new_right_expr)}"
|
step["after"] = f"{sstr(new_left_expr)} = {sstr(new_right_expr)}"
|
||||||
step["step"] = f"Multiply both sides by {sstr(value)}"
|
step["step"] = f"Multiply both sides by {sstr(value)}"
|
||||||
|
|||||||
15
main.py
15
main.py
@@ -66,6 +66,17 @@ def generate_problem_message():
|
|||||||
|
|
||||||
return problem
|
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):
|
def check_solution(got, solution):
|
||||||
values = set([sympify(r.split("=")[1].strip()) for r in got.split(",")])
|
values = set([sympify(r.split("=")[1].strip()) for r in got.split(",")])
|
||||||
if is_iterable(solution) and not isinstance(solution, str):
|
if is_iterable(solution) and not isinstance(solution, str):
|
||||||
@@ -98,3 +109,7 @@ def is_iterable(obj):
|
|||||||
return True
|
return True
|
||||||
except TypeError:
|
except TypeError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
#Starts the program
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
1
start.bat
Normal file
1
start.bat
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uvicorn main:app --reload --host 0.0.0.0 --port 8000
|
||||||
BIN
www/favicon.png
Normal file
BIN
www/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
@@ -1,14 +1,17 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
|
<link rel="icon" type="image/png" href="favicon.png">
|
||||||
<link rel="stylesheet" href="style/styles.css">
|
<link rel="stylesheet" href="style/styles.css">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<canvas id="waveCanvas"></canvas>
|
<canvas id="waveCanvas"></canvas>
|
||||||
<canvas id="particleCanvas"></canvas>
|
<canvas id="particleCanvas"></canvas>
|
||||||
<div id="problem">Loading...</div>
|
|
||||||
<div id="steps"></div>
|
<div id="problem"></div>
|
||||||
|
<div id="equation"></div>
|
||||||
|
<div id="explanation"></div>
|
||||||
|
|
||||||
<script src="scripts/background.js"></script>
|
<script src="scripts/background.js"></script>
|
||||||
<script src="scripts/problem.js"></script>
|
<script src="scripts/problem.js"></script>
|
||||||
|
|||||||
@@ -1,15 +1,55 @@
|
|||||||
let state = "problem"; // problem | steps | done
|
|
||||||
|
|
||||||
function showProblem() {
|
function showProblem() {
|
||||||
const problemEl = document.getElementById("problem");
|
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 = "";
|
stepsEl.innerHTML = "";
|
||||||
|
|
||||||
MathJax.typesetPromise();
|
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() {
|
function startSequence() {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
showNextStep();
|
showNextStep();
|
||||||
@@ -29,17 +69,19 @@ function showNextStep() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const s = problemData.steps[stepIndex];
|
const s = problemData.steps[stepIndex];
|
||||||
|
const formatted_step_before = formatMath(s.before);
|
||||||
|
const formatted_step_after = formatMath(s.after);
|
||||||
|
|
||||||
const html = `
|
const html = `
|
||||||
<div class="step">
|
|
||||||
<div>\\(${s.before}\\)</div>
|
|
||||||
<div>${s.step}</div>
|
|
||||||
<div>\\(${s.after}\\)</div>
|
|
||||||
</div>
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
<div class="step">
|
||||||
|
<div>\\(${formatted_step_before}\\)</div>
|
||||||
|
<div>${s.step}</div>
|
||||||
|
<div>\\(${formatted_step_after}\\)</div>
|
||||||
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
stepsEl.innerHTML += html;
|
stepsEl.innerHTML = html;
|
||||||
|
|
||||||
MathJax.typesetPromise();
|
MathJax.typesetPromise();
|
||||||
|
|
||||||
@@ -48,3 +90,19 @@ function showNextStep() {
|
|||||||
setTimeout(showNextStep, 2000); // time between steps
|
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}");
|
||||||
|
}
|
||||||
@@ -21,7 +21,7 @@ socket.onmessage = (event) => {
|
|||||||
showProblem();
|
showProblem();
|
||||||
|
|
||||||
// start animation sequence
|
// start animation sequence
|
||||||
startSequence();
|
startSteps();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
body {
|
html, body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -11,20 +11,91 @@ body {
|
|||||||
font-family: Arial;
|
font-family: Arial;
|
||||||
}
|
}
|
||||||
|
|
||||||
#waveCanvas {
|
#problem {
|
||||||
position: absolute;
|
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;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#particleCanvas {
|
#particleCanvas {
|
||||||
position: absolute;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
z-index: 0;
|
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 {
|
@keyframes gradientShift {
|
||||||
0% { background-position: 0% 50%; }
|
0% { background-position: 0% 50%; }
|
||||||
50% { background-position: 100% 50%; }
|
50% { background-position: 100% 50%; }
|
||||||
|
|||||||
Reference in New Issue
Block a user