scaffold: 12 Hobbies Studio site + OpenScribe project page
Initial static site (no framework, no build) for the 12 Hobbies Studio maker studio, featuring OpenScribe as the flagship project. What changed: - index.html: studio home - hero, featured OpenScribe block with sync diagram, projects grid, about. British spelling, dark warm theme. - projects/openscribe.html: OpenScribe product page. Leads with the "bring your own AI" differentiator, an interactive provider picker, the feature set, a four-step build guide, and licensing. - assets/styles.css: all styling (palette, cards, featured layout, picker, code blocks). - assets/app.js: dependency-free provider picker that swaps a sample server .env snippet across Ollama / OpenAI / Anthropic / Groq / LM Studio - on message with OpenScribe's any-AI design. - README, LICENSE (MIT for site code), .gitignore. Why: - The user asked to develop a site on 12 Hobbies Studio; this is the first cut, showcasing OpenScribe and the connect-to-any-AI capability. Branding uses sensible defaults and is trivially editable (noted in README). Notes: - Pure static files; deploy to any static host or Forgejo Pages. Validated: app.js passes node --check; HTML section tags balanced. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
commit
e1bf5a2d7a
7 changed files with 497 additions and 0 deletions
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
.DS_Store
|
||||
Thumbs.db
|
||||
*.swp
|
||||
*~
|
||||
node_modules/
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2026 12 Hobbies Studio
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
39
README.md
Normal file
39
README.md
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
# 12 Hobbies Studio - website
|
||||
|
||||
A small, dependency-free static site for **12 Hobbies Studio**, a maker studio that builds
|
||||
open-source, self-hostable projects. The flagship project featured here is
|
||||
[OpenScribe](https://git.discworld.casa/laurence/openscribe), an open AI voice recorder you
|
||||
can connect to any AI.
|
||||
|
||||
> Note on branding: this is an initial site with sensible defaults (name, tagline, colours,
|
||||
> copy). All of it is easy to change - edit `assets/styles.css` for the look and the HTML for
|
||||
> the words. Nothing here is locked in.
|
||||
|
||||
## What's here
|
||||
|
||||
```
|
||||
index.html Studio home: hero, featured project, projects grid, about
|
||||
projects/openscribe.html OpenScribe product page + interactive "bring your own AI" picker
|
||||
assets/styles.css All styling (no framework, no build)
|
||||
assets/app.js Provider picker that swaps a sample server .env snippet
|
||||
```
|
||||
|
||||
## Preview locally
|
||||
|
||||
It is plain HTML/CSS/JS - open `index.html` in a browser, or serve the folder:
|
||||
|
||||
```bash
|
||||
python -m http.server 8080 # then visit http://localhost:8080
|
||||
```
|
||||
|
||||
## Deploy
|
||||
|
||||
Any static host works (it is just files). For Forgejo Pages, publish this repo per your
|
||||
instance's Pages setup; for a plain web server, copy the files to the web root. There is no
|
||||
build step and no server-side code.
|
||||
|
||||
## Licence
|
||||
|
||||
Site code (HTML/CSS/JS) is MIT (see `LICENSE`). Prose content is the studio's own.
|
||||
OpenScribe is an independent project inspired by the Plaud class of device and is not
|
||||
affiliated with Plaud.
|
||||
86
assets/app.js
Normal file
86
assets/app.js
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
// Interactive AI-provider picker for the OpenScribe page. Swaps a sample server .env
|
||||
// snippet as you choose a provider - the whole point of OpenScribe: bring your own AI.
|
||||
(function () {
|
||||
var PROVIDERS = {
|
||||
ollama: {
|
||||
label: "Ollama (local)",
|
||||
lines: [
|
||||
["c", "# Fully local and self-hosted - no cloud, no key"],
|
||||
["k", "OPENSCRIBE_LLM_PROVIDER", "ollama"],
|
||||
["k", "OPENSCRIBE_OLLAMA_URL", "http://localhost:11434"],
|
||||
["k", "OPENSCRIBE_OLLAMA_MODEL", "llama3.1"],
|
||||
],
|
||||
},
|
||||
openai: {
|
||||
label: "OpenAI",
|
||||
lines: [
|
||||
["c", "# Any OpenAI-compatible endpoint works the same way"],
|
||||
["k", "OPENSCRIBE_LLM_PROVIDER", "openai_compatible"],
|
||||
["k", "OPENSCRIBE_LLM_BASE_URL", "https://api.openai.com/v1"],
|
||||
["k", "OPENSCRIBE_LLM_API_KEY", "sk-..."],
|
||||
["k", "OPENSCRIBE_LLM_MODEL", "gpt-4o-mini"],
|
||||
],
|
||||
},
|
||||
anthropic: {
|
||||
label: "Anthropic (Claude)",
|
||||
lines: [
|
||||
["c", "# Commercial Claude via the official Anthropic API"],
|
||||
["k", "OPENSCRIBE_LLM_PROVIDER", "anthropic"],
|
||||
["k", "OPENSCRIBE_LLM_API_KEY", "sk-ant-..."],
|
||||
["k", "OPENSCRIBE_LLM_MODEL", "claude-opus-4-8"],
|
||||
],
|
||||
},
|
||||
groq: {
|
||||
label: "Groq",
|
||||
lines: [
|
||||
["c", "# Fast + cheap, OpenAI-compatible"],
|
||||
["k", "OPENSCRIBE_LLM_PROVIDER", "openai_compatible"],
|
||||
["k", "OPENSCRIBE_LLM_BASE_URL", "https://api.groq.com/openai/v1"],
|
||||
["k", "OPENSCRIBE_LLM_API_KEY", "gsk_..."],
|
||||
["k", "OPENSCRIBE_LLM_MODEL", "llama-3.3-70b-versatile"],
|
||||
],
|
||||
},
|
||||
lmstudio: {
|
||||
label: "LM Studio (local)",
|
||||
lines: [
|
||||
["c", "# A local model server on your LAN, OpenAI-compatible"],
|
||||
["k", "OPENSCRIBE_LLM_PROVIDER", "openai_compatible"],
|
||||
["k", "OPENSCRIBE_LLM_BASE_URL", "http://localhost:1234/v1"],
|
||||
["k", "OPENSCRIBE_LLM_MODEL", "local-model"],
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
function esc(s) { return s.replace(/&/g, "&").replace(/</g, "<"); }
|
||||
|
||||
function render(key) {
|
||||
var p = PROVIDERS[key];
|
||||
var html = p.lines.map(function (l) {
|
||||
if (l[0] === "c") return '<span class="c">' + esc(l[1]) + "</span>";
|
||||
return '<span class="k">' + esc(l[1]) + "</span>=" + esc(l[2]);
|
||||
}).join("\n");
|
||||
document.getElementById("env-out").innerHTML = html;
|
||||
}
|
||||
|
||||
function init() {
|
||||
var picker = document.getElementById("provider-picker");
|
||||
if (!picker) return;
|
||||
Object.keys(PROVIDERS).forEach(function (key, i) {
|
||||
var b = document.createElement("button");
|
||||
b.type = "button";
|
||||
b.textContent = PROVIDERS[key].label;
|
||||
b.setAttribute("aria-pressed", i === 0 ? "true" : "false");
|
||||
b.addEventListener("click", function () {
|
||||
picker.querySelectorAll("button").forEach(function (x) { x.setAttribute("aria-pressed", "false"); });
|
||||
b.setAttribute("aria-pressed", "true");
|
||||
render(key);
|
||||
});
|
||||
picker.appendChild(b);
|
||||
});
|
||||
render(Object.keys(PROVIDERS)[0]);
|
||||
}
|
||||
|
||||
if (document.readyState !== "loading") init();
|
||||
else document.addEventListener("DOMContentLoaded", init);
|
||||
})();
|
||||
128
assets/styles.css
Normal file
128
assets/styles.css
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
/* SPDX-License-Identifier: MIT
|
||||
12 Hobbies Studio - site styles. No framework, no build step. */
|
||||
|
||||
:root {
|
||||
--ink: #10131a;
|
||||
--ink-2: #171b24;
|
||||
--panel: #1e2330;
|
||||
--line: #2c3444;
|
||||
--text: #e7ecf3;
|
||||
--muted: #9aa6b8;
|
||||
--accent: #f0a35e; /* warm amber */
|
||||
--accent-2: #6ec7c0; /* teal */
|
||||
--radius: 14px;
|
||||
--wrap: 1080px;
|
||||
--sans: ui-sans-serif, system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||
--mono: ui-monospace, "SF Mono", "Cascadia Code", "Fira Code", Consolas, monospace;
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
|
||||
html { scroll-behavior: smooth; }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: var(--sans);
|
||||
color: var(--text);
|
||||
background:
|
||||
radial-gradient(1200px 600px at 80% -10%, rgba(240,163,94,0.10), transparent 60%),
|
||||
radial-gradient(1000px 500px at -10% 10%, rgba(110,199,192,0.08), transparent 55%),
|
||||
var(--ink);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
a { color: var(--accent); text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
|
||||
.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 20px; }
|
||||
|
||||
/* Header */
|
||||
.site-header {
|
||||
position: sticky; top: 0; z-index: 10;
|
||||
backdrop-filter: blur(8px);
|
||||
background: rgba(16,19,26,0.72);
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
.site-header .wrap { display: flex; align-items: center; justify-content: space-between; height: 62px; }
|
||||
.brand { display: flex; align-items: center; gap: 10px; font-weight: 700; letter-spacing: 0.2px; color: var(--text); }
|
||||
.brand .mark {
|
||||
display: grid; place-items: center; width: 30px; height: 30px; border-radius: 8px;
|
||||
background: linear-gradient(135deg, var(--accent), var(--accent-2)); color: #0c0e13; font-weight: 800;
|
||||
}
|
||||
.nav a { color: var(--muted); margin-left: 22px; font-weight: 500; }
|
||||
.nav a:hover { color: var(--text); text-decoration: none; }
|
||||
|
||||
/* Hero */
|
||||
.hero { padding: 84px 0 40px; }
|
||||
.eyebrow { color: var(--accent-2); font-family: var(--mono); font-size: 0.82rem; letter-spacing: 2px; text-transform: uppercase; }
|
||||
.hero h1 { font-size: clamp(2.1rem, 5vw, 3.4rem); line-height: 1.08; margin: 12px 0 14px; }
|
||||
.hero p.lead { font-size: 1.18rem; color: var(--muted); max-width: 640px; }
|
||||
.hero .accent { color: var(--accent); }
|
||||
|
||||
/* Buttons */
|
||||
.btn {
|
||||
display: inline-block; padding: 11px 18px; border-radius: 10px; font-weight: 600;
|
||||
border: 1px solid var(--line); color: var(--text); background: var(--panel);
|
||||
}
|
||||
.btn:hover { text-decoration: none; border-color: var(--accent); }
|
||||
.btn.primary { background: linear-gradient(135deg, var(--accent), #e8925a); color: #14100a; border: none; }
|
||||
.btn-row { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 26px; }
|
||||
|
||||
/* Sections */
|
||||
section { padding: 46px 0; }
|
||||
h2 { font-size: 1.7rem; margin: 0 0 6px; }
|
||||
.section-sub { color: var(--muted); margin: 0 0 26px; }
|
||||
|
||||
/* Cards / grid */
|
||||
.grid { display: grid; gap: 18px; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); }
|
||||
.card {
|
||||
background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
|
||||
padding: 20px; transition: border-color .15s, transform .15s;
|
||||
}
|
||||
.card:hover { border-color: var(--accent); transform: translateY(-2px); }
|
||||
.card h3 { margin: 0 0 6px; font-size: 1.12rem; }
|
||||
.card p { color: var(--muted); margin: 0; }
|
||||
.card .tag { display: inline-block; font-family: var(--mono); font-size: 0.72rem; color: var(--accent-2);
|
||||
border: 1px solid var(--line); border-radius: 999px; padding: 2px 10px; margin-bottom: 10px; }
|
||||
.card.soon { opacity: 0.72; }
|
||||
|
||||
/* Featured */
|
||||
.featured {
|
||||
display: grid; grid-template-columns: 1.2fr 1fr; gap: 26px; align-items: center;
|
||||
background: linear-gradient(180deg, var(--ink-2), var(--panel));
|
||||
border: 1px solid var(--line); border-radius: 18px; padding: 28px;
|
||||
}
|
||||
.featured h2 { font-size: 1.9rem; }
|
||||
.featured .kicker { color: var(--accent); font-family: var(--mono); font-size: .8rem; letter-spacing: 1.5px; text-transform: uppercase; }
|
||||
.featured ul { margin: 14px 0 0; padding-left: 18px; color: var(--muted); }
|
||||
.diagram {
|
||||
font-family: var(--mono); font-size: 0.8rem; color: var(--muted);
|
||||
background: #0c0f16; border: 1px solid var(--line); border-radius: 12px; padding: 16px; white-space: pre; overflow-x: auto;
|
||||
}
|
||||
@media (max-width: 780px) { .featured { grid-template-columns: 1fr; } }
|
||||
|
||||
/* Provider picker (openscribe page) */
|
||||
.picker { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0 16px; }
|
||||
.picker button {
|
||||
font-family: var(--sans); font-size: .92rem; cursor: pointer;
|
||||
background: var(--panel); color: var(--text); border: 1px solid var(--line);
|
||||
border-radius: 999px; padding: 8px 15px;
|
||||
}
|
||||
.picker button[aria-pressed="true"] { border-color: var(--accent); background: rgba(240,163,94,0.14); color: var(--text); }
|
||||
pre.code {
|
||||
font-family: var(--mono); font-size: 0.86rem; color: #d7e2f0;
|
||||
background: #0c0f16; border: 1px solid var(--line); border-radius: 12px; padding: 16px; overflow-x: auto;
|
||||
}
|
||||
pre.code .c { color: var(--muted); }
|
||||
pre.code .k { color: var(--accent-2); }
|
||||
|
||||
/* Feature list */
|
||||
.features { display: grid; gap: 14px; grid-template-columns: repeat(auto-fit, minmax(220px,1fr)); }
|
||||
.feature { border-left: 2px solid var(--accent); padding-left: 14px; }
|
||||
.feature h4 { margin: 0 0 3px; }
|
||||
.feature p { margin: 0; color: var(--muted); font-size: 0.96rem; }
|
||||
|
||||
/* Footer */
|
||||
.site-footer { border-top: 1px solid var(--line); padding: 30px 0; color: var(--muted); }
|
||||
.site-footer .wrap { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 12px; }
|
||||
.pill { font-family: var(--mono); font-size: .75rem; color: var(--accent-2); }
|
||||
115
index.html
Normal file
115
index.html
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
<!doctype html>
|
||||
<!-- SPDX-License-Identifier: MIT -->
|
||||
<html lang="en-GB">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>12 Hobbies Studio - open, self-hosted maker projects</title>
|
||||
<meta name="description" content="12 Hobbies Studio builds open-source, self-hosted maker projects. Flagship: OpenScribe, an AI voice recorder you can connect to any AI." />
|
||||
<link rel="stylesheet" href="assets/styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header class="site-header">
|
||||
<div class="wrap">
|
||||
<a class="brand" href="index.html"><span class="mark">12</span> Hobbies Studio</a>
|
||||
<nav class="nav">
|
||||
<a href="#projects">Projects</a>
|
||||
<a href="#about">About</a>
|
||||
<a href="projects/openscribe.html">OpenScribe</a>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<section class="hero">
|
||||
<div class="wrap">
|
||||
<div class="eyebrow">A maker studio</div>
|
||||
<h1>Twelve hobbies, one habit:<br /><span class="accent">build it open, run it yourself.</span></h1>
|
||||
<p class="lead">12 Hobbies Studio makes small, open-source, self-hostable projects across
|
||||
hardware, software and everything in between. No lock-in, no subscriptions you cannot leave,
|
||||
no data you do not own.</p>
|
||||
<div class="btn-row">
|
||||
<a class="btn primary" href="projects/openscribe.html">Meet OpenScribe</a>
|
||||
<a class="btn" href="#projects">Browse projects</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div class="wrap">
|
||||
<div class="featured">
|
||||
<div>
|
||||
<div class="kicker">Flagship project</div>
|
||||
<h2>OpenScribe</h2>
|
||||
<p class="section-sub">An open-source, self-hosted AI voice recorder in the spirit of a
|
||||
Plaud device - but you bring the AI. Record on a small ESP32-S3, sync over BLE or WiFi,
|
||||
transcribe and summarise with <strong>any AI you choose</strong>: open-standard, local,
|
||||
or a commercial API.</p>
|
||||
<ul>
|
||||
<li>Open hardware, open firmware, open API - build it and own it.</li>
|
||||
<li>Connect to OpenAI, Anthropic, Groq, a local model, or your own server.</li>
|
||||
<li>Self-hosted transcription and summaries. No mandatory cloud.</li>
|
||||
</ul>
|
||||
<div class="btn-row">
|
||||
<a class="btn primary" href="projects/openscribe.html">Explore OpenScribe</a>
|
||||
<a class="btn" href="https://git.discworld.casa/laurence/openscribe">Source</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="diagram">mic
|
||||
-> ESP32-S3 (record to SD)
|
||||
| BLE / WiFi sync
|
||||
v
|
||||
self-hosted server
|
||||
transcribe -> summarise
|
||||
| (any AI provider)
|
||||
v
|
||||
phone app + open API</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="projects">
|
||||
<div class="wrap">
|
||||
<h2>Projects</h2>
|
||||
<p class="section-sub">One shipped, more in the workshop. Everything here is open source.</p>
|
||||
<div class="grid">
|
||||
<a class="card" href="projects/openscribe.html">
|
||||
<span class="tag">hardware + AI</span>
|
||||
<h3>OpenScribe</h3>
|
||||
<p>Self-hosted AI voice recorder. Bring your own AI, open or commercial.</p>
|
||||
</a>
|
||||
<div class="card soon">
|
||||
<span class="tag">in the workshop</span>
|
||||
<h3>More soon</h3>
|
||||
<p>New hobbies, new builds. This grid grows as projects ship.</p>
|
||||
</div>
|
||||
<div class="card soon">
|
||||
<span class="tag">idea</span>
|
||||
<h3>Your idea?</h3>
|
||||
<p>Open a discussion on the forge. The studio likes a good excuse to build.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="about">
|
||||
<div class="wrap">
|
||||
<h2>About the studio</h2>
|
||||
<p class="section-sub" style="max-width:680px">
|
||||
12 Hobbies Studio is a home for maker projects that are worth doing properly and worth
|
||||
sharing. The through-line: build in the open, keep the data with the person who made it,
|
||||
and let anyone reproduce the whole thing from the repo alone. Firmware, servers and apps
|
||||
are copyleft; hardware is open-hardware licensed; docs are share-alike.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer class="site-footer">
|
||||
<div class="wrap">
|
||||
<div>© 12 Hobbies Studio. Built open. <span class="pill">self-hosted</span></div>
|
||||
<div><a href="https://git.discworld.casa/laurence/openscribe">OpenScribe source</a></div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
103
projects/openscribe.html
Normal file
103
projects/openscribe.html
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
<!doctype html>
|
||||
<!-- SPDX-License-Identifier: MIT -->
|
||||
<html lang="en-GB">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>OpenScribe - open, self-hosted AI voice recorder | 12 Hobbies Studio</title>
|
||||
<meta name="description" content="OpenScribe is an open-source, self-hosted AI voice recorder. Record on an ESP32-S3, sync over BLE or WiFi, and transcribe and summarise with any AI you choose - open or commercial." />
|
||||
<link rel="stylesheet" href="../assets/styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header class="site-header">
|
||||
<div class="wrap">
|
||||
<a class="brand" href="../index.html"><span class="mark">12</span> Hobbies Studio</a>
|
||||
<nav class="nav">
|
||||
<a href="../index.html#projects">Projects</a>
|
||||
<a href="#any-ai">Any AI</a>
|
||||
<a href="https://git.discworld.casa/laurence/openscribe">Source</a>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<section class="hero">
|
||||
<div class="wrap">
|
||||
<div class="eyebrow">Project - hardware + AI</div>
|
||||
<h1>OpenScribe</h1>
|
||||
<p class="lead">An open-source, self-hosted AI voice recorder in the spirit of a Plaud device.
|
||||
Record on a small ESP32-S3, sync to your phone and your own server, and turn recordings into
|
||||
transcripts and summaries with <span class="accent">any AI you choose</span>.</p>
|
||||
<div class="btn-row">
|
||||
<a class="btn primary" href="https://git.discworld.casa/laurence/openscribe">Get the source</a>
|
||||
<a class="btn" href="#build">How to build</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="any-ai">
|
||||
<div class="wrap">
|
||||
<h2>Bring your own AI</h2>
|
||||
<p class="section-sub">This is the difference. A commercial recorder locks you to its cloud.
|
||||
OpenScribe lets you point transcription and summaries at whatever you want - a local model,
|
||||
an open-standard endpoint, or a commercial API. Pick one and drop it in your server config:</p>
|
||||
<div id="provider-picker" class="picker" aria-label="Choose an AI provider"></div>
|
||||
<pre class="code"><code id="env-out"></code></pre>
|
||||
<p class="section-sub">Transcription is just as flexible: local <code>faster-whisper</code>, or
|
||||
any OpenAI-compatible audio endpoint (OpenAI, Groq, or your own whisper server).</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div class="wrap">
|
||||
<h2>What it does</h2>
|
||||
<p class="section-sub">The expected recorder features, without the lock-in.</p>
|
||||
<div class="features">
|
||||
<div class="feature"><h4>One-button recording</h4><p>Capture to microSD on a wearable ESP32-S3. No length limit.</p></div>
|
||||
<div class="feature"><h4>Three ways to sync</h4><p>BLE for control, WiFi to the app, and independent WiFi upload when on charge.</p></div>
|
||||
<div class="feature"><h4>Transcribe + summarise</h4><p>Server-side, with the AI provider you chose. Overview, key points, action items.</p></div>
|
||||
<div class="feature"><h4>Completely open API</h4><p>List, download and export recordings (audio, TXT, SRT, VTT, Markdown, JSON).</p></div>
|
||||
<div class="feature"><h4>Self-hosted storage</h4><p>Upload to your own S3-compatible store, WebDAV or NAS. Your data stays yours.</p></div>
|
||||
<div class="feature"><h4>Mobile app</h4><p>Flutter app for Android and iOS: provisioning, library, playback, summaries.</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="build">
|
||||
<div class="wrap">
|
||||
<h2>Build one</h2>
|
||||
<p class="section-sub">Off-the-shelf parts, a printed case, and a server you run.</p>
|
||||
<div class="grid">
|
||||
<div class="card"><span class="tag">hardware</span><h3>1. Get the parts</h3><p>ESP32-S3 with PSRAM, an I2S MEMS mic, a microSD card, a LiPo and a charge IC. Full BOM in the repo.</p></div>
|
||||
<div class="card"><span class="tag">firmware</span><h3>2. Flash it</h3><p>PlatformIO builds two board profiles. Record to WAV, then sync over WiFi and the on-device REST API.</p></div>
|
||||
<div class="card"><span class="tag">case</span><h3>3. Print the case</h3><p>Parametric OpenSCAD enclosure you can re-tune to your exact board and battery.</p></div>
|
||||
<div class="card"><span class="tag">server</span><h3>4. Run the server</h3><p>FastAPI ingest + transcription + summaries. Point it at your chosen AI and storage.</p></div>
|
||||
</div>
|
||||
<div class="btn-row">
|
||||
<a class="btn primary" href="https://git.discworld.casa/laurence/openscribe">Open the repository</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div class="wrap">
|
||||
<h2>Open all the way down</h2>
|
||||
<p class="section-sub" style="max-width:680px">
|
||||
Firmware, server and app are GPL-3.0. The hardware design is CERN-OHL-S. The case and docs
|
||||
are CC-BY-SA. Anyone can build it, improve it, and keep the result open. OpenScribe is an
|
||||
independent project inspired by the Plaud class of device; it is not affiliated with Plaud.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer class="site-footer">
|
||||
<div class="wrap">
|
||||
<div>© 12 Hobbies Studio. Built open. <span class="pill">bring your own AI</span></div>
|
||||
<div><a href="../index.html">Back to the studio</a></div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="../assets/app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue