DDS Vibe Academy · Class #80 · Application

Your GPU or Nothing

Wire an Angular app so it dies without your GPU. Scope OLLAMA_ORIGINS instead of handing every site your inference stack. Tell four identical-looking failures apart. Ends with a live readiness gate nobody can fake.

Subject google/AIventure + Ollama Model gemma3:4b Stack Angular 19 + Phaser 3.90 Read time ~50 min Level Advanced
  • First-party teardown of a real Google project, cloned and inspected today
  • Live preflight gate that probes your local Ollama and cannot be faked
  • Asset forensics showing 0/118 valid PNGs and the ten-second integrity check
  • Graded evidence with every claim marked MEASURED, CALCULATED, or ASSERTED
Quick Answer

Set up Ollama on your own hardware, pull gemma3:4b, scope OLLAMA_ORIGINS to this site instead of the wildcard, and pass a live preflight gate that checks all three. The gate cannot be faked because either gemma3:4b is answering on your GPU or the gate stays red. Along the way you learn why CORS rejects and dead servers look identical to JavaScript, and why a green build is not evidence your assets survived.

Key Takeaways
  • Switching AIventure from cloud inference to local inference is a two-line comment swap in Angular's dependency injection. The app resolves one model backend through an injection token, not a vendor SDK.
  • The correct OLLAMA_ORIGINS value is https://ddsboston.com. The wildcard "*" hands your GPU to every site you visit. That advice came from a Google AI Studio remix, not the upstream repo.
  • A CORS rejection and a dead server both surface in JavaScript as an identical TypeError. The browser deliberately hides which one it was. Any tutorial claiming to detect "CORS error specifically" from client-side JS is wrong.
  • Chrome or Edge required. Safari blocks public sites from reaching local addresses regardless of CORS configuration.
  • AI Studio destroyed all 118 PNG files in the project — 0 of 118 still had a valid header. Every byte that was not valid UTF-8 became U+FFFD. 66,989 replacement sequences in one 161 KB sprite. A green build is not evidence your assets survived.
  • Apache 2.0 covers what the author owns. It cannot launder third-party art under a non-transferable licence. Read the README, not just the LICENSE file.

Section 01

Chrome or Edge Required

Before you start This class requires Chrome or Edge. Safari will not work and there is no workaround.

The gate on this page needs to reach http://127.0.0.1:11434 from a page served over HTTPS. That is a mixed-content scenario: a secure page reaching a non-secure local address.

Chromium (Chrome, Edge) treats http://127.0.0.1 as a potentially trustworthy origin. The browser allows the connection even though the page itself is HTTPS. That is a Chromium-specific policy decision.

Safari blocks public websites from reaching local addresses regardless of how Ollama is configured. That is a Safari security policy, not a CORS misconfiguration, and not something DDS or Ollama can override. If you are on Safari, switch to Chrome or Edge before continuing.

Grade: ASSERTED (W3C Secure Contexts / Chromium trustworthy-origin policy).

Section 02

The Subject Project

Answer capsule AIventure is a Google-authored Angular 19 + Phaser 3.90 text adventure that ships six model backends. Switching to Ollama is a two-line comment swap. The repo is Apache 2.0, but nine sprites carry a non-transferable Oryx Design Lab licence. Students clone the repo themselves; DDS hosts instructions, not art.
FactValueGrade
Repogithub.com/bebechien/AIventureMEASURED (cloned 2026-08-01)
AuthorGoogle (not an officially supported Google product)ASSERTED (repo README)
Code licenceApache 2.0MEASURED (LICENSE.txt)
StackAngular 19 + Phaser 3.90MEASURED (package.json)
Build outputStatic bundle via ng buildMEASURED (package.json scripts)
Stars / commits13 / 6MEASURED (repo page, 2026-08-01)
Files with Google LLC copyright71MEASURED (grep -rl)

Section 03

The Architectural Gate

Answer capsule Angular's dependency injection makes the "no cloud fallback" guarantee structural. The app resolves exactly one model backend through an injection token. Switching from cloud to local is a two-line comment swap in app.config.ts, not a rewrite.

The upstream repo ships six backends: Gemini, Ollama, LM Studio, Transformers.js, Chrome Prompt API, and MediaPipe LLM Inference. One is active at a time. The consumer injects MODEL_BACKEND, not GeminiService.

That is the whole payoff of the token pattern. Every component talks to an interface. The implementation behind it is a configuration choice, not a code change. Switching to Ollama means commenting one line and uncommenting another. Grade: MEASURED (read from the cloned upstream app.config.ts, 2026-08-01).

What Ollama is actually called with

The upstream service file hardcodes two values:

  • API URL: http://localhost:11434/api/chat
  • Model: gemma3:4b

The model is gemma3:4b, not gemma. The install step is ollama pull gemma3:4b. Getting this wrong is the single most likely reason a setup "silently does not work." Ollama returns a model-not-found error rather than an obvious failure.

The service uses streaming fetch. No proxy, no server, no API key. Grade: MEASURED (lines 28-29 of the upstream file).

Section 04

The CORS Lesson

Answer capsule A page served from https://ddsboston.com is a different origin from http://127.0.0.1. Ollama refuses cross-origin requests unless explicitly told otherwise. Three things must all be true before the browser gets a single token back.
  1. Ollama installed and running
  2. ollama pull gemma3:4b
  3. OLLAMA_ORIGINS permits the page's origin, and Ollama restarted afterward

Step 3 is a real skill that stays invisible until something needs it. A page that refuses to work until you configure CORS correctly teaches CORS better than any lesson about CORS.

The security point

Do not use the wildcard

OLLAMA_ORIGINS="*" permits every website you subsequently visit to reach your Ollama and use your GPU. That wildcard advice came from a Google AI Studio remix of this project, not from the upstream repo. The upstream error string is a bare "Error connecting to Ollama." with no CORS advice at all.

The correct value scopes access to one domain:

OLLAMA_ORIGINS=https://ddsboston.com

Windows: set it as a system environment variable, then restart Ollama.
macOS / Linux: export it before launching Ollama.

Section 05

Four Failures That Look Identical

Answer capsule This is the most useful thing in the class and it is not documented anywhere obvious. A CORS rejection and a dead server both surface in client-side JavaScript as an identical TypeError. The browser deliberately withholds which one it was.
Probe resultWhat it meansWhat you do
fetch throws TypeErrorOllama down OR origin not permittedCheck both. The browser will not say which
HTTP non-200Reachable, wrong responseRestart Ollama
200, gemma3:4b absent from /api/tagsModel not installedollama pull gemma3:4b
200, model presentReadyUnlock

A cross-origin rejection and a connection-refused both surface in JavaScript as an indistinguishable TypeError. The browser deliberately withholds which one it was. That is a privacy protection, not a bug. Grade: ASSERTED (Fetch spec behaviour), consistent with MEASURED behaviour while building the gate.

Any tutorial that claims to detect "CORS error specifically" from client-side JS is wrong. The preflight gate on this page says so plainly instead of guessing and sending you down the wrong path.

Section 06

Setup

Answer capsule Three steps on your machine, then pass the gate on this page. The gate is the completion proof. Nobody can fake it because there is architecturally nothing else for the app to call.
  1. Install Ollama from ollama.com, then run: ollama pull gemma3:4b
  2. Set the origin: OLLAMA_ORIGINS=https://ddsboston.com (Windows: system environment variable. macOS/Linux: export before launch.) Then restart Ollama.
  3. Pass the preflight gate below. All three steps must go green.

Prerequisite

This class assumes Ollama is installed. If you need the full install walkthrough, model catalog, API reference, and Modelfile guide, start with Class #67: The Definitive Ollama Masterclass.

Section 07

The Preflight Gate

Answer capsule The gate below probes your local Ollama on load. It checks three things: running, origin permitted, gemma3:4b installed. It pre-fills the exact fix command for each failure, including the OLLAMA_ORIGINS value computed at runtime from this page's origin. It is honest about the TypeError ambiguity rather than guessing.

This is the completion proof. Either gemma3:4b is answering on your hardware or the gate stays red. It is the most honest completion signal in the curriculum, and it costs DDS nothing to run: no inference bill, no API keys, no server.

DDS VIBE ACADEMY · REWARD UNLOCK

AIventure

A text adventure that thinks with your GPU. There is no cloud model behind this and no API key — it talks to the Ollama running on your machine, or it does not run at all.

Checking your machine…
  1. Ollama is running
  2. This site is allowed to reach it
  3. The gemma3:4b model is installed

Chrome or Edge required. Safari blocks websites from reaching local addresses no matter how Ollama is configured — that is a Safari policy, not something we can work around.

Section 08

Verify What the Tool Hands You

Answer capsule A Google AI Studio import of this project silently destroyed every image. Zero of 118 PNG files had valid headers. The app still compiled, the UI rendered, the assistant reported "building cleanly," and the game canvas was solid black. A green build is not evidence that your assets survived.
CheckAI Studio exportUpstream GitHub
Valid PNG headers0 / 118118 / 118
gamedata blobs decodable (Pillow)0 / 111111 / 111
Sample sprite size292,599 bytes161,182 bytes
PNG magic bytesEF BF BD 50 4E 4789 50 4E 47

Grade: MEASURED. Both archives extracted and analysed on 2026-08-01.

The mechanism

EF BF BD is UTF-8 for U+FFFD, the replacement character. The binaries were decoded as text somewhere in the ingest pipeline. Every byte that was not valid UTF-8 became U+FFFD, and each one-byte value became three. One 161 KB sprite came back as 292 KB containing 66,989 replacement sequences. Grade: MEASURED (byte scan).

That substitution is lossy. The original byte values are gone. No repair is possible, and asking the assistant to "fix the images" cannot work because it would be generating new art, not recovering old.

How to catch it in ten seconds

Every PNG must start with the same 8 magic bytes: 89 50 4E 47 0D 0A 1A 0A. Run this against the directory:

find . -name "*.png" -exec sh -c 'head -c8 "$1" | xxd | head -1' _ {} \;

Or in Python, decode them and count the failures. The point is that a one-line integrity check would have caught this before a week of work went on top of it.

A latent build break worth seeing

The AI Studio copy kept socket.service.ts, which imports from socket.io-client, while dropping the dependency from package.json. Dead code with a live import is invisible until a clean production build. Deleting the file was the correct fix; adding a dependency for code nobody calls would not have been. Grade: MEASURED.

Section 09

The README Outranks the LICENCE File

Answer capsule LICENSE.txt is Apache 2.0. 71 files carry Copyright 2026 Google LLC. On that evidence alone the obvious conclusion is "Apache 2.0, redistribution permitted, ship it." That conclusion is wrong, and the repo's own README says so.

The README discloses that several sprites were licensed from the Oryx Design Lab Wee Fantasy sprite pack. Nine files are named. All nine are present in the repo. Grade: MEASURED (README lines 110-130; all nine files confirmed).

The Oryx Design Lab licence states:

This archive or files within MAY NOT BE REDISTRIBUTED and are intended for the sole use of the Licensee.

And: "The license is not transferable." Grade: ASSERTED (oryxdesignlab.com/license, fetched 2026-08-01).

The rule this teaches: an Apache 2.0 header covers what the author owns. It cannot launder third-party art the author licensed but does not own. A permissive LICENSE.txt does not survive contact with a non-transferable dependency. Read the README and the credits before you conclude anything about redistribution.

ActionVerdict
Host the game or its assets on ddsboston.comNo. That is DDS redistributing Oryx art
Link students to Google's public repo to cloneYes. DDS redistributes nothing
Redistribute the Apache-2.0 code (e.g. a patch)Yes, licence retained

Sprites by Oryx Design Lab (Wee Fantasy pack) — www.oryxdesignlab.com

Section 10

The Reward: Run It on Your GPU

Answer capsule You passed the gate. Your Ollama is running, this origin is permitted, and gemma3:4b is installed. Now clone the repo, swap two lines, and play a game that runs entirely on your own hardware.
  1. git clone https://github.com/bebechien/AIventure
  2. cd AIventure && npm install
  3. Open src/app/app.config.ts. Comment out the LmStudioService line. Uncomment the OllamaService line. Two lines, one swap.
  4. npm run dev
  5. Open localhost:4200 in Chrome or Edge. The game runs entirely on your GPU. No cloud model, no API key, no inference bill.

This is the Academy's thesis demonstrated rather than asserted: a capable model, running on hardware you already own, for nothing.

Sprites by Oryx Design Lab (Wee Fantasy pack) — www.oryxdesignlab.com

Bottom Line

Bottom Line

You wired an app so it dies without your GPU. You scoped OLLAMA_ORIGINS to one domain instead of handing every site you visit your inference stack. You told four identical-looking failures apart and passed a gate that cannot be faked. Along the way you learned that a green build is not evidence your assets survived, and that an Apache 2.0 header does not cover art the author licensed but does not own.

Nobody can fake this completion. Either gemma3:4b is answering on your hardware or the gate stays red. That is the most honest completion signal in the curriculum, and it costs nothing to run.

FAQ

Frequently Asked Questions

What is the Ollama local-only gate?

A preflight check embedded in this class page that probes your local Ollama instance. It verifies three things: Ollama is running, the page origin is permitted via OLLAMA_ORIGINS, and the gemma3:4b model is installed. All three must be true before the gate goes green. Nobody can fake completion because either gemma3:4b is answering on their hardware or the gate stays red.

What model does the AIventure game require?

gemma3:4b. Not gemma. The upstream Ollama service file hardcodes the model string as gemma3:4b on line 29. The install step is ollama pull gemma3:4b. Getting the name wrong is the single most likely reason a student setup silently does not work because Ollama returns a model-not-found error rather than an obvious failure.

Why does OLLAMA_ORIGINS matter?

A page served from https://ddsboston.com is a different origin from http://127.0.0.1. Ollama refuses cross-origin requests unless explicitly told otherwise. Setting OLLAMA_ORIGINS to the wildcard star hands your GPU to every website you subsequently visit. The correct value is OLLAMA_ORIGINS=https://ddsboston.com, which permits only this site.

Can I use Safari for this class?

No. Safari blocks public websites from reaching local addresses regardless of how Ollama is configured. This is a Safari security policy, not something that can be worked around. Chrome or Edge is required because Chromium treats http://127.0.0.1 as a potentially trustworthy origin, so an HTTPS page can reach localhost without triggering mixed-content blocking.

Can JavaScript tell whether Ollama is down or CORS is blocking?

No. A cross-origin rejection and a connection-refused both surface in client-side JavaScript as an identical TypeError. The browser deliberately withholds which one it was as a privacy protection, not a bug. Any tutorial that claims to detect a CORS error specifically from client-side JS is wrong. The preflight gate on this page says so plainly instead of guessing.

Why can't the game be played on ddsboston.com?

Nine sprites in the upstream AIventure repo are Oryx Design Lab art under a licence that reads MAY NOT BE REDISTRIBUTED and The license is not transferable. Google is the licensee, not DDS. Hosting the game or its assets on ddsboston.com would be redistributing Oryx art. Students clone the public repo themselves and run it locally. DDS hosts instructions, not art.

What did AI Studio do to the game assets?

AI Studio silently destroyed every image in the project. Zero of 118 PNG files had valid headers. The files were decoded as text somewhere in the ingest pipeline and every byte that was not valid UTF-8 became the replacement character U+FFFD, turning each one-byte value into three. One 161 KB sprite came back at 292 KB containing 66,989 replacement sequences. The substitution is lossy and the original byte values are gone.

How do I verify PNG integrity in ten seconds?

Every PNG must start with the same 8 magic bytes: 89 50 4E 47 0D 0A 1A 0A. Run find dot -name star.png -exec sh -c head -c8 dollar1 pipe xxd pipe head -1 underscore braces backslash semicolon against the directory. Any file whose first byte is EF BF BD instead of 89 has been through a UTF-8 text decode and is destroyed. A green build is not evidence that your assets survived.

What does this masterclass cost?

Nothing. This masterclass is free. No signup, no email, no paywall, no certificate requirement. It is part of the DDS Vibe Academy, a free AI coding curriculum built by Robert McCullock at Design Delight Studio.

What is the prerequisite for this class?

Class 67, The Definitive Ollama Masterclass. That class covers every install path, the model catalog, the API and Modelfile, and editor integrations. This class assumes Ollama is installed and focuses on CORS, the local-only gate pattern, asset forensics, and licence analysis.

DDS Vibe Academy

Keep Building

This class is one of a free curriculum that maps the full territory from first prompt to sovereign stack. No signup. No paywall. Built in the spirit of the first internet.