Important
This is crazy pre-alpha and is changing really rapidly. Stuff should stabilize eventually but probably not for a month or two.
.
βββ public
βββ src
β βββ components
β βββ pages
β βββ styles
βββ whisper-server
βββ main.py
βββ requirements.txt
βββ README.md
9 directories, 3 filesThistle is a transcription service I'm building for Cedarville's startup competition! I'm also using it as an opportunity to become more familar with web components and full stack applications.
I'm just running this locally for now but getting started is super straightforward.
bun install
bun devYour server will be running at http://localhost:3000 with hot module reloading. Just edit any .ts, .html, or .css file and watch it update in the browser.
Thistle requires a separate Whisper transcription server for audio processing. Set it up in the whisper-server/ directory:
cd whisper-server
./run.shOr manually:
cd whisper-server
pip install -r requirements.txt
python main.pyThe Whisper server will run on http://localhost:8000. Make sure it's running before using transcription features.
Copy .env.example to .env and configure:
cp .env.example .env
# Edit .env to set WHISPER_SERVICE_URL=http://localhost:8000The tech stack is pretty minimal on purpose. Lit components (~8-10KB gzipped) for things that need reactivity, vanilla JS for simple stuff, and CSS variables for theming. The goal is to keep the total JS bundle as small as possible.
The development flow is really nice in my opinion. The server imports HTML files as route handlers. Those HTML files import TypeScript components using <script type="module">. The components are just Lit web components that self-register as custom elements. Bun sees all this and bundles everything automatically including linked images or assets from the public directory.
// src/index.ts - Server imports HTML as routes
import indexHTML from "./pages/index.html";
Bun.serve({
port: 3000,
routes: {
"/": indexHTML,
},
development: {
hmr: true,
console: true,
},
});<!-- src/pages/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="../styles/main.css" />
</head>
<body>
<counter-component></counter-component>
<script type="module" src="../components/counter.ts"></script>
</body>
</html>// src/components/counter.ts
import { LitElement, html, css } from "lit";
import { customElement, property } from "lit/decorators.js";
@customElement("counter-component")
export class CounterComponent extends LitElement {
@property({ type: Number }) count = 0;
static styles = css`
:host {
display: block;
padding: 1rem;
}
`;
render() {
return html`
<div>${this.count}</div>
<button @click=${() => this.count++}>+</button>
`;
}
}Oh last two points. Please please please use standard commits for my sanity and report any issues to the tangled repo
Β© 2025-present Kieran Klukas