<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: C W</title>
    <description>The latest articles on DEV Community by C W (@moersebene).</description>
    <link>https://dev.to/moersebene</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4021314%2F03f47fcf-d610-4210-b273-e848d38d27fc.png</url>
      <title>DEV Community: C W</title>
      <link>https://dev.to/moersebene</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/moersebene"/>
    <language>en</language>
    <item>
      <title>Dōjō 道場 — karate made me do it.</title>
      <dc:creator>C W</dc:creator>
      <pubDate>Sat, 11 Jul 2026 07:46:00 +0000</pubDate>
      <link>https://dev.to/moersebene/dojo-dao-chang-karate-made-me-do-it-1abj</link>
      <guid>https://dev.to/moersebene/dojo-dao-chang-karate-made-me-do-it-1abj</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/weekend-2026-07-09"&gt;Weekend Challenge: Passion Edition&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;Dōjō (道場) is a Shito-Ryu based karate kata training companion, built around the Passion Edition prompt taken literally, to say that passion is the fire that drives us.&lt;/p&gt;

&lt;p&gt;The home screen is a living flame that grows with your training, fed by both your streak and the effort you put in each day. If you show up consistently, it builds and feeds the flame; if you put in a hard session, it flares up that same day. It's a real canvas particle fire and not a static graphic.&lt;/p&gt;

&lt;p&gt;The core is a count-along kata drill with a live sensei voice. Pick a kata, set the tempo, and a sensei counts you through it in Japanese — ichi, ni, san… — on the beat, with a kiai shout on the traditional counts and an optional metronome. Pause/resume mid-drill, and every kata's counts are editable, since those conventions vary by branch. Finishing a drill logs the session and feeds the flame.&lt;/p&gt;

&lt;p&gt;Rounding it out: a kata hall grouped by their respective lineage (Pinan, Shuri-te, Naha-te), with a belt-and-history view, and a one-tap Kiai button to test the chosen voice.&lt;/p&gt;

&lt;p&gt;I have been practicing karate for 30 years and my goal was to build something that feels like stepping into a dōjō, not opening a fitness dashboard — and to make the voice feel like a real sensei counting beside you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;


&lt;div class="ltag-netlify"&gt;
  &lt;iframe src="https://dojoh.netlify.app" title="Netlify embed"&gt;
  &lt;/iframe&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/chantleyw" rel="noopener noreferrer"&gt;
        chantleyw
      &lt;/a&gt; / &lt;a href="https://github.com/chantleyw/dojo" rel="noopener noreferrer"&gt;
        dojo
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Dōjō · 道場&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;A Shito-Ryu (糸東流) training companion with a live sensei voice.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Dōjō is a karate practice app built around a single emotional idea: &lt;em&gt;passion is the
fire that drives us&lt;/em&gt;. The home screen shows a flame that grows with your training
streak — a cold ember at zero, a roaring fire past 30 days. Pick a kata and a sensei
voice counts you through it in Japanese, on the beat — &lt;em&gt;ichi, ni, san…&lt;/em&gt; — with a kiai
shout on the traditional counts and an optional metronome tick.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Built for the DEV.to Weekend Challenge (Passion Edition).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;✨ Highlights&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A flame that grows with your streak.&lt;/strong&gt; Layered SVG plume with a Framer Motion
flicker, driven by &lt;code&gt;fire = min(1, streak / 30)&lt;/code&gt;. Reduced-motion holds it still.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A live count-along drill.&lt;/strong&gt; Choose a kata; the sensei counts in Japanese on the
beat, kiai-ing on the traditional counts. Tempo…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/chantleyw/dojo" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;The stack is Vite + React + TypeScript + Tailwind, with Framer Motion, Zustand for state, the Web Audio API for the metronome, and Netlify Functions for the backend. State persists per-device in localStorage — so no accounts are required.&lt;/p&gt;

&lt;p&gt;The sensei voice (ElevenLabs)&lt;br&gt;
This is the core of the app, and getting it to feel live drove most of the interesting decisions.&lt;/p&gt;

&lt;p&gt;A custom voice, built in Voice Design. The sensei is a purpose-built deep, gravelly grand-master voice created in ElevenLabs Voice Design — the kind of voice that could bark a battle command. The app pulls every voice on the account into a picker, but defaults to the sensei.&lt;/p&gt;

&lt;p&gt;Authentic Japanese counting. Numerals are generated programmatically as hiragana (いち, に, さん…, composing じゅういち for 11, and so on) and spoken with Turbo v2.5 using language_code: "ja". That language flag was the unlock because without it, an English-leaning accented voice pronounces さん like the English word "san"; with it, you get a proper sahn pronunciation.&lt;/p&gt;

&lt;p&gt;Making it land on the beat. A count drill can't afford a network round-trip per number. So on "Begin," the app pre-generates one clip per unique word, caches them as object URLs keyed by text, then plays the cached audio on each metronome beat. The count and the kiai are also given separate expressiveness profiles — the counts stay crisp and consistent, while the kiai runs at low stability / high style for a raw, shouted delivery.&lt;/p&gt;

&lt;p&gt;Keeping the key safe. The link is public, so the ElevenLabs key can never touches the browser. A tiny Netlify Function proxies /api/tts and /api/voices, holding the key in an env var and forwarding requests server-side. The client only ever talks to my own domain.&lt;/p&gt;

&lt;p&gt;Never hard-failing. If the proxy returns a non-200 — a quota cap, a rate limit — the app falls back to the browser's built-in speech synthesis (preferring a Japanese voice) and keeps counting. I actually hit this live during testing when a capped key ran dry, and the drill kept running on the fallback voice without a hiccup. Generation is also concurrency-limited with retries so the free tier's request limits don't drop individual clips.&lt;/p&gt;

&lt;p&gt;The flame is a canvas particle system — rising flame particles, floating embers, and an additive glow, all scaling with a single fire value from 0 to 1. Rather than tie that purely to the streak, I compute it from both consistency and effort: fire = 0.7 × (streak / 30) + 0.4 × (today's minutes / 45), capped at 1. A long streak carries a strong baseline, a hard session flares it up the same day, and a single huge day can't max it out alone. Reduced-motion users get a still flame instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;p&gt;Best Use of ElevenLabs. The sensei voice is the core of the app: a custom generated Voice Design grand-master voice, spoken with Turbo v2.5 and language_code: "ja" for authentic Japanese counting, pre-generated and cached per word so it lands on the beat, with separate expressiveness profiles for the counts and the kiai which are all served through a serverless proxy that keeps the API key off of the client, with a seamless fallback to the browser voice so a public link never hard-fails.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>elevenlabs</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
