Beyond 'eval()': How I Built a Step-by-Step Math Calculator That Explains Its Work with AI A developer built a step-by-step math calculator that explains its work using an AI model combined with LaTeX and MathJax. The tool handles arithmetic, algebra, fractions, and word problems, avoiding eval() for security and clarity. The AI provides flexible reasoning while normal code manages the interface and formatting. Building a calculator that returns an answer takes little code. Building one that explains how it reached that answer creates a different problem. Take this expression: 12 + 6 × 3 JavaScript can calculate the result with simple code. js const result = 12 + 6 3; console.log result ; // 30 That gives the correct answer. It does not explain the work. A student may need to see this: 12 + 6 × 3 Step 1: Multiply 6 by 3. 6 × 3 = 18 Step 2: Add 12 and 18. 12 + 18 = 30 Final answer: 30 That difference between calculating and explaining became the main challenge when I worked on a step-by-step math calculator. I wanted something that could handle more than basic arithmetic. The calculator needed to work with equations, fractions, algebra, percentages, calculus, word problems, and other math questions. I also wanted clean mathematical notation. That meant solving several separate problems: I ended up using an AI model together with normal application code, LaTeX, and MathJax. The AI handles the flexible reasoning. LaTeX describes the math. MathJax turns the LaTeX into readable mathematical notation. JavaScript handles the interface and application logic. eval is not enough A basic JavaScript calculator often starts with something like this: js const expression = "12 + 6 3"; const answer = eval expression ; console.log answer ; There are two problems with this approach. The first problem is security. Passing raw user input to eval can execute JavaScript. That makes it a poor choice for a public calculator. The second problem matters even more here. eval gives me this: 30 It does not give me this: 6 × 3 = 18 12 + 18 = 30 It also cannot explain why multiplication happens before addition. The limitation becomes clearer with algebra. Consider: 2x + 5 = 17 A useful result should look like this: 2x + 5 = 17 Subtract 5 from both sides. 2x = 12 Divide both sides by 2. x = 6 JavaScript does not understand 2x + 5 = 17 as a normal JavaScript expression. A step-by-step solver needs more than expression evaluation. One option would be to write custom solving logic for every type of math. I could start with addition. Then subtraction. Then multiplication. Then division. Then fractions. Then percentages. Then linear equations. Then quadratic equations. Then powers and roots. Then logarithms. Then derivatives. Then integrals. The amount of code would keep growing. Even one category contains many different forms. A linear equation might look like this: 2x + 5 = 17 It might also look like this: 4 x - 2 = 20 Or: 3x + 7 = x + 19 The steps change for each case. Word problems create another issue. A rectangle has a length of 12 cm and a width of 7 cm. What is its area? A normal expression parser first needs to understand the sentence. It then needs to identify the correct formula. Only after that can it calculate the answer. I did not want to create thousands of explanation rules by hand. That is where an AI model became useful. I do not treat the AI model as the whole application. It handles the part that benefits from flexible reasoning and language. The rest of the system still uses normal code. A simplified flow looks like this: User enters a problem ↓ Application processes the input ↓ Solver receives the problem ↓ AI works through the solution ↓ AI returns structured output ↓ Application checks the response ↓ MathJax formats the math ↓ Steps appear in the browser The model can understand different forms of math without requiring one hard-coded path for every possible question. That does not mean the model gets full control. The application still decides how the response should look and how it should reach the screen. I do not want the model to return a random block of text. A response like this is difficult to control: Okay Let's solve this problem. First we need to... The wording may change on every request. The frontend also has to guess where one step ends and another begins. Structured output works better. For example: { "finalAnswer": "\\ x = 6\\ ", "steps": { "explanation": "Start with the equation.", "math": "\\ 2x + 5 = 17\\ " }, { "explanation": "Subtract 5 from both sides.", "math": "\\ 2x = 12\\ " }, { "explanation": "Divide both sides by 2.", "math": "\\ x = 6\\ " } } Now the roles stay clear. The AI produces the solution data. The application controls the interface. This gives me much more predictable output. Getting the correct steps from AI solves only part of the problem. Math can look bad in plain text. Take the quadratic formula. The AI could return: x = -b +- sqrt b^2 - 4ac / 2a A human can understand it. It does not look like proper mathematical notation. LaTeX gives the model a standard way to describe the expression. x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a} The same approach works for fractions: \frac{3x + 2}{x - 5} Square roots: \sqrt{x^2 + 9} Powers: x^{12} Integrals: \int 0^5 x^2 \, dx Matrices: \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix} LaTeX gives the application one consistent format for mathematical expressions. The AI does not need to invent a different visual style for every problem. LaTeX is still text. A browser does not automatically turn this: \ \frac{x+2}{3}=7\ into a properly formatted equation. That is where MathJax comes in. The full flow looks more like this: User Input ↓ Input Processing ↓ Solver Router ↓ AI or Local Math Engine ↓ Validation ↓ Structured JSON ↓ LaTeX Expressions ↓ MathJax ↓ Step-by-Step Interface The AI decides what the solution should contain. LaTeX describes the mathematical notation. MathJax renders that notation inside the page. Each part has one clear job. The prompt matters a lot. I do not send only: Solve this: 2x + 5 = 17 That gives the model too much freedom. I define the expected output. A simplified prompt might look like this: Solve the math problem step by step. Keep each explanation short. Do not skip important operations. Return mathematical expressions as LaTeX. Use \ ... \ for inline math. Use \ ... \ for equations that should appear on their own line. Do not return HTML. Do not place LaTeX inside Markdown code blocks. Return valid JSON. Use this structure: { "finalAnswer": "", "steps": { "explanation": "", "math": "" } } I can also add instructions for specific types of problems. For algebra: Show what operation happens to both sides of the equation. For fractions: Show the common denominator when one is required. For calculus: State the rule used before applying it. The prompt does not need to teach mathematics from scratch. The model already handles the reasoning. The prompt defines how I want the result delivered. There is one small detail that can cause confusing bugs. LaTeX uses backslashes. For example: \frac{3}{4} JSON strings also use backslashes for escaping. That means serialized JSON may contain: { "math": "\\ \\frac{3}{4}\\ " } The double backslashes are normal. After JavaScript parses the JSON, the string becomes the LaTeX expression that MathJax needs. This matters for commands such as: \frac \sqrt \times \div \int Incorrect escaping can break otherwise valid AI output. A page can load MathJax from a content delivery network. A simple setup can look like this: