Fujimod
브라우저에서 카메라 펌웨어를 시험하고 Fujimod SD 부팅 파일을 만든다
저장소 정보는 아직 수집하지 않았습니다.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
AI trip planner that only suggests real places: every stop checked on OpenStreetMap, with a map, stays, packing, budget and an on-device journal.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗An AI trip planner that can't make places up. Describe a trip in a sentence and Natour plans it day by day on a map, looking every suggested place up on OpenStreetMap and dropping the ones that don't exist. Drag stops between days, lock favourites, ask for a rainy-day version, compare neighbourhoods to stay in, pack from real climate averages, rough out a budget, and keep a journal afterwards that never leaves your device. No account needed.
natour.ewstudios.workers.dev · The shared API
Natour started in 2021 as three CSS exercises from the same course: natour, a tour-booking landing page whose form went nowhere; Trillo, a hotel page with made-up reviews and "only 4 rooms left"; and Nexter, a homes page that survived only as built files. None of it did anything. What was worth keeping was the travel idea, natour's Easy / Medium / Hard tours, and "where to stay".
So those became a planner. The tours' difficulty is now how much walking a day takes. "Where to stay" became a comparison of three neighbourhoods measured against your own stops. And the fake reviews and scarcity went the other way: Natour shows nothing invented as fact. The AI writes the plan, but every place it names is looked up on OpenStreetMap inside your destination before it reaches you, and a stamp with its coordinates proves it.
| From | What Natour takes |
|---|---|
| Wanderlog | A day-by-day plan on a map, with drag to reorder |
| Mindtrip / Layla | Plan from a sentence, here with every place checked |
| TripIt | Everything for one trip in one place: plan, stay, packing, budget |
| Roadtrippers | Walking times between stops, and "add a stop on the way" |
| Polarsteps | A journal after the trip, with the route drawn |
| Google Travel | The best months to visit, here from 25 years of NASA climate averages |
flowchart LR
S([A sentence]) --> AI[AI planner<br/>destination, then stops]
AI --> D{Destination found<br/>on OpenStreetMap?}
D --> B[its bounding box]
AI --> C{Each stop inside<br/>that box?}
B --> C
C -- no --> X[dropped<br/>and counted]
C -- yes --> P[Day columns + map<br/>stamp with coordinates]
P --> W[Walking times<br/>Easy / Medium / Hard]
P --> R[Lock · new ideas · rainy day<br/>stop on the way]
R --> AI
P --> T[Stay · Pack · Budget]
P --> J[(Journal<br/>on your device)]
| <img src="docs/list.png" alt="The same trip in List view: Day 1 as plain text, each stop numbered with its type, time there, OpenStreetMap address and reason, and "Then walk ~8 min (0.7 km)" lines between stops, next to the map"> | |
| The planner. Every stop carries a stamp with its coordinates; the place's spelling is OpenStreetMap's. Drag stops between days (keyboard too), lock favourites, ask for new ideas or a stop on the way. | List view. The accessible view of the map: every day in words, with estimated walks between stops. |
| A rainy-day version. Indoor and covered places near the planned ones, a tap to switch back. | Where to stay. Three areas compared by the AI; the walking times to your stops are measured by the app. Plain search links, no prices or reviews. |
| Pack. A list from the month's climate averages, the trip's activities and its length. Ticks stay on the device. | Budget. A rough estimate you can edit, in your currency, totalled for the group and the trip. |
| <img src="docs/explore.png" alt="Explore at night: the title "Somewhere worth the walk.", a search box for any city, six miniature-diorama mood tiles (coast, mountains, old towns, desert, forest, night cities) with a note that they are illustrations, and a numbered list of destinations with coordinates"> | |
| Destination guides. A real photo with credit, Wikivoyage's introduction (CC BY-SA, linked) and the best months from NASA climate averages. | Explore. Start from a feeling; any other city works through search. |
| The journal. Notes and photos per day, beside the route you walked. Stored in IndexedDB only. | Night theme. Both themes pass WCAG AA on every page, checked by axe in CI. |
| The landing. One dotted route drawn through four chapters as you scroll: Dream, Plan, Go, Remember. |
flowchart TB
subgraph Browser
R[TanStack Router<br/>lazy routes] --> L[Landing<br/>magazine cover, one scroll-drawn route]
R --> SH[App shell]
SH --> TR[Trips]
SH --> PL[Planner<br/>dnd-kit columns + list view]
SH --> ST[Stay] & PK[Pack] & BU[Budget]
SH --> EX[Explore + guides]
SH --> JO[Journal]
PL & ST --> MAP[MapLibre GL<br/>OpenFreeMap tiles]
PL & ST & PK & BU --> JOBS[trips.ts jobs<br/>stream → check → write]
JOBS <--> DX[(Dexie / IndexedDB<br/>trips, journal)]
TR & PL & JO -. live queries .-> DX
end
JOBS --> P{AI provider<br/>chosen in Settings}
P -->|default| EW[ew-apps-api<br/>/api/ai/natour/:action]
P --> PU[Puter.js] & OR[OpenRouter PKCE] & OWN[Own key]
EW --> G[Gemini Flash-Lite<br/>free tier]
JOBS & EX --> PLC[ew-apps-api /api/places/*<br/>search · guide · climate]
PLC --> NOM[Nominatim<br/>1 request/s, shared, cached a week]
PLC --> WV[Wikivoyage]
PLC --> NASA[NASA POWER<br/>climatology]
EX --> UN[ew-apps-api /api/photos<br/>Unsplash]
One plan, from a sentence to stamped stops:
sequenceDiagram
participant U as You
participant J as startPlan()
participant A as AI provider
participant N as /api/places/search
participant D as IndexedDB
U->>J: "3 days in Lisbon in May: food, viewpoints…"
J->>D: new trip (the planner opens at once)
J->>A: plan {description, days, effort}
A-->>J: {"destination": "Lisbon", "country": "Portugal", …}
J->>N: "Lisbon, Portugal"
N-->>J: centre + bounding box
loop each stop line as it streams
A-->>J: {day, name, kind, minutes, why}
J->>N: name, inside the box (one at a time)
alt a result whose name matches and isn't a bus stop or a road
J->>D: stop with OSM's spelling and coordinates
else nothing real
J->>D: dropped + 1
end
end
D-->>U: live query: stops and stamps appear one by one
Nominatim allows one request a second for the whole app, so the API keeps one clock for everybody:
flowchart LR
B[Browsers] --> R[/api/places/search/]
R --> C{In the cache?<br/>a week}
C -- yes --> B
C -- no --> F{Same search<br/>already in flight?}
F -- yes --> W[share its answer]
F -- no --> Q{Next free second<br/>within 20 s?}
Q -- yes --> N[Nominatim] --> C
Q -- no --> E[503 places_busy<br/>the app retries once]
src/lib/check.ts decides. Each name is searched on Nominatim inside the destination's bounding box, and a result counts only if at least half the suggested name's words (accents, punctuation and filler words like "de" or "the" removed) are in its OpenStreetMap name, and it isn't a bus stop, a platform or a road named after the place. The stop then takes OpenStreetMap's spelling and coordinates. On the recorded Gemini plan for Lisbon (the one in the screenshots), one suggestion wasn't on the map and was dropped, and every other stop took OpenStreetMap's name and coordinates. If our server can't check (offline, or Nominatim busy), the stop is kept but marked "not checked" and gets no pin, instead of failing the plan.src/lib/trips.ts that stream the AI's JSON lines, check each place and write into IndexedDB as they go. Pages only watch the trip with a live query, so you can switch tabs while a plan fills in, and two tabs show the same progress. A job interrupted by closing the tab is cleared with a note on the next visit.The same credits are in the app's footer, on the map, next to each guide and photo, and on the Terms page.
| Version | Concept | Why it changed |
|---|---|---|
| v1 (2021) | Three CSS course exercises: a React 17 tour landing page (natour), a hotel page (Trillo), a homes page (Nexter) | No logic, forms that went nowhere, fake reviews and scarcity |
| v2 (Oct 2026) | An AI trip planner whose every place is checked on OpenStreetMap, with stays, packing, budget and a journal | Live |
Built in conversation with Claude Code, which wrote and tested the code. The design direction came from Awwwards references (Hedwig, The Explora Journal, EXOLAUNCH Orbit Explorer, Dérive, Mammut Local Adventure; see docs/design-brief.md). The art and clips were generated in Google Flow (Nano Banana Pro and Omni 1.1 Flash); docs/assets.md lists every prompt. The logo and icons are SVG. The screenshots show real OpenStreetMap lookups, real Wikivoyage, NASA and Unsplash data, and real Gemini answers to the server's own prompts.
npm install
npm run dev
npm test
npm run e2e
Node 24. Copy .env.example to .env and point VITE_API_URL at a running ew-apps-api: it carries the place checks, guides, climate, photos and the free AI option. Without an AI provider you can still start an empty trip and add places yourself. npm run build also prerenders the public pages, so it needs Playwright's Chromium (npx playwright install chromium). npm run e2e answers every place lookup, guide, climate call, map tile and AI request inside the test, so it needs no keys or network; it covers describe → plan (with a made-up place dropped) → reorder by menu and by keyboard drag → list view, packing, budget maths, stays, the journal, explore, and axe on every page in both themes. CI adds lint, typecheck, unit tests and Lighthouse (≥ 0.95 in every category). Deploy with VITE_API_URL=https://ewandtina-d9aa187632ca.herokuapp.com npm run build && npx wrangler deploy (config in wrangler.jsonc).
node scripts/screenshots.mjs retakes the pictures in docs/ against a served build, with real place data from a local API and the recorded Gemini answers in scripts/screenshot-fixtures.json.
src/
├─ main.tsx router.load(), then hydrate or render
├─ router.tsx every route, lazily loaded
├─ index.css design tokens for paper and night, fonts, graticule, stamps
├─ ai/ actions + templates, providers, JSON Lines, PKCE, Supabase sign-in
├─ lib/ trips (AI jobs), check (is it real?), geo (walking times), budget, climate,
│ api (places, guides, photos), destinations, Dexie
├─ landing/ cover, stamp window, postcard strip, landscape, journal spread, motion, route
├─ components/ shells, trip frame, MapLibre map, stamps, route sketches, effort bar
└─ pages/ Landing, Trips, Planner, Stay, Pack, Budget, Explore, Destination, Journal,
Settings, Developer, Pro, Legal, 404
scripts/
├─ prerender.mjs static HTML for the public pages
├─ contours.mjs bakes the cover's topographic lines
└─ screenshots.mjs the README pictures
e2e/ Playwright flows with mocked place, map and AI hosts, and axe checks
docs/ brief, design brief, data terms, asset list, screenshots
Made with ♥ by EWSTUDIOS
| 404. Off the map. |
stroke-dashoffset behind an SVG mask (no Club plugins), and our own word splitting. The contour lines are traced once from seeded noise by scripts/contours.mjs (18 kB gzipped) and loaded after first paint, so the cover's largest element is text. Phones get their own vertical layout, and with reduced motion every stamp is already down and the route is fully drawn. Mobile Lighthouse: 0.96–0.98 performance, 1.0 everywhere else. The design notes are in docs/landing-redesign.md.