107 Commits

Author SHA1 Message Date
itsrubberduck
2d1b9eab75 feat(bridge): map GPS position + true heading into telemetry
Bridge now sends latitude_deg/longitude_deg/heading_deg; map them to
PLANE_LATITUDE/PLANE_LONGITUDE/PLANE_HEADING_DEGREES_TRUE so position and
course land in the telemetry store and surface in /api/bridge/live.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 13:36:30 +02:00
itsrubberduck
4a145844d9 feat(pm): auto-tune radio from SimBridge telemetry via ?token
When /pm is opened with ?token=<bridge-token>, poll /api/bridge/live for
fresh telemetry. While the bridge keeps posting, mirror the sim's COM1
active frequency into the radio (only on actual sim change, so manual/flow
tuning isn't clobbered) and show a "Bridge connected" badge in the HUD.

Telemetry now carries COM_ACTIVE_FREQUENCY/COM_STANDBY_FREQUENCY from the
bridge's com_active_frequency/com_standby_frequency fields.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 12:30:23 +02:00
leubeem
592ec5912c feat(stt): seed Whisper prompt with expected readback + per-field debug UI
Whisper prompt seeding (per request):
- ptt.post.ts builds the prompt as generic ICAO bias + this state's expected
  readback appended LAST (survives the 224-token truncation), in both raw token
  form and spoken ICAO form via new radioSpeech.speakToken().
- pm.vue passes the expected phrase + active variable values; classroom.vue
  passes the lesson's expected field values.

Per-field readback debug:
- sttMatch.matchTranscriptionToFields returns fields[] (matched/missing + which
  view matched) plus normalized/denormalized transcription views.
- useRadioBackend types readback_report on the transmit response.
- pm.vue renders a "Readback check" panel in the right log rail; classroom.vue
  renders per-field rows under the STT panel.

Radio-pronunciation fixes (radioSpeech.ts):
- callsign expander handles multi-letter suffixes (DLH6RK -> Lufthansa six Romeo
  Kilo).
- toRadioSpeech now expands airports (EDDC -> Echo Delta Delta Charlie).
- bare altitudes >=1000 in a clearance context are spoken ("climb initially
  5000" -> "climb initially five thousand feet"); speeds/headings untouched.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 14:12:54 +02:00
leubeem
95b380f5e0 docs: align CLAUDE.md/AGENTS.md/README with the two-repo architecture; drop dead LLM routing
The LLM decision routing moved to the external Python backend
(OpenSquawk-LiveATC-api), but the core docs still described the old in-Nuxt
path (routeDecision(), /api/llm/decide, a Nuxt /api/decision-flows/runtime
route) — none of which exist. Every agent session started with a wrong mental
model.

- Rewrite CLAUDE.md to describe the real /pm flow (useRadioBackend -> Python
  backend owns authoritative state; Nuxt owns STT/TTS/audio/auth/editor) and
  fix stale commands (bun -> yarn).
- Fix the two stale AGENTS.md lines (openai.ts is getOpenAIClient() only;
  decisionFlowService is editor-only, no Nuxt runtime route).
- README: note the Python backend is required for /pm; correct server/ desc.
- Remove dead shared/utils/openaiDecision.ts (called the non-existent
  /api/llm/decide) and the now-orphaned LLM decision contract types in
  shared/types/llm.ts. Trace types used by pm.vue are kept.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 14:46:57 +02:00
leubeem
f8fdd8bc79 feat(server): per-user AI usage tracking, cost alerting, and endpoint hardening
Usage tracking:
- new UsageEvent collection records every STT/TTS/LLM call per user with
  provider, model, volume (audio seconds, characters, tokens) and an
  estimated USD cost; self-hosted providers (Speaches/Piper) and cache
  hits record at $0
- pricing table for whisper-1, tts-1, gpt-5-nano & co. in server/utils/usage.ts
- weekly KPI mail gains an "AI-Nutzung & Kosten" section: weekly and
  rolling 30-day cost, per-kind breakdown, top 5 users by cost
- quota alert mail when rolling 30-day cost exceeds USAGE_ALERT_USD
  (default $5), at most once per calendar month (UsageAlertDelivery)

Hardening:
- /api/atc/say now requires an authenticated session (middleware
  exemption removed); useFlightLabAudio sends the bearer token
- /api/service/tools/latency requires auth (was a public LLM endpoint)
- per-user rate limits: PTT 20/min, say 60/min, latency 5/min
- cron endpoints (waitlist-drip, weekly-kpi-report) require a shared
  secret via ?secret= or x-cron-secret (CRON_SECRET, falls back to
  KPI_CRON_SECRET); allowed with a warning while unset so existing
  deployments keep working
- PTT records the actual transcribed audio duration for billing accuracy

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 23:17:03 +02:00
leubeem
1f4fed6955 feat(pm): live ATIS broadcast loop with METAR-slot refresh and multi-station support
- per-airport ATIS loop keyed by station with a virtual start epoch, so
  re-tuning resumes where the broadcast would be instead of restarting
- refetch airport data at :23/:53 to follow VATSIM ATIS regeneration from
  real-world METAR publication, with faster retries while no ATIS is on
  the feed; prefetch audio when the info letter changes
- support separate arrival/departure ATIS stations on different frequencies
- cancel the deferred audio teardown on retune so a fresh broadcast is not
  killed by the previous stop()'s fade-out timer (atisAudioLoop)
- comm log shows newest entries first

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 23:10:35 +02:00
leubeem
d758873f55 fix(radio): speak SID names and waypoints as words, expand more ATIS elements
- SID basenames and 5-letter waypoints (ANEKI 7S, SULUS) are pronounceable
  by design and are now spoken as words instead of letter-by-letter phonetics
- skip acronyms (ATIS, RNAV, MAIN, ...) when spelling 4-letter ICAO codes
- expand stand/gate designators, ATIS information letter, and surface wind
  groups for TTS
- normalizeATCText now runs full client-side radiotelephony expansion
  (callsigns, airports) since preNormalized texts skip the server normalizer

Note: tests/radioSpeech "normalizes SID suffix and METAR data" still expects
the old spelled-out SID behavior and fails until updated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 23:10:22 +02:00
leubeem
75533d6771 feat: scenario picker, flow chaining UX, reliable frequency checks
Scenario picker & completion:
- Login → scenario selection screen with complete chains + individual phases
- Completion screen with "fly again / try opposite / back to scenarios"
- Scenario.airport ('dep'|'arr') drives which airport frequencies to fetch;
  arrival scenarios (vfr-arrival, circuit-landing, taxi-in) use arr ICAO

Backend session integration:
- createSession forwards no_chain; response carries active_flow + session_complete
- Pass all six airport frequency variables to session so every chained flow
  has the real airport values from creation
- fetchAirportFrequencies now runs before session creation so resolved
  frequencies are included in backendVariables

Wrong-frequency check:
- airportFreqMap computed (from airportFrequencies, always up-to-date)
  used as primary source in expectedFrequencyForState — immune to flow
  snapshot switches
- setActiveFlow called when response.active_flow changes so local engine
  cursor moves to the correct flow's states after a chain
- Wrong-freq ATC reply appended to communication log (offSchema entry)

Engine fixes (communicationsEngine.ts):
- patchVariables / patchFlags: write directly to the internal reactive
  store, bypassing readonly(ref) which silently blocked all (vars as any)
  .value[k] = v mutations
- appendLogEntry: push ATC speech (and wrong-freq replies) into comm log
- ATC controller_say_rendered appended to comm log after every transmission
2026-06-08 13:03:55 +02:00
itsrubberduck
f894eb4928 feat(atis): inline METAR expansion, airport name lookup, acronym fix
ATIS text often arrives in raw METAR form (e.g.
"METAR EDDF 281050Z AUTO 02008KT 320V070 CAVOK 24/02 Q1025 NOSIG"),
which TTS reads as letter-by-letter spelling. The normalizer now expands
the full WMO Code Form FM 15-XV vocabulary inline: DDHHMMZ date stamps,
compressed wind (with gusts, VRB, calm), wind variability ranges, RVR
(R25L/1500N), wind shear, slash-form temp/dewpoint, Q/A pressure,
NSC/SKC/CLR/NCD/VV cloud codes, weather phenomena (with intensity and
descriptors), recent-weather RE prefix, BECMG/TEMPO/FM/TL/AT trend
codes, and strips RMK remarks. Plus ATIS/METAR/SPECI get lowercased
so TTS pronounces them as words (pilots SPELL ILS/QNH/VOR so those
stay uppercase).

Airport ICAO codes are substituted with their OpenAIP name when the
frequencies endpoint returns one. New `airportName` field added to
the FrequencyResponse for that. Adds 7 test cases covering the user-
reported EDDF sample plus calm/VRB/gust winds, RVR, weather codes,
cloud specials, trend codes, and RMK stripping.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 13:45:15 +02:00
itsrubberduck
a9a391c301 feat(atis): carrier-noise bed and Web-Audio loop seek
Tuning to the ATIS frequency now plays carrier noise immediately so the
pilot gets feedback before the TTS comes back (synthesis takes a moment
on cold cache). When the ATIS audio is ready, the carrier ducks down to
a subtle bed level and stays underneath the announcement — mimicking
how a real radio channel always carries some noise floor.

Switches the loop from HTMLAudioElement (whose seek on data: URLs gets
quantized by some browsers) to a Web-Audio AudioBufferSourceNode.
`source.start(0, offset)` is sample-accurate per spec, so the
virtual-clock entry point lands exactly where computed. `window.__atisDebug`
exposes ctx/source/state for manual inspection, and pm.vue logs the
requestedOffset/duration/epochAge on each loop start.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 09:24:31 +02:00
itsrubberduck
c165167d6b feat(atis): ICAO phraseology normalizer for spoken ATIS
The ATIS loop sent raw VATSIM `text_atis` to TTS, producing "Q-N-H one
thousand twenty-four", "WIND oh thirty degrees", "RUNWAY oh eight L".
New `normalizeAtisForSpeech` applies ATIS-specific transforms — info
letter → phonetic alphabet, wind/temperature/time digit-by-digit, TRL
expansion, NOSIG → "no significant change", cloud layers (BKN030 →
broken three thousand), visibility, bare runway designators — then
hands off to `normalizeRadioPhrase` for QNH/RWY/FL/freq. pm.vue calls
the normalizer before posting to /api/atc/say so the disk cache keys
the spoken form. Adds 4 test cases covering a full real-world EDDM
broadcast plus edge cases (cloud layers, negative temperatures, km/m
visibility).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 09:09:12 +02:00
itsrubberduck
ac6618e347 Make callsign STT matching far more tolerant
Whisper routinely garbles the airline portion of a callsign while
nailing the flight number ("Loftansa three five niner", "Speed bird
27", "Lufthana 359"). Previously these slipped past the matcher.

Two changes:

1) Whole-string fuzzy distance for callsigns bumped to allowedDistance
   + 3 (was +1), which covers ~1–2 character substitutions in the
   airline name.

2) New `callsignMatches()` splits each candidate into its alphabetic
   airline prefix and trailing digit run and matches each part
   independently:
   - The digits (e.g. "359") are the strong anchor and must appear.
   - The airline portion is matched both verbatim and with whitespace
     stripped ("Speed bird" → "speedbird"), with a generous ~25%
     character-distance allowance.
   - Bare flight number without any airline trigger does NOT match —
     verified by a dedicated false-positive test.

7 new test cases cover the realistic Whisper error modes (misspell,
split words, ICAO letter readout, reordered words, telephony glue).
All 69 tests green.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 21:26:54 +02:00
itsrubberduck
3b64908461 Make classroom STT production-ready
Last pass fixed the crashes but the UX wasn't trustworthy — you'd hit
the mic, something happened, fields silently changed, and there was no
clear way to see what Whisper actually heard or which fields it touched.
This rebuilds that flow:

UI
- Dedicated transcription panel below the controls row replaces the
  single-line "Heard:" hint. Has explicit states: recording (red,
  pulsing dot, live MM:SS timer), transcribing (spinner), result
  (editable textarea + summary chip), or error (red body text).
- Mic button label shows the elapsed recording time so the pilot knows
  recording is actually running.
- Per-field mic icon appears on every blank that was filled by the
  current transcription, so it's obvious what came from speech vs.
  what was typed.
- Result panel exposes three explicit actions: Apply to fields (re-runs
  the mapping after edits), Record again, Dismiss.
- Hard auto-stop at 45s (well under the server's 2 MB / ~60s cap).
- 503/unreachable responses from the PTT endpoint now flip
  `sttServerAvailable` so the mic button gracefully hides itself.

Matching reliability (shared/utils/sttMatch.ts)
- Process fields longest-expected-first so a 6-char callsign claims its
  substring before a 1-char digit field grabs an overlapping character.
- Short candidates (<3 chars) now require a whole-word boundary match,
  so the digit "5" in callsign "359" no longer auto-fills an unrelated
  readability field.
- Two new test cases cover both false-positive guards.

62 / 62 tests green, vue-tsc clean, dev server starts and serves the
classroom page without TDZ / hydration warnings in the log.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 21:24:41 +02:00
itsrubberduck
4a12719395 Fix STT readback — TDZ crash, spoken-form mismatch, hydration
Three bugs in yesterday's STT addition:

1) **TDZ crash** — `sttSupported` referenced `isClient` before its const
   declaration, throwing on setup and breaking the whole classroom page.
   `sttSupported` is now a ref that's populated in `onMounted`.

2) **Spoken vs. written mismatch** — Whisper returns natural ATC speech
   ("runway two five right", "lufthansa three five niner"), but the
   lesson fields hold the canonical written form ("25R", "DLH359"). The
   old `normalized.includes(...)` check never matched. Matching now lives
   in `shared/utils/sttMatch.ts` and searches both the raw normalized
   transcription *and* a denormalized projection that folds spoken
   digits/letters back to written tokens (incl. SID suffix `7S`, runway
   `25R`, scale words `five thousand → 5000`, frequency `decimal` as a
   digit-run boundary).

3) **SSR hydration mismatch** — `sttSupported` evaluated differently on
   server vs. client, causing visible-vs-hidden button divergence on
   hydration. The ref-set-on-mount approach resolves it.

The new helper is fully unit-tested (15 cases covering radio check,
departure clearance, SIDs, squawks, Speedbird telephony, decimal
frequencies and edge cases).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 21:18:39 +02:00
itsrubberduck
0b386e873a Address classroom tester feedback (Detlef / FSC e.V.)
Fixes the most impactful issues from ~1.5h of testing:

- TTS: spell SID prefixes phonetically (ANEKI → Alfa November Echo Kilo
  India) so unfamiliar waypoint names are intelligible without prior
  briefing context.
- TTS: expand standalone uppercase waypoints after via/direct (with a
  skip list for common ATC English tokens like MAYDAY, CLEARED, …).
- TTS: join taxi route tokens with ", " so pauses land between
  taxiways (C5, Z5, U10, …) instead of running together.
- TTS: handle "ILS Z 25C" variant before the runway → "ILS Zulu runway
  two five center" (was previously read as "Zee twentyfive cee").
- Scenarios: derive arrivalRunway from the chosen approach so the
  controller no longer clears a flight for ILS 25C onto runway 18.
- Radio check: accept any readability 1–5 (numeric or spoken), shorten
  placeholder so it fits the sm-width field.
- Line-up readback: clearer hint about the runway-first ICAO order.
- Classroom UI: disable browser autocomplete/autocorrect on readback
  inputs (Edge autofill was injecting unrelated values).
- Classroom UI: "Speak answer" button replays the expected readback as
  TTS so students can hear the correct phrasing.

Tests adjusted for the new SID and taxi-route phonetics.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 10:24:48 +02:00
leubeem
2069663f01 feat: wire Python backend session to PTT, add pm.vue debug logger
- Pass  as top-level field in PTT requests so Whisper STT
  results are linked to the correct Python backend session
- Add namespaced  helper in pm.vue (info/warn/error/debug/group)
  controlled by localStorage PM_DEBUG flag; logs transmit/response
  cycles, TTS calls, flag/variable syncs, and fallback warnings
- Log backend session creation context (flow, start state, vars, flags)
  in startMonitoring
- Fix typo in text input hint: STT fails not PTT fails

and

fix: sync backend variables to frontend after each transmission

The ATC say template was rendered using the frontend engine's local
variable defaults (squawk '1234', hardcoded SID, etc.) instead of
the authoritative values from the Python backend session. This caused
the spoken clearance and the readback prompt to show different squawk
codes.

- After each backend transmission response, sync all response.variables
  into vars.value (same pattern already used for flags)
- Prefer controller_say_rendered (pre-rendered by backend) over the raw
  template for TTS scheduling, eliminating any remaining dependency on
  local variable state for the ATC speech text
2026-05-20 16:44:01 +02:00
itsrubberduck
f721fd1536 copilot 2026-05-19 12:46:31 +02:00
leubeem
9464d37293 Wire /pm to Python backend for stateful ATC training sessions
Replace the LLM-per-request flow in /pm with a stateful Python backend
(OpenSquawk-LiveATC-api). The backend owns session state, does regex-first
routing with readback evaluation, and returns the next state + ATC speech.
The frontend keeps its local cursor (communicationsEngine) for TTS and
monitoring UI, but no longer calls /api/llm/decide.

Changes:

app/composables/useRadioBackend.ts (new)
  Typed Nuxt composable wrapping the Python REST API:
  createSession, transmit, deleteSession, fetchFlows.
  Base URL read from NUXT_PUBLIC_RADIO_BACKEND_URL (default 127.0.0.1:8000).

nuxt.config.ts
  Expose radioBackendUrl as a public runtime config key so the composable
  and communicationsEngine can both reach the Python backend.

shared/utils/communicationsEngine.ts
  - fetchRuntimeTree now accepts an optional baseUrl so it fetches from the
    Python backend instead of the Nuxt server when a URL is provided.
  - renderTpl handles both {var} (old MongoDB schema) and {{var}} (new YAML
    schema) — double-brace matched first to avoid partial matches.
  - stateSayTpl / stateUtteranceTpl helpers unify say_tpl|say_template and
    utterance_tpl|expected_pilot_template across both schema versions.
  - auto_transitions from the new YAML schema are included when collecting
    eligible transitions in collectAtcStatesUntilPilotTurn.

shared/types/decision.ts
  RuntimeDecisionState extended with say_template and expected_pilot_template
  fields (new YAML schema field names alongside the existing legacy names).

app/pages/pm.vue
  - startMonitoring: loads tree from Python backend, then creates a backend
    session (backendSessionId). Cursor synced to session.current_state.
  - handlePilotTransmission: calls radioBackend.transmit instead of
    /api/llm/decide. Applies auto_advanced_states via moveToSilent, then
    the final state. Speaks controller_say_template via TTS.
  - Both fetchRuntimeTree calls now pass radioBackendUrl so they hit the
    Python backend, not the Nuxt flow-from-MongoDB path.

AGENTS.md (new)
  Project guide updated to document the new two-backend architecture,
  the Python backend session lifecycle, and the dual template schema.

docs/plans/2026-05-06-pm-python-runtime-contract.md (new)
  Implementation plan and API contract written before the work started.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 17:49:28 +02:00
itsrubberduck
ae3dab6f9d komplette 320 sops 2026-05-06 15:51:58 +02:00
itsrubberduck
20358eea6c redeisng to match osq 2026-04-25 20:52:25 +02:00
itsrubberduck
bbcd9dca54 first version looks ok 2026-04-25 20:29:09 +02:00
itsrubberduck
e792b09671 feat: update classroom feedback round 2 content 2026-02-27 13:03:04 +01:00
itsrubberduck
f5509d9fce claude hat das pfd sehr krass ueberarbeitet 2026-02-21 18:04:37 +01:00
itsrubberduck
febe4d907a feat(pfd): realistic styling, flight inertia, and improved training exercises
- Darken all tape backgrounds to match real A320 PFD (#16181f/#1c1e26)
- Speed/altitude readouts green (#19e34a) instead of cyan
- Attitude indicator: sky/ground gradients, W-shaped aircraft symbol
- Speed tape: cyan target zone (not red), VFE/min-speed red bands
- Altitude tape: ticks on left side toward attitude indicator
- Flight physics: 3x slower pitch (smoothed, tau 2s), halved roll rate,
  stronger speed-pitch coupling for realistic 150t inertia
- Pitch/bank exercises use normal flight ranges (±10° bank, ±3-4° pitch)
- Multi-phase speed exercise: explain → coarse hold 5s → fine hold 8s
- ATC messages emphasize small inputs, patience, and anticipation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 15:45:39 +01:00
itsrubberduck
06f277e3ee feat(learn-pfd): add pitch-based speed hold step and target speed zones 2026-02-21 00:08:16 +01:00
itsrubberduck
b83ccf2c7c engine thr mehr respektieren 2026-02-20 23:55:45 +01:00
itsrubberduck
ef8f1a1991 feat(engine): add learn-pfd engine composable with goal evaluation
Composable manages phase navigation, interaction goal monitoring with
hold-time validation, progress tracking, and hint system for the
learn-pfd medienstation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 23:01:16 +01:00
itsrubberduck
636f7f7e12 feat(data): add learn-pfd scenario phases with progressive PFD element introduction
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 18:33:15 +01:00
itsrubberduck
c4c841a2c1 feat(ws): add stick-input WebSocket message handler and client support
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 18:30:26 +01:00
itsrubberduck
4e74b74255 feat(fbw): add Airbus Normal Law FBW physics composable
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 18:30:16 +01:00
itsrubberduck
3f28abae1f feat(types): add LearnPfdPhase, PFD element types, and stick-input WS event
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 18:29:01 +01:00
itsrubberduck
352ad8d68e feat(flightlab): simplify takeoff flow and wait for TTS before auto-advance 2026-02-19 00:04:21 +01:00
itsrubberduck
d40259d03c manuelle anpassungen an der config 2026-02-18 23:19:37 +01:00
itsrubberduck
f384e30b9b feat(flightlab): add seatbelt phases to stepper and escape shortcuts 2026-02-18 22:52:23 +01:00
itsrubberduck
390c38d8bd Bridge dome light mode mapping and flightlab seat belt flow 2026-02-18 22:43:56 +01:00
itsrubberduck
5915479c1a hoehen anpassen damit alles etwas ruhiger wird 2026-02-18 19:35:07 +01:00
itsrubberduck
c605705a38 change default settings 2026-02-18 18:05:12 +01:00
itsrubberduck
f88fced5b1 typescript 2026-02-17 18:19:55 +01:00
itsrubberduck
8f45c3397d fix typescript errors and update dependencies 2026-02-17 18:13:04 +01:00
itsrubberduck
3d5a18df6a use 6 digit codes for bridge 2026-02-16 15:47:12 +01:00
itsrubberduck
36f5a72c66 fix(flightlab): prevent overlapping takeoff voices on rapid phase changes 2026-02-15 18:05:11 +01:00
itsrubberduck
bb73b43a89 refactor(flightlab): rewrite takeoff texts for simulator context and auto-stop sounds on phase change
Rewrote all takeoff scenario texts from passive fear-of-flying coaching
to active simulator operation instructions (thrust levers, sidestick,
rudder pedals, gear lever, instrument readings). Stop looping ambient
sounds automatically when transitioning to phases that don't reference them.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 16:50:04 +01:00
itsrubberduck
7a1f35bc90 refactor(flightlab): remove instructor flow and simplify takeoff controls 2026-02-15 16:32:20 +01:00
itsrubberduck
5a25e212d7 fix(classroom): audio speed slider now actually changes playback speed with pitch correction
- Fix client: playbackRate was set to 1 for non-native-speed providers (Speaches/Piper),
  making the speed slider ineffective in the main Pizzicato audio path
- Fix server: pass speed parameter to Speaches TTS API
- Add pitch-preserving playback via MediaElementSourceNode when rate != 1,
  routing through the same Web Audio effects chain (radio filters, distortion, etc.)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 01:01:02 +01:00
itsrubberduck
ea51e1dcc3 feat(classroom): integrate user feedback — audio speed, METAR TTS, phonetics, UI fixes
- Lower default audio speed to 0.85x, extend slider range to 0.5-1.3x
- Add METAR normalization for intelligible TTS (wind, vis, clouds, temp, QNH)
- Expand SID/STAR suffix regex to handle spaces (SUGOL 2S)
- Add approach suffix phonetic expansion (ILS 08R Y → Yankee)
- Fix "Soll:" → "Expected:" in readback feedback
- Accept numeric values for pushback delay field
- Add news article documenting the changes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 14:21:35 +01:00
itsrubberduck
77ecd49334 feat(flightlab): sidebar, progress bars, skip speech, SimBridge telemetry & auth
- Add collapsible sidebar with phase stepper (jump between phases)
- Add SimBridge conditions panel in sidebar (live values, progress bars, targets)
- Add global progress bar (top edge, glowing) + phase-local TTS progress bar
- Add skip button to skip TTS speech while ATC is speaking
- Add skipSpeech() to audio composable (stops current Pizzicato sound)
- Wire up bridge data.post.ts with user auth (JWT) + example payload
- Add server-side telemetry store with pub/sub for Bridge→WS relay
- Extend WS handler with subscribe-telemetry message + userId tracking
- Extend sync composable with subscribeTelemetry() + onTelemetry() callback
- Add require-auth middleware to all flightlab pages
- Fix instructor station ECONNREFUSED via import.meta.client guard
- Add animations: phase transitions, button lists, fade-scale, check-pop, pulse

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 10:14:33 +01:00
itsrubberduck
2efa24f7f5 umalute fixen 2026-02-13 18:49:56 +01:00
itsrubberduck
a915af4398 dont log users id on transmission 2026-02-13 18:44:34 +01:00
itsrubberduck
25378db177 fix(flightlab): resolve TypeScript strict null checks in engine composable
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:01:05 +01:00
itsrubberduck
9923cbbd5d feat(flightlab): add WebSocket sync composable for instructor-participant sessions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 14:45:45 +01:00