diff --git a/.gitignore b/.gitignore
index 36b13f1..128fc01 100644
--- a/.gitignore
+++ b/.gitignore
@@ -174,3 +174,6 @@ cython_debug/
# PyPI configuration file
.pypirc
+node_modules/
+dist/
+.vite/
diff --git a/README.md b/README.md
index fcd7b8f..f2d84d2 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,16 @@
-# repo-seed
+# ๐งช TestDrive UI
-A git repository template to bootstrap coulomb projects from.
\ No newline at end of file
+Baseline scaffold for test-driven browser UI component development with **Lit**, **Mocha**, and **jsdom**.
+
+### Commands
+
+| Command | Description |
+|----------|-------------|
+| `npm install` | Install dependencies |
+| `npm test` | Run all Mocha tests headlessly |
+| `npm run dev` | Start Vite dev server and preview components |
+
+### Folder layout
+- `src/components/` โ individual components (each with .js, .test.js, .stories.js)
+- `test/setup.js` โ shared JSDOM environment
+- `vite.config.js` โ dev preview config
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..40f4149
--- /dev/null
+++ b/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "testdrive-ui",
+ "version": "0.1.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "test": "mocha --require test/setup.js \"src/**/*.test.js\""
+ },
+ "devDependencies": {
+ "chai": "^5.1.0",
+ "jsdom": "^24.0.0",
+ "lit": "^3.1.0",
+ "mocha": "^11.0.0",
+ "vite": "^6.0.0"
+ }
+}
diff --git a/src/components/ui-edit-button/ui-edit-button.js b/src/components/ui-edit-button/ui-edit-button.js
new file mode 100644
index 0000000..c4a609f
--- /dev/null
+++ b/src/components/ui-edit-button/ui-edit-button.js
@@ -0,0 +1,32 @@
+import { LitElement, html, css } from "lit";
+
+export class UiEditButton extends LitElement {
+ static styles = css`
+ button {
+ position: fixed;
+ top: 50%;
+ right: 20px;
+ transform: translateY(-50%);
+ background: #007acc;
+ color: white;
+ border: none;
+ border-radius: 8px;
+ padding: 10px 16px;
+ cursor: pointer;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
+ }
+ button:hover {
+ background: #005fa3;
+ }
+ `;
+
+ render() {
+ return html``;
+ }
+
+ _onClick() {
+ alert("Edit button clicked!");
+ }
+}
+
+customElements.define("ui-edit-button", UiEditButton);
diff --git a/src/components/ui-edit-button/ui-edit-button.stories.js b/src/components/ui-edit-button/ui-edit-button.stories.js
new file mode 100644
index 0000000..c002a96
--- /dev/null
+++ b/src/components/ui-edit-button/ui-edit-button.stories.js
@@ -0,0 +1,7 @@
+import "./ui-edit-button.js";
+
+export default {
+ title: "UI/Edit Button",
+};
+
+export const Default = () => ``;
diff --git a/src/components/ui-edit-button/ui-edit-button.test.js b/src/components/ui-edit-button/ui-edit-button.test.js
new file mode 100644
index 0000000..4f50e03
--- /dev/null
+++ b/src/components/ui-edit-button/ui-edit-button.test.js
@@ -0,0 +1,24 @@
+import "../ui-edit-button/ui-edit-button.js";
+
+describe("", () => {
+ it("renders a button element", () => {
+ const el = document.createElement("ui-edit-button");
+ document.body.appendChild(el);
+ const button = el.shadowRoot.querySelector("button");
+ expect(button).to.exist;
+ expect(button.textContent).to.include("Edit");
+ });
+
+ it("triggers a click handler", () => {
+ const el = document.createElement("ui-edit-button");
+ document.body.appendChild(el);
+
+ let clicked = false;
+ el._onClick = () => (clicked = true);
+
+ const button = el.shadowRoot.querySelector("button");
+ button.click();
+
+ expect(clicked).to.be.true;
+ });
+});
diff --git a/src/index.html b/src/index.html
new file mode 100644
index 0000000..7394fbc
--- /dev/null
+++ b/src/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+ TestDrive UI
+
+
+
+ Hello TestDrive UI
+
+
+
diff --git a/test/setup.js b/test/setup.js
new file mode 100644
index 0000000..ecc7b99
--- /dev/null
+++ b/test/setup.js
@@ -0,0 +1,12 @@
+import { JSDOM } from "jsdom";
+import { expect } from "chai";
+
+const dom = new JSDOM(``, {
+ url: "http://localhost"
+});
+
+global.window = dom.window;
+global.document = dom.window.document;
+global.customElements = dom.window.customElements;
+global.HTMLElement = dom.window.HTMLElement;
+global.expect = expect;
diff --git a/vite.config.js b/vite.config.js
new file mode 100644
index 0000000..eb17b1d
--- /dev/null
+++ b/vite.config.js
@@ -0,0 +1,8 @@
+import { defineConfig } from "vite";
+
+export default defineConfig({
+ root: "src",
+ server: {
+ open: true
+ }
+});