DEV Community

Cover image for interactive ski-planning prototype
emi
emi

Posted on

interactive ski-planning prototype

Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass Submission 🌿

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass

What I Built

Lift-Lap Planner is a local ski-outing planning prototype
users can make a request, add constraints such as 'only blue runs, no drag lifts, and I only have 2 hours', correct anything the model misses, then get a generated compact simulated itinerary for their ski day!

the intended users are skiers and snowboarders who want to spend less time staring at a map and more time on the slopes! the current prototype I have is for trying and testing the interaction of planning the routes, but not yet for navigating the real mountain.

the language component uses the open-weight Qwen3-8B model via Tinker. a separate python planner owns connectivity, difficulty, lift restrictions, times, and closures.

Lift-Lap: visible constraints, a fictional mountain map and a confirmed simulated itinerary

the screen is meant to be the short part: review, confirm, print/download the itinerary. unfortunately I won't be able to field test this myself until ski season starts. but I'm excited to give it a try once its snowing!

Demo

this recording uses an exact replay of a real Qwen3-8B app response. It deliberately preserves the “no drag lifts” mistake. then I correct the hard exclusions locally, confirm the constraints, and inspect the simulated route. the interface labels the response as recorded AI, not fresh inference.

the walkthrough also shows itinerary-step inspection, local text export, closed lifts, an unsupported request, mobile layout and the geographic terrain lab. there is no hosted public inference service. anyone can run the default app without credentials using rules mode or that exact-input recorded example; arbitrary live AI requests require the separately configured research environment.

Code

GitHub Repo

git clone https://github.com/emihiggins/touch-grass-tinker.git
cd touch-grass-tinker
python3 -m liftlap.server --port 8767
Enter fullscreen mode Exit fullscreen mode

then open http://127.0.0.1:8767 on the same computer. no package installation, model download, API key or paid call is required for the default demo.

How I Built It

model before the planner, not in charge of it

the model produces a strict intent object. “Only blues” sets a hard ceiling; “mostly blues” expresses a preference. lift prohibitions and soft avoidance are separate fields. unsupported live-condition requests should stop for review, not become invented data.

the user sees the original request and selected settings beside the interpretation. time, max difficulty level and hard lift exclusions can be corrected without another model call. editing constraints invalidates the previous outing. a route is created only after confirmation, and printed/exported itineraries retain the approved constraints and interpretation source.

an independent validator checks returned routes against the supplied graph and constraints. that is not the same as proving the model understood the sentence. for evaluation, I also check routes against the human-reviewed reference interpretation. otherwise a model could drop an exclusion, solve an easier problem, and appear successful.

refuse to invent the mountain

an early terrain audit found 62–107 metre geometry gaps. I retained the failed evidence and switched to native OpenStreetMap node connections rather than snapping nearby endpoints together.

the app now has fictional Pine Mountain and an explicitly unreviewed Alpendorf geometry lab. a bundled MapLibre view and attributed hillshade work without a tile-service account; the SVG sketch remains available for printing and renderer failure. geometry is visual and structural evidence—not proof of permitted boarding, current operations or safe skiing. additional resort snapshots stay in research review, not the selectable routing menu.

let the experiments say “no”

I used Tinker's SDK and the open-source Cookbook's pinned qwen3_disable_thinking renderer. inspecting assistant-only loss masks and target lengths was part of the training preflight. I reviewed the source labels; 47 migrated training examples were retained, excluding an overlapping case.

two real training configurations completed:

Experiment Paired base → trained task successes Decision
First pilot: three full-batch updates, learning rate 1e-4 9/16 → 7/16 Reject tuned candidate
Exploratory follow-up: three epochs, batches 16/16/15, learning rate 3e-5 10/16 → 10/16 Retain base

the follow-up used all 47 examples once per epoch, with nine optimizer updates and no dropped final batch. It gained one case and lost another. both trials used the already-exposed historical pilot, not an untouched final test. the second recipe changed both batching and learning rate, so it cannot isolate either factor's effect.

separately, the retained base previously passed 13/16 tasks on a fresh, human-reviewed, frozen set, with 16/16 schema-valid outputs. those are different cases: 13/16 is not a gain over the pilot's 9/16 or 10/16. the fresh set was same-agent-authored and small, not representative field validation; its labels and outputs were not used as training examples for the follow-up.

the follow-up's two malformed outputs each ended with an extra quote. looking at the complete object underneath still revealed wrong interpretations. simply stripping punctuation would not have fixed those answers. the persistent problems were semantic: omitted exclusions, ignored destinations and unnecessary clarification.

Evaluation overview, paired follow-up evidence, and case-level postmortem retain the failures and denominators.

Why Does Open Innovation Matter?

the useful freedom was being able to inspect and change the language component without replacing the planner or evaluator. Qwen3-8B made a task-specific open-weight fine-tuning experiment possible. the Cookbook exposed how messages become tokens and loss masks, so I could audit exactly what received supervision instead of treating training as a black box.

OpenStreetMap provides another kind of inspectability: a graph segment can be traced back to its source. that comes with attribution and ODbL obligations, not permission to relabel the data as application code.

the result is a project another builder can examine, reproduce and challenge—including the decision not to use its trained models. that matters more to me than a demo that only shows the successful prompts.

I have not demonstrated that this outperforms a closed model, reduces model costs or runs AI inference offline. the planner runs locally; measured model calls ran on Tinker. open components made the experiments inspectable, not automatically better.

foundations: Qwen3-8B, Tinker SDK, Tinker Cookbook, OpenStreetMap, MapLibre GL JS and Mapzen Terrain Tiles. Terrain attribution: © OpenStreetMap contributors. AI coding assistance was used; third-party notices document licenses and attribution.

My Agent Session

I used an openclaw coding agent hosted on a VM I communicate with via a telegram bot to assist me with planning and executing this project.

Prize Categories

Best Use of Tinker — submitted for consideration, alongside the overall Touch Grass challenge.

I used Tinker to fine-tune Qwen3-8B for structured ski-outing intent extraction, with reviewed training examples, audited loss masks, checkpoint/restore handling and paired baseline evaluation. The experiments are reproducible, including their negative results: task success changed from 9/16 to 7/16 in the first trial and 10/16 to 10/16 in the follow-up. Neither trial established an aggregate task-success improvement, and I have not established a latency or cost improvement; the base remains selected.

Top comments (0)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.