Haunted AI: Whispers of Blackthorn Manor — A Local Qwen Detective Game
This is a submission for the Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine . What I Built Haunted AI: Whispers of Blackthorn Manor is a supernatural detective browser game. A death in 1926 brings you into a mansion a century later. Eleanor, Thomas and Clara each remember diffe

Hacktoberfest Open-Source AI Challenge: Ghost in the Machine Submission 👻🌼
This is a submission for the Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine.
Haunted AI: Whispers of Blackthorn Manor is a supernatural detective browser game. A death in 1926 brings you into a mansion a century later. Eleanor, Thomas and Clara each remember different parts of the night, and you need evidence to understand what happened.
You explore six rooms, collect eight clues, reconstruct a torn letter, calibrate a memory machine and connect evidence on a detective board. You finish by submitting a supported theory. There are three endings: Truth Revealed, Partial Truth and False Accusation.
The idea behind the AI was to give each ghost a limited, consistent view of the mystery. I wanted players to question characters naturally while still being able to reason from clues. That made the connection between the game rules, story content and local model the main engineering challenge.
This silent, approximately two-minute highlight shows exploration, clue collection, the journal, opening the letter drawer, the reconstruction interface and a genuine live Qwen reply from Eleanor. The reply's actual source label stays visible. The clip does not show a completed puzzle or ending; those were checked in separate full playthroughs.
Source code and setup: Kevin-Phon/haunted-ai-showcase.
Project contributions are published under the MIT license to the extent of rights the owner can grant. Upstream software/model terms remain separate, and no exclusive copyright in generated outputs is asserted.
The source includes setup instructions, the spoiler-free player guide, API/data schemas, tests and media provenance. Source spoiler warning: canonical story data and tests contain solutions and ending criteria. The runtime frontend does not receive that complete hidden content.
The project has one React/TypeScript frontend, one Python/FastAPI backend and structured JSON game data. Vite, Tailwind CSS and Motion for React handle the browser presentation. Ollama runs the open-weight qwen2.5:1.5b model locally; the tested configuration was Q4_K_M with Ollama 0.40.13 on an 8 GiB Mac.
Browser action -> FastAPI validation -> game rules -> public state Ghost question -> permitted character knowledge -> AI adapter -> local Ollama/Qwen -> output validation -> authored factual clauses + actual source label Enter fullscreen mode Exit fullscreen mode The browser sends typed actions under a versioned contract. The backend checks room access, object state, evidence, puzzles, deductions and theory support. It owns progression and endings. Moving a card or animating an object cannot award progress.
For dialogue, the backend filters the selected ghost's knowledge against the current investigation and relationship state. It removes superseded beliefs and sends a bounded selection of permitted facts and recent history to the model. It does not send the complete hidden case truth as a prompt.
Qwen selects permitted authored fact IDs and a reaction from a fixed vocabulary using structured output. The backend validates that selection and renders authored factual clauses. This is real inference, with a deliberate content boundary: the model does not freely write every factual sentence, invent clues or decide an ending.
The AI adapter keeps the provider boundary separate from the frontend. Another provider could be implemented behind it, although provider swapping has not been tested. The local Ollama path needs no external paid-service API key. Model weights stay outside the repository.
There is a ten-second provider deadline. Unavailable, slow or invalid output produces visibly labeled authored fallback. Demo mode also uses authored dialogue, but makes no model call. A configured model or healthy server is not treated as proof of live inference.
That distinction mattered in testing. A complete live-mode browser run reached Truth Revealed at 14/14 milestones and restarted cleanly. Clara and Thomas returned live Qwen responses; Eleanor timed out and used labeled fallback. I kept that failure in the record rather than describing the run as all-live. The recorded highlight separately captured a successful live Eleanor reply.
Local open-weight inference made the model connection inspectable and runnable on my laptop. I could work on the knowledge boundary, structured output and failure behavior without putting an external provider key in the browser. The authored story and deterministic rules remain inspectable separately from model selection.
The useful lesson was that a small model becomes more practical when its responsibility is narrow. It helps select a character's response to a natural-language question; the game engine handles truth and progression. The selected Qwen model has an Apache-2.0 license, while Ollama is separately MIT-licensed. Those upstream terms are distinct from the project's own license.
There are tradeoffs. Replies can be broad or repetitive, and cold loading or resource pressure can trigger fallback. I have not trained or fine-tuned a model, verified every offline scenario or benchmarked this against a closed-model implementation. The value here is a working local connection with clear boundaries and honest failure handling.
A fresh single-revision macOS setup passed 20 Data, 56 Backend and 36 Frontend tests, plus schema, lint, formatting, type, production-build and bundle checks. All eleven media references were verified. The sanitized publication copy separately passed those test counts and 39 contract fixtures with actual in-process public API projections, using existing matching dependency environments. Its code and media remain unchanged; documentation and internal provenance identifiers were the reviewed packaging differences.
Separate browser runs exercised all six rooms, eight clues, both puzzles, four deductions, all three demo endings and restart. Keyboard controls, focus, reduced motion, a narrow viewport and opt-in sound received scoped checks. Physical touch devices, a full screen-reader/contrast audit and broad performance testing remain unverified.
Sessions are in one backend process's memory; restarting it loses saves. The dependency audit retained eleven moderate development-tool findings, with zero high, critical or production-dependency findings in that audit. This is a local game, not a deployed multiuser service or a guarantee of model reliability.
I supplied the concept and creative direction and coordinated development with Codex assistance for implementation, fictional story material, tests and documentation. The specialist chats were AI development tools, not human teammates.
Six room images and three fictional portraits were generated with OpenAI's imagegen tool from original project prompts; its underlying model version was not exposed. Qwen did not generate the artwork. Ambient and discovery sounds were synthesized by project code without samples or recordings. Fonts are system fonts. File-level provenance and upstream notices are included with the source; no exclusive copyright in generated outputs is asserted.