Inspiration

Learning from mistakes it the best way to improve. This is what we are extremely convinced about. But when it comes to execution, we tend to fail. The entire idea started with our own experiences. I myself have a box, where I put all of my exams in. Every time I receive a corrected exam, I tell myself: I will read this now and see my mistakes. But every time I either forget, or just don't want to (when I see the horrible grade I just can't continue reading). But that exactly is where I feel missed out. I actually feel, from the bottom of my heart, that I'm loosing something, an opportunity, a chance.

Therefore, when we saw this hackathon, we had no troubles finding a project! We directly started doing our work. This is something we would have done either way. With and without this hackathon.

What it does

Our AI + Education tool works like this: When you get your exam, or any corrected work (homework, assignment etc.), you can simply take a picture of it and send it to Examina. Examina will then send this picture to an ai that analyses it (while shredding the exam in the digital world. This provides the machine with time to analyse, but also means metaphorical for: The exam is over. The past is in the past. We won't keep it, but we will learn from it).

The ai will now generate the stage 1 JSON file. This is a factual depiction of the exam. Basically a digital copy of the exam. It contains information such as: grade, date, subject, topic, tasks, answers, feedbacks... This JSON file will then be feed to ai again, generating the stage 2 JSON file. This is a deep analysis based on the JSON file before. It recognizes what mistakes were made. What this means. Why these mistakes were made. What is the main issue. What are weak spot and strong spots. And so on and so forth. This JSON file is essential for the tool and makes a huge difference. It doesn't just see the exam, but also understands it. After having the stage 2 JSON file we can generate the stage 3 JSON file. Different from the other two JSON files, we don't have one of this for each exam, but each user has exactly one stage 3 JSON file. This is a deep analysis of the user itself. It is generated based on all of the stage 2 JSON files, collecting all the information about all of the exams. How does this user learn. What is it good/bad at. Has he/she improved? Etc.

After this, the ai gets the stage 2 and stage 3 JSON files and generates a study plan to improve, learn from the mistakes and also prepare for the next exam. But that's not all. It also generates interactive tasks for each day you can study.

How we built it

Two halves: a pipeline that verifies itself, and a room that's compiled rather than modelled.

The pipeline runs on Next.js 15, React 19, and TypeScript. Every model call passes through a single function: we derive a JSON Schema from a Zod contract, embed it in the prompt, pull the JSON back out of whatever the model wraps it in, and validate it against that same contract. If validation fails, we retry once with the error echoed back to the model, and if it still fails, it fails loudly rather than quietly. Nothing untyped ever reaches a component. The provider underneath is swappable too: by default it's the local Claude Code CLI, so the whole thing runs with no API key required, but it can just as easily point at the Anthropic API instead.

Stage 1 does nothing but transcribe. Stage 2 is where we stop trusting the model and start checking it. Code computes the numbers first, things like scores, blank rate, work-shown rate, and chronology, and passes them into the prompts as established facts. The model is only ever asked to interpret those numbers, never to count them itself. Three specialist analyses run concurrently: Newman error stages, habits and metacognition, and feedback uptake. Each one's methodology lives in its own markdown skill file, injected into its system prompt, so tuning the analysis just means editing markdown rather than touching code. When a specialist needs a category outside our fixed taxonomy, it can mint one as custom dot slug, and code then normalizes and deduplicates these afterward, so IDs stay stable across runs. Evidence itself is enforced in code, not taken on the model's word. References are parsed with a regular expression and resolved against the stage-1 arrays. If a claim references something that doesn't actually exist, that reference is dropped, and if a claim ends up with no valid references left, it's removed entirely, with that removal counted and reported rather than silently swallowed. Counts are treated as contracts, not suggestions. If the model comes up short, it gets up to two top-up calls, each one shown exactly what it already produced and asked for precisely the remainder, merged back in by id and by identical prompt text. Overflow is trimmed deterministically, and if it's still short after that, it's a hard fail rather than a partial result. For mock exams specifically, we count the question and answer markers against what was requested, compile with two-pass pdflatex in a temp directory, and if that fails, feed the log excerpt back for one repair attempt.

The room is generated by four Blender Python scripts rather than modelled by hand. Textures are periodic value-noise lattices, addressed through world-space box-projected UVs where one UV unit equals one metre, so texel density stays identical across every surface, and a whole material family can share a single roughness and normal set, just tinting its detail luminance for the albedo. Cycles bakes diffuse direct-plus-indirect irradiance, with no colour, into a 2048 atlas on a second UV set, for both day and night. Since Cycles won't denoise a bake at all, that atlas instead runs through the compositor's OIDN node, a twelve times drop in RMS noise on a synthetic gradient test, rather than a Gaussian blur, which wouldn't be able to tell noise apart from a contact shadow. And because glTF has no dedicated lightmap slot, it ends up riding along in the occlusion channel, since that's the only one the exporter actually binds to the second texture coordinate set.

From there it goes through Godot 4.7, exported to WASM under GL Compatibility, with zero real-time lights and zero shadow maps. The shader places baked irradiance in emission and leaves albedo physically accurate, so normal maps and environment specular still read correctly. The one over pi factor is three.js's Lambert divisor, kept in place so the room doesn't come out pi times too bright. Day and night are controlled by a single global uniform float, room night, written through the rendering server, so all around fifty-five compiled shaders crossfade together off one assignment. Collision is derived from the GLB automatically at load time, and anchors are just empties exported out of the blend file, so restaging the room only ever means a re-export, never a code change. The whiteboard is a control tree rendered into a sub viewport and read back as an image texture, since a live viewport texture silently fails to bind under compatibility mode, painted onto a quad built from the wall face's own corners, so it still picks up baked light correctly.

Setting thread support to false selects the no-threads template, which means there are no COOP or COEP headers to configure at all. The whole room comes out to roughly 25 megabytes gzipped and embeds anywhere. React talks to the engine over a small JSON bridge, and headless GDScript walks through the entire loop in CI-style checks, including one invariant specifically built to catch the lightmap landing on the wrong UV set.

Challenges we ran into

The ai sounds exactly as confident when it's wrong. That was the scary part. It'll give you 13 days when you asked for 14, or tell a student something about themselves that isn't in any of their exams, and it says it beautifully either way. So we stopped trusting it. Counts get checked in code. Claims have to name the exam question they came from, and if the reference doesn't exist, the sentence gets deleted. We show the count in the UI so you can see it happened.

Then Blender and Godot ate about a week. The room came out twice as dark because we were gamma-correcting everything twice without knowing. The lighting bake bled between unrelated parts of the texture, so the picture rail came out in blocky bands and the lamp cable came out green. After the Godot port, the office chair was RGB static and the monitor face had green bars.

All three look like a broken texture file. None of them were. Every time it was two correct things paired wrong, and every time we lost hours looking at the wrong half. Now we render the colour and the lighting as two separate images so we can see which one is lying.

The hardest part wasn't code though. Once the Godot room worked we had two working 3D rooms, and deleting the three.js one, the one we built first, genuinely hurt. We did it anyway.

Accomplishments that we're proud of

Honestly, for our first hackathon, we think we can be proud of us that we have even made it. But what makes us especially proud are our ideas. The tool itself for example. But also the idea to make an interactive 3d interface showing a cozy room. This makes the usage of our tool not just a bit more interesting and funny. The shredder machine, the streak and the animated UI, all creating a sense of accomplishment and spiking dopamine. Not to forget the sleeping time, set to remind students that a healthy body is way more precious that a good grade. All of these small ideas don't just make out product a hackathon project, but actually a tool that you can use and you would want to use. (We will definitely continue using it) That's what makes us the proudest.

What we learned

We learned an incredible amount of new stuff. Of course we have learned a lot about ai and ML. But also in coding. Coding for example with three.js or godot, with react. But also many new skills such as using blender or controlling a character in 3d model. Besides the technical stuff, we also learned to communicate. To cooperate with each other in one project. To brainstorm together and report each other what we have found.

What's next for Examina

Examina will not be abandoned after this hackathon. We will continue fine tuning and exploring possibilities. Our idea for the next step, is to give it a huge amount of exams from ourselves and make it learn from that. Make it see how exams could also look like in, what tasks are out there. The more data it gets, the better it should become. We hope one day, we could use it ourselves to prepare for the next exam.

Built With

Share this project:

Updates

Submission history