Elyra
Elyra The coding agent eTerm The terminal that knows where each command ends Huskarl AI colleagues on your own Mac Starf An activity monitor for Apple silicon that never invents a number etrans An SSH and SFTP client for macOS Elyra VM Virtual machines for macOS, Linux and Windows on your Mac Litr A small, native web browser for macOS Notr A notebook for macOS e The native code editor Elyra Grove Native local development environment Askr The real server for Laravel & PHP Elyra Framework Rust + Svelte 5 framework for desktop apps Elyra Conductor Local project conductor Refr Local-first PDF workspace for macOS Elyra Workspace A desktop workspace for coding agents Elyra SQL Server MySQL-compatible SQL server in Rust Elyra Félagi Agents as teammates on one board Elyra SQL Client Native desktop SQL workbench Elyra SQL Anywhere Replication-ready SQL engine Elyra Sjá SEO & GEO workspace for macOS Elyra DataGrid Server-driven data grid for Laravel
Release notes
Changelog
Elyra

Microphone

Speak instead of type. The button records in the shell, not the page, and hands back what was said as text, through the app's server (RFC 0032).

Examples
<script>
  import { Field, Microphone, Textarea } from "@elyra/ui";

  let notes = $state("");
  const add = (text) => (notes = notes ? `${notes} ${text}` : text);
</script>

<Field label="Notes" description="Type, or dictate.">
  <Textarea bind:value={notes} rows={3} />
</Field>
<Microphone language="en" ontext={add} />
  • A click starts recording, and the next one stops it.
  • Space or Enter held past 300 ms records until let go: push-to-talk. A shorter press works like a click.
  • Esc while recording throws the recording away.
  • ontext(text) gets what was said, once it's transcribed. Nothing is sent for silence.
  • onrecorded(file) gets the recording itself, a ChosenFile (a 16 kHz mono WAV), before it's transcribed. With transcribe={false} it stops there: attach it to a record, or queue it in the outbox, like a file the user chose.
  • language tells the model what's spoken ("no", "en"). Without it, the model guesses.
  • maxSeconds stops a recording sooner than the app's longest (300 seconds unless App::microphone_max_seconds says less).

The app needs App::microphone(why) and elyra's microphone feature, and Backend::transcription() for the text:

App::new()
    .microphone("Notes uses the microphone to let you dictate.")
    .backend(Backend::new(url).transcription())

why is what macOS shows when it asks the user. rata bundle writes it in the .app. On the server, Route::elyraTranscription() adds the key (docs/backend.md).

Words

Every word the button shows or says is in labels, English by default:

<script>
  import { Microphone } from "@elyra/ui";

  let said = $state("");
</script>

<Microphone
  language="no"
  labels={{
    button: "Dikter",
    recording: "Tar opp",
    transcribing: "Skriver ut…",
    hint: "Klikk, eller hold mellomrom, for å snakke",
  }}
  ontext={(text) => (said = text)}
/>
<p>{said}</p>
Label Default Where
button "Dictate" The button's name.
recording "Recording" Said, and shown, while it records.
transcribing "Transcribing…" Said, and shown, while it transcribes.
hint "Click, or hold Space, to talk" The button's tooltip.

Accessibility

  • It's a toggle button: aria-pressed while it records, with a name that stays the same (labels.button).
  • What it's doing is said in a polite live region ("Recording", "Transcribing…"). A failure, such as the user not allowing the microphone, is a role="alert".
  • A recording of only silence, which is what macOS gives an app it doesn't let listen, is that alert too, saying where to allow the microphone.
  • While it transcribes, it's busy (aria-busy) and can't be pressed.
  • The level meter is decoration (aria-hidden). With less motion asked for, it stands still while it records.
  • Taken off the page while recording, it cancels the recording.

API

Microphone

Prop Type Default Description
transcribe boolean true Turn the recording into text, for ontext.
language string — What's spoken: "no", "en".
maxSeconds number — Stop by itself after this long.
disabled boolean false
labels object {} Its words: button, recording, transcribing, hint.
ontext (text) => void — Told what was said.
onrecorded (file) => void — Told the recording, a ChosenFile.
class string "" Added to the outer element.

Other attributes go to the button.