+ {/* view header */}
+
+
New app
+
+ Describe it, or start from a template
+
+
+
+ {/* scrollable body */}
+
+ {/* hero */}
+
+
+ Build a taOS app in plain words.
+
+
+ Describe what it should do. An agent builds it against the taOS SDK, sandboxed and safe,
+ and you can publish it to your Store or share it with family.
+
+
+
+ a shared shopping list the whole house can add to from their phones...
+
+
+
+ Build
+
+
+
+
+ {/* section label */}
+
+ Start from a template
+
+
+ {/* template grid */}
+
+ {TEMPLATES.map((t) => {
+ const Icon = t.icon;
+ return (
+
+
+
+
+ {t.label}
+
+ {t.desc}
+
+
+ );
+ })}
+
+
+
+ );
+}
diff --git a/desktop/src/apps/codingstudio/BuildView.tsx b/desktop/src/apps/codingstudio/BuildView.tsx
new file mode 100644
index 00000000..95088773
--- /dev/null
+++ b/desktop/src/apps/codingstudio/BuildView.tsx
@@ -0,0 +1,384 @@
+import {
+ Sparkles,
+ Folder,
+ FileText,
+ ClipboardCheck,
+ Check,
+ Circle,
+ ChevronDown,
+ Play,
+} from "lucide-react";
+
+const CODE_LINES = [
+ {
+ n: 1,
+ jsx: (
+ <>
+
+ {/* column 1: file tree */}
+
+
+ todo-app
+
+
+ {/* src folder */}
+
+
+ src
+
+
+ {/* App.tsx - active */}
+
+
+
+
+ TodoList.tsx
+
+
+
+
+ useTodos.ts
+
+
+
+
+ styles.css
+
+
+ {/* root files */}
+
+
+ index.html
+
+
+
+
+ package.json
+
+
+
+
+ vite.config.ts
+
+
+
+ {/* column 2: editor */}
+
+ {/* tabs bar */}
+
+
+ App.tsx
+ x
+
+
+ useTodos.ts
+ x
+
+
+
+ {/* code area */}
+
+ {CODE_LINES.map(({ n, jsx }) => (
+
+
+ {n}
+
+
+ {jsx}
+ {n === 10 && (
+
+ )}
+
+
+ ))}
+
+
+ {/* terminal strip */}
+
+
+ ~/todo-app
+ {" $ npm run dev"}
+
+
+ VITE v5.4
+ {" ready in 412 ms"}
+
+
+ {"> Local: "}
+ http://todo-app.taos.local
+ {" "}
+ live
+
+
+
+
+ {/* column 3: build log */}
+
+ {/* header */}
+
+
+ Build log
+
+
+ {/* steps */}
+
+ {BUILD_STEPS.map((step) => (
+
+
+
+
{step.title}
+
+ {step.meta}
+
+
+
+ ))}
+
+
+ {/* footer */}
+
+ {/* model pill */}
+
+
+
+
Qwen2.5-Coder 7B
+
local - fedora-gpu
+
+
+
+
+ {/* open preview button */}
+
+
+
+
+
+ {/* prompt bar */}
+ ("desktop");
+
+ return (
+
+ {/* view header */}
+
+
Preview
+
+ todo-app - live on fedora-gpu
+
+
+
+ {/* horizontal split */}
+
+ {/* preview stage */}
+
+ {/* url bar + device toggle */}
+
+
+
+ todo-app.taos.local
+
+
+ {(
+ [
+ { id: "desktop" as DeviceMode, Icon: Monitor },
+ { id: "tablet" as DeviceMode, Icon: Tablet },
+ { id: "phone" as DeviceMode, Icon: Smartphone },
+ ] as { id: DeviceMode; Icon: typeof Monitor }[]
+ ).map(({ id, Icon }) => (
+ setDeviceMode(id)}
+ className={`flex cursor-pointer items-center rounded-full px-[11px] py-[5px] ${
+ deviceMode === id
+ ? "bg-shell-surface-active text-shell-text"
+ : "text-shell-text-tertiary"
+ }`}
+ >
+
+
+ ))}
+
+
+
+ {/* frame - simulated todo app in light theme */}
+
+ {/* app bar */}
+
+
+ My Tasks
+
+ 2 left
+
+
+
+ {/* app body */}
+
+ {/* add input */}
+
+ Add a task...
+
+
+ {/* todo items */}
+
+
+
Ship Coding Studio mock
+
+ today
+
+
+
+
+
+
Wire the cluster build runner
+
+ soon
+
+
+
+
+
+
Add completed-tasks filter
+
+ soon
+
+
+
+
+
+
Pick the syntax theme
+
+
+
+
+
+ {/* console panel */}
+
+
+
+ Console - dev server
+
+
+
+
+ 18:02:11 {" "}
+ ready
+ {" vite v5.4 in 412ms"}
+
+
+ 18:02:11 {" "}
+ hmr
+ {" page reload App.tsx"}
+
+
+ 18:02:18 {" "}
+ hmr
+ {" update TodoList.tsx"}
+
+
+ 18:02:18
+ {" useTodos: restored 4 from localStorage"}
+
+
+ 18:02:24 {" "}
+ 200
+ {" GET / 14ms"}
+
+
+ 18:02:24
+ {" render - 4 todos - 2 remaining"}
+
+
+ 18:02:31 {" "}
+ hmr
+ {" update styles.css"}
+
+
+
+
+
+ {/* footer bar */}
+
+
+
+ Restart
+
+
+
+ Open in browser
+
+
+
+ Share to Store
+
+
+
+ );
+}
diff --git a/desktop/src/apps/codingstudio/TemplatesView.tsx b/desktop/src/apps/codingstudio/TemplatesView.tsx
new file mode 100644
index 00000000..32819766
--- /dev/null
+++ b/desktop/src/apps/codingstudio/TemplatesView.tsx
@@ -0,0 +1,158 @@
+import {
+ Sparkles,
+ LayoutPanelTop,
+ List,
+ TerminalSquare,
+ Diamond,
+ Square,
+ Calendar,
+ ChevronRight,
+ Globe,
+} from "lucide-react";
+import { type LucideIcon } from "lucide-react";
+
+const TEMPLATES: {
+ name: string;
+ desc: string;
+ stack: string;
+ gradient: string;
+ Icon: LucideIcon;
+}[] = [
+ {
+ name: "Web App",
+ desc: "React + Vite single-page app with routing.",
+ stack: "react - ts - vite",
+ gradient: "linear-gradient(135deg,#6f7687,#565d6e)",
+ Icon: LayoutPanelTop,
+ },
+ {
+ name: "REST API",
+ desc: "FastAPI service with typed routes and docs.",
+ stack: "python - fastapi",
+ gradient: "linear-gradient(135deg,#5f8a6f,#4a6f57)",
+ Icon: List,
+ },
+ {
+ name: "CLI Tool",
+ desc: "Command-line app with args and help output.",
+ stack: "node - commander",
+ gradient: "linear-gradient(135deg,#7a7488,#5e596b)",
+ Icon: TerminalSquare,
+ },
+ {
+ name: "Discord Bot",
+ desc: "Slash-command bot wired to your agents.",
+ stack: "node - discord.js",
+ gradient: "linear-gradient(135deg,#5d7a8a,#465e6c)",
+ Icon: Diamond,
+ },
+ {
+ name: "Static Site",
+ desc: "Fast marketing or docs site, deploy to LAN.",
+ stack: "astro - html",
+ gradient: "linear-gradient(135deg,#8a7a5d,#6c5e46)",
+ Icon: Square,
+ },
+ {
+ name: "Data Pipeline",
+ desc: "Scheduled job that pulls, transforms, stores.",
+ stack: "python - pandas",
+ gradient: "linear-gradient(135deg,#6f7687,#565d6e)",
+ Icon: Calendar,
+ },
+ {
+ name: "Python Script",
+ desc: "A single-file utility for a quick automation.",
+ stack: "python",
+ gradient: "linear-gradient(135deg,#5f8a6f,#4a6f57)",
+ Icon: ChevronRight,
+ },
+ {
+ name: "Browser Extension",
+ desc: "Chrome/Firefox extension scaffold + manifest.",
+ stack: "ts - webext",
+ gradient: "linear-gradient(135deg,#7a7488,#5e596b)",
+ Icon: Globe,
+ },
+];
+
+export function TemplatesView() {
+ return (
+
+ {/* view header */}
+
+
New project
+
+ Start from a prompt, a template, or blank
+
+
+
+ {/* scrollable body */}
+
+ {/* hero card */}
+
+
+ Describe what you want to build.
+
+
+ Tell taOS the app, tool, or script you need. An agent on your cluster scaffolds it,
+ writes the code, runs it, and hands you a live preview you can keep editing.
+
+
+
+
+
+ Build
+
+
+
+
+ {/* template grid */}
+
+ Start from a template
+
+
+ {TEMPLATES.map(({ name, desc, stack, gradient, Icon }) => (
+
+
+
+
+
{name}
+
+ {desc}
+
+
+ {stack}
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/desktop/src/apps/designstudio/DesignView.tsx b/desktop/src/apps/designstudio/DesignView.tsx
new file mode 100644
index 00000000..d6e043c8
--- /dev/null
+++ b/desktop/src/apps/designstudio/DesignView.tsx
@@ -0,0 +1,296 @@
+import { Type, Square, Circle, Image, Plus, Star, Sparkles, AlignLeft, Italic, Underline, Undo, Download } from "lucide-react";
+
+const ELEMENT_TILES: { label: string; icon: typeof Type }[] = [
+ { label: "Text", icon: Type },
+ { label: "Shape", icon: Square },
+ { label: "Circle", icon: Circle },
+ { label: "Image", icon: Image },
+ { label: "Line", icon: Plus },
+ { label: "Star", icon: Star },
+];
+
+const BRAND_SWATCHES = [
+ "#6b7689",
+ "#2c3142",
+ "#cdd3df",
+ "#3d8f7a",
+ "#c98b5b",
+ "#ffffff",
+];
+
+const COLOR_SWATCHES = [
+ { hex: "#ffffff", active: true },
+ { hex: "#cdd3df", active: false },
+ { hex: "#6b7689", active: false },
+ { hex: "#3d8f7a", active: false },
+ { hex: "#c98b5b", active: false },
+];
+
+const MAGIC_CHIPS = ["Make it bolder", "Match brand", "Rewrite copy"];
+
+export function DesignView() {
+ return (
+ <>
+ {/* view header */}
+
+
Untitled poster
+
Poster · 1080 x 1350
+
+
+
+ Undo
+
+
+
+ Export
+
+
+
+
+ {/* three-column body */}
+
+ {/* left elements panel */}
+
+
+ Add
+
+
+ {ELEMENT_TILES.map(({ label, icon: Icon }) => (
+
+
+
+ ))}
+
+
+ Brand colors
+
+
+ {BRAND_SWATCHES.map((hex) => (
+
+ ))}
+
+
+
+ {/* center canvas stage */}
+
+ {/* stage bar */}
+
+
+
+ Heading
+
+
+ Sohne · 40
+
+
68%
+
+
+ {/* artboard */}
+
+
+ {/* decorative blob */}
+
+ {/* poster text content */}
+
+ taOS Studios
+
+
+ Build it your way.
+
+
+ Dedicated studios for every project, running on hardware you already own.
+
+
+ Get started
+
+
+ {/* selection box */}
+
+ {/* corner handles */}
+ {[
+ { left: "26px", top: "58px" },
+ { left: "calc(100% - 26px)", top: "58px" },
+ { left: "26px", top: "150px" },
+ { left: "calc(100% - 26px)", top: "150px" },
+ ].map((pos, i) => (
+
+ ))}
+
+
+
+
+ {/* right properties panel */}
+
+ {/* text */}
+
+
+ {/* style */}
+
+
+ Style
+
+
+
+ B
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* color */}
+
+
+ Color
+
+
+ {COLOR_SWATCHES.map(({ hex, active }) => (
+
+ ))}
+
+
+
+ {/* magic edits box */}
+
+
+
+ Magic edits
+
+
+ Ask for a change in words. taOS restyles the selected layer, on your cluster.
+
+
+ {MAGIC_CHIPS.map((chip) => (
+
+ {chip}
+
+ ))}
+
+
+
+
+ >
+ );
+}
diff --git a/desktop/src/apps/designstudio/MagicView.tsx b/desktop/src/apps/designstudio/MagicView.tsx
new file mode 100644
index 00000000..a1fec6ed
--- /dev/null
+++ b/desktop/src/apps/designstudio/MagicView.tsx
@@ -0,0 +1,98 @@
+import { Sparkles } from "lucide-react";
+
+const STYLE_CHIPS = ["Bold", "Minimal", "Editorial", "Playful", "Dark", "Corporate"];
+
+const RESULTS: { label: string; gradient: string }[] = [
+ {
+ label: "Bold, centered",
+ gradient:
+ "radial-gradient(130% 120% at 20% 12%, #5a6b86, transparent 55%), linear-gradient(150deg, #2c3142, #171a24)",
+ },
+ {
+ label: "Split layout",
+ gradient:
+ "radial-gradient(130% 120% at 80% 18%, #3d8f7a, transparent 55%), linear-gradient(150deg, #16302a, #0e1c18)",
+ },
+ {
+ label: "Editorial",
+ gradient:
+ "radial-gradient(130% 120% at 30% 80%, #c98b5b, transparent 55%), linear-gradient(150deg, #2a2018, #15100b)",
+ },
+];
+
+export function MagicView() {
+ return (
+
+ {/* view header */}
+
+
Magic design
+ Describe it, get a full layout
+
+
+ {/* scrollable body */}
+
+ {/* hero */}
+
+
+ Describe the design you need.
+
+
+ An agent on your cluster lays it out with your brand kit, fonts, and colors. Pick one and keep editing on the canvas.
+
+
+
+ {/* prompt bar */}
+
+
+ a launch poster for taOS Studios, bold, dark, confident...
+
+
+
+ Generate
+
+
+
+ {/* style chips */}
+
+ {STYLE_CHIPS.map((chip) => (
+
+ {chip}
+
+ ))}
+
+
+ {/* generated result tiles */}
+
+ {RESULTS.map(({ label, gradient }) => (
+
+ ))}
+
+
+
+ );
+}
diff --git a/desktop/src/apps/designstudio/TemplatesView.tsx b/desktop/src/apps/designstudio/TemplatesView.tsx
new file mode 100644
index 00000000..09aa4ce9
--- /dev/null
+++ b/desktop/src/apps/designstudio/TemplatesView.tsx
@@ -0,0 +1,123 @@
+import { useState } from "react";
+
+const FILTER_PILLS = ["All", "Social", "Posters", "Presentations", "Logos", "Print"];
+
+const TEMPLATES: {
+ name: string;
+ caption: string;
+ size: string;
+ gradient: string;
+}[] = [
+ {
+ name: "Instagram Post",
+ caption: "Square post",
+ size: "1080x1080",
+ gradient: "linear-gradient(140deg, #2c3142, #171a24)",
+ },
+ {
+ name: "Story",
+ caption: "Vertical story",
+ size: "1080x1920",
+ gradient: "linear-gradient(140deg, #3d8f7a, #1d4d42)",
+ },
+ {
+ name: "Poster",
+ caption: "Event poster",
+ size: "1080x1350",
+ gradient: "linear-gradient(140deg, #5a6b86, #2b3447)",
+ },
+ {
+ name: "Presentation",
+ caption: "Slide deck",
+ size: "16:9",
+ gradient: "linear-gradient(140deg, #c98b5b, #7a4f2e)",
+ },
+ {
+ name: "Logo",
+ caption: "Brand mark",
+ size: "500x500",
+ gradient: "linear-gradient(140deg, #4a4150, #241c28)",
+ },
+ {
+ name: "Flyer",
+ caption: "A5 flyer",
+ size: "print",
+ gradient: "linear-gradient(140deg, #356270, #16323a)",
+ },
+ {
+ name: "Banner",
+ caption: "Web banner",
+ size: "1500x500",
+ gradient: "linear-gradient(140deg, #6b7689, #3a4151)",
+ },
+ {
+ name: "Business Card",
+ caption: "Card",
+ size: "print",
+ gradient: "linear-gradient(140deg, #7a5d8a, #3d2c47)",
+ },
+];
+
+export function TemplatesView() {
+ const [activeFilter, setActiveFilter] = useState("All");
+
+ return (
+
+ {/* view header */}
+
+
Templates
+ Start from a ready-made design
+
+
+ {/* scrollable body */}
+
+ {/* filter pills */}
+
+ {FILTER_PILLS.map((pill) => (
+ setActiveFilter(pill)}
+ className={`rounded-full px-[14px] py-[7px] text-[12px] font-semibold transition-colors ${
+ activeFilter === pill
+ ? "border-0 text-white"
+ : "border border-shell-border bg-shell-surface text-shell-text-secondary hover:border-shell-border-strong"
+ }`}
+ style={
+ activeFilter === pill
+ ? { background: "#8b92a3" }
+ : undefined
+ }
+ >
+ {pill}
+
+ ))}
+
+
+ {/* template grid */}
+
+ {TEMPLATES.map(({ name, caption, size, gradient }) => (
+
+
+ {name}
+
+
+ {caption}{" "}
+ · {size}
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/desktop/src/apps/musicstudio/ComposeView.tsx b/desktop/src/apps/musicstudio/ComposeView.tsx
new file mode 100644
index 00000000..1f353590
--- /dev/null
+++ b/desktop/src/apps/musicstudio/ComposeView.tsx
@@ -0,0 +1,111 @@
+import { Sparkles, Play } from "lucide-react";
+
+const STYLE_CHIPS = ["Lo-fi", "Cinematic", "House", "Ambient", "Drum and bass", "Hip-hop"];
+
+interface GeneratedResult {
+ bpm: number;
+ duration: string;
+ bars: number[];
+}
+
+const RESULTS: GeneratedResult[] = [
+ { bpm: 92, duration: "0:48", bars: [30, 60, 45, 80, 50, 70, 40, 90, 55, 65, 35, 75, 50, 60] },
+ { bpm: 90, duration: "1:02", bars: [50, 40, 70, 55, 85, 45, 60, 50, 75, 40, 65, 55, 80, 45] },
+ { bpm: 94, duration: "0:54", bars: [40, 55, 50, 65, 45, 75, 55, 60, 50, 70, 45, 80, 50, 60] },
+];
+
+export function ComposeView() {
+ return (
+
+ {/* view header */}
+
+
Compose
+
+ Describe a track, get a full arrangement
+
+
+
+
+ {/* hero */}
+
+
+ Hum it, or just describe it.
+
+
+ An agent on your cluster writes a multi-track arrangement you can open in the studio
+ and edit note by note. Apache-licensed models, nothing leaves your network.
+
+
+
+ {/* prompt bar */}
+
+
+ a warm lo-fi beat, 90 bpm, dusty drums, rhodes chords, vinyl crackle...
+
+
+
+ Generate
+
+
+
+ {/* style chips */}
+
+ {STYLE_CHIPS.map((chip, i) => (
+
+ {chip}
+
+ ))}
+
+
+ {/* generated results */}
+
+ {RESULTS.map((result, i) => (
+
+
+
+
+ {result.bars.map((h, bi) => (
+
+ ))}
+
+
+
+ {result.bpm} BPM - {result.duration}
+
+
Open
+
+ ))}
+
+
+
+ );
+}
diff --git a/desktop/src/apps/musicstudio/SoundsView.tsx b/desktop/src/apps/musicstudio/SoundsView.tsx
new file mode 100644
index 00000000..f063cc14
--- /dev/null
+++ b/desktop/src/apps/musicstudio/SoundsView.tsx
@@ -0,0 +1,133 @@
+const FILTER_PILLS = ["All", "Drums", "Bass", "Keys", "Synths", "FX"];
+
+interface SoundCard {
+ name: string;
+ category: string;
+ detail: string;
+ padGradient: string;
+ bars: number[];
+}
+
+const SOUNDS: SoundCard[] = [
+ {
+ name: "Boom Bap Kit",
+ category: "Drums",
+ detail: "24 hits",
+ padGradient: "linear-gradient(140deg, #3a2c24, #1d1611)",
+ bars: [40, 90, 30, 70, 45, 95, 35],
+ },
+ {
+ name: "Analog Bass",
+ category: "Bass",
+ detail: "synth",
+ padGradient: "linear-gradient(140deg, #23303f, #121b24)",
+ bars: [70, 50, 85, 45, 65],
+ },
+ {
+ name: "Rhodes Mk I",
+ category: "Keys",
+ detail: "electric piano",
+ padGradient: "linear-gradient(140deg, #223529, #101c15)",
+ bars: [55, 65, 50, 75, 55, 60],
+ },
+ {
+ name: "Warm Pad",
+ category: "Synths",
+ detail: "ambient",
+ padGradient: "linear-gradient(140deg, #2f2839, #171320)",
+ bars: [35, 45, 40, 50, 42],
+ },
+ {
+ name: "Pluck Lead",
+ category: "Synths",
+ detail: "mono",
+ padGradient: "linear-gradient(140deg, #3a3526, #1d1a11)",
+ bars: [80, 45, 90, 55, 70],
+ },
+ {
+ name: "Vinyl FX",
+ category: "FX",
+ detail: "texture",
+ padGradient: "linear-gradient(140deg, #34232c, #1a1116)",
+ bars: [30, 60, 35, 55],
+ },
+ {
+ name: "Sub 808",
+ category: "Bass",
+ detail: "808",
+ padGradient: "linear-gradient(140deg, #23303f, #121b24)",
+ bars: [60, 80, 50, 70, 55],
+ },
+ {
+ name: "Felt Piano",
+ category: "Keys",
+ detail: "acoustic",
+ padGradient: "linear-gradient(140deg, #223529, #101c15)",
+ bars: [50, 55, 65, 45, 60],
+ },
+];
+
+export function SoundsView() {
+ return (
+
+ {/* view header */}
+
+
Sounds
+
+ Instruments and samples, all offline
+
+
+
+
+ {/* filter pills */}
+
+ {FILTER_PILLS.map((pill, i) => (
+
+ {pill}
+
+ ))}
+
+
+ {/* sound card grid */}
+
+ {SOUNDS.map((sound) => (
+
+ {/* pad preview */}
+
+ {sound.bars.map((h, i) => (
+
+ ))}
+
+
+
{sound.name}
+
+ {sound.category} - {sound.detail}
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/desktop/src/apps/musicstudio/StudioView.tsx b/desktop/src/apps/musicstudio/StudioView.tsx
new file mode 100644
index 00000000..f566cb06
--- /dev/null
+++ b/desktop/src/apps/musicstudio/StudioView.tsx
@@ -0,0 +1,351 @@
+import { Square, Play, Circle, Check } from "lucide-react";
+
+/* Muted track color palette -- content, not chrome */
+const TRACK_COLORS = {
+ drum: "var(--ms-tk-drum, #c98b6b)",
+ bass: "var(--ms-tk-bass, #6f8aa8)",
+ keys: "var(--ms-tk-keys, #7faa90)",
+ pad: "var(--ms-tk-pad, #9a87b0)",
+ lead: "var(--ms-tk-lead, #c0a86a)",
+} as const;
+
+type TrackColor = keyof typeof TRACK_COLORS;
+
+interface Track {
+ id: string;
+ label: string;
+ color: TrackColor;
+ volume: number;
+ muted: boolean;
+}
+
+const TRACKS: Track[] = [
+ { id: "drum", label: "Drums", color: "drum", volume: 72, muted: false },
+ { id: "bass", label: "Bass", color: "bass", volume: 60, muted: false },
+ { id: "keys", label: "Keys", color: "keys", volume: 54, muted: false },
+ { id: "pad", label: "Pad", color: "pad", volume: 48, muted: true },
+ { id: "lead", label: "Lead", color: "lead", volume: 66, muted: false },
+];
+
+interface Clip {
+ trackId: string;
+ label: string;
+ left: number;
+ width: number;
+ opacity?: number;
+ bars: number[];
+}
+
+const CLIPS: Clip[] = [
+ { trackId: "drum", label: "Drums", left: 0, width: 288, bars: [40, 90, 30, 70, 40, 95, 30, 60, 40, 88, 30, 70] },
+ { trackId: "bass", label: "Bassline", left: 72, width: 216, bars: [60, 50, 80, 45, 70, 55, 85, 50] },
+ { trackId: "keys", label: "Rhodes", left: 144, width: 288, bars: [50, 65, 40, 75, 55, 60] },
+ { trackId: "pad", label: "Pad (muted)", left: 216, width: 360, opacity: 0.5, bars: [30, 35, 32, 38] },
+ { trackId: "lead", label: "Lead", left: 288, width: 180, bars: [80, 45, 90, 55, 70] },
+];
+
+const RULER_BARS = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+
+const PIANO_KEYS = [
+ { label: "C4", black: false },
+ { label: "B3", black: true },
+ { label: "A3", black: false },
+ { label: "G3", black: true },
+ { label: "F3", black: false },
+ { label: "E3", black: true },
+ { label: "D3", black: false },
+];
+
+interface PianoNote {
+ left: number;
+ top: number;
+ width: number;
+}
+
+const PIANO_NOTES: PianoNote[] = [
+ { left: 8, top: 14, width: 32 },
+ { left: 44, top: 46, width: 64 },
+ { left: 112, top: 14, width: 32 },
+ { left: 148, top: 78, width: 48 },
+ { left: 200, top: 46, width: 64 },
+ { left: 268, top: 30, width: 32 },
+ { left: 304, top: 62, width: 80 },
+];
+
+const KNOBS = ["Swing", "Drive", "Tone", "Width"];
+const FX_ROWS = [
+ { label: "Reverb", on: true },
+ { label: "Tape delay", on: false },
+ { label: "Sidechain", on: true },
+];
+
+export function StudioView() {
+ return (
+
+ {/* transport bar */}
+
+
+ {/* stop */}
+
+
+
+ {/* play */}
+
+
+
+ {/* record */}
+
+
+
+
+
+
+
+ 003 . 2 . 1
+
+
+ 92
+ BPM
+
+
+ 4/4
+ Time
+
+
+ A min
+ Key
+
+
+
+
+
+
+ Saved to Workspace
+
+
+
+
+ {/* arrange area */}
+
+ {/* track list column */}
+
+ {/* ruler label */}
+
+
+ Tracks
+
+
+
+ {TRACKS.map((track, i) => (
+
+
+
+
{track.label}
+
+
+ M
+
+
+ S
+
+
+
+
+
+
+
+ ))}
+
+
+ {/* scrolling timeline */}
+
+ {/* bar ruler */}
+
+ {RULER_BARS.map((b) => (
+
+ {b}
+
+ ))}
+
+
+ {/* lanes */}
+ {TRACKS.map((track) => {
+ const clip = CLIPS.find((c) => c.trackId === track.id);
+ return (
+
+ {clip && (
+
+
+ {clip.label}
+
+
+ {clip.bars.map((h, idx) => (
+
+ ))}
+
+
+ )}
+
+ );
+ })}
+
+ {/* playhead */}
+
+
+
+
+
+ {/* right inspector */}
+
+
+
+ Drums
+
+
+ taOS Drum Kit - Boom Bap
+
+
+
+ {KNOBS.map((label) => (
+
+ ))}
+
+
+
+ {FX_ROWS.map((fx) => (
+
+ ))}
+
+
+
+
+ {/* piano roll strip */}
+
+ {/* key labels */}
+
+ {PIANO_KEYS.map((k) => (
+
+ {k.label}
+
+ ))}
+
+
+ {/* note grid */}
+
+ {PIANO_NOTES.map((note, i) => (
+
+ ))}
+
+
+
+ );
+}
diff --git a/desktop/src/apps/officesuite/CalcView.tsx b/desktop/src/apps/officesuite/CalcView.tsx
new file mode 100644
index 00000000..6b4abce1
--- /dev/null
+++ b/desktop/src/apps/officesuite/CalcView.tsx
@@ -0,0 +1,213 @@
+import { Sparkles } from "lucide-react";
+
+const MONTHS = ["Jan", "Feb", "Mar", "Apr", "May"] as const;
+const BAR_HEIGHTS = [48, 60, 78, 70, 92] as const;
+
+const ROWS: { month: string; revenue: string; costs: string; profit: string }[] = [
+ { month: "January", revenue: "4,200", costs: "2,100", profit: "2,100" },
+ { month: "February", revenue: "5,100", costs: "2,300", profit: "2,800" },
+ { month: "March", revenue: "6,400", costs: "2,800", profit: "3,600" },
+ { month: "April", revenue: "5,900", costs: "2,600", profit: "3,300" },
+ { month: "May", revenue: "7,300", costs: "3,100", profit: "4,200" },
+];
+
+export function CalcView() {
+ return (
+
+ {/* formula bar */}
+
+ B7
+
+ =SUM(B2:B6)
+
+
+
+
+ {/* spreadsheet */}
+
+
+
+
+
+ {["A", "B", "C", "D"].map((col) => (
+
+ {col}
+
+ ))}
+
+
+
+ {/* header row */}
+
+
+ 1
+
+
+ Month
+
+
+ Revenue
+
+
+ Costs
+
+
+ Profit
+
+
+
+ {/* data rows */}
+ {ROWS.map((row, i) => (
+
+
+ {i + 2}
+
+
+ {row.month}
+
+
+ {row.revenue}
+
+
+ {row.costs}
+
+
+ {row.profit}
+
+
+ ))}
+
+ {/* total row */}
+
+
+ 7
+
+
+ Total
+
+
+ 28,900
+
+
+ 12,900
+
+
+ 16,000
+
+
+
+
+
+
+ {/* right sidebar */}
+
+ {/* bar chart card */}
+
+
Revenue by month
+
+ {BAR_HEIGHTS.map((h, i) => (
+
+ ))}
+
+
+ {MONTHS.map((m) => (
+
+ {m}
+
+ ))}
+
+
+
+ {/* ask your data */}
+
+
+
+ Ask your data
+
+
+ “Which month had the best margin?” taOS reads the sheet and answers, on
+ your hardware.
+
+
+
+
+
+ );
+}
diff --git a/desktop/src/apps/officesuite/SlidesView.tsx b/desktop/src/apps/officesuite/SlidesView.tsx
new file mode 100644
index 00000000..13defcae
--- /dev/null
+++ b/desktop/src/apps/officesuite/SlidesView.tsx
@@ -0,0 +1,160 @@
+import { Sparkles } from "lucide-react";
+
+const SLIDES = [
+ {
+ idx: 1,
+ label: "Build it your way",
+ bg: "radial-gradient(120% 130% at 18% 14%,#4a5572,transparent 55%),linear-gradient(150deg,#262c3b,#14161f)",
+ },
+ { idx: 2, label: "Ready today", bg: "linear-gradient(150deg,#1d3a33,#0f1f1b)" },
+ { idx: 3, label: "On the way", bg: "linear-gradient(150deg,#3a2f1d,#1f190f)" },
+ { idx: 4, label: "Your hardware", bg: "linear-gradient(150deg,#2c2436,#16111d)" },
+ { idx: 5, label: "Get started", bg: "linear-gradient(150deg,#23303f,#121b24)" },
+] as const;
+
+const LAYOUTS = [
+ { id: "title", active: true, barWidths: ["70%", "90%"] },
+ { id: "split", active: false, barWidths: ["50%", "90%"] },
+ { id: "center", active: false, barWidths: ["40%"] },
+] as const;
+
+export function SlidesView() {
+ return (
+
+ {/* slide thumbnail rail */}
+
+
+ {/* slide canvas stage */}
+
+
+
+ taOS Studios
+
+
+ Build it your way.
+
+
+ Dedicated studios for every project, running on hardware you already own.
+
+ {/* selection box */}
+
+
+
+
+ {/* right panel */}
+
+ {/* generate a deck */}
+
+
+
+ Generate a deck
+
+
+ Describe the talk and taOS drafts the slides, on brand.
+
+
+ a 5-slide intro to taOS Studios for new users…
+
+
+
+ Generate
+
+
+
+ {/* layout picker */}
+
+ Layout
+
+
+ {LAYOUTS.map((lay) => (
+
+ {lay.barWidths.map((w, i) => (
+
+ ))}
+
+ ))}
+
+
+
+ );
+}
diff --git a/desktop/src/apps/officesuite/WriteView.tsx b/desktop/src/apps/officesuite/WriteView.tsx
new file mode 100644
index 00000000..bbf57e1f
--- /dev/null
+++ b/desktop/src/apps/officesuite/WriteView.tsx
@@ -0,0 +1,152 @@
+import {
+ Sparkles,
+ AlignLeft,
+ AlignCenter,
+ Pencil,
+ Scissors,
+ ArrowRight,
+ AlignJustify,
+} from "lucide-react";
+
+const AI_OPTIONS: { label: string; desc: string; Icon: typeof Sparkles }[] = [
+ { label: "Rewrite", desc: "Clearer, same meaning", Icon: Pencil },
+ { label: "Shorten", desc: "Tighten the selection", Icon: Scissors },
+ { label: "Continue writing", desc: "Pick up where you left off", Icon: ArrowRight },
+ { label: "Change tone", desc: "Friendly, formal, punchy", Icon: AlignJustify },
+];
+
+export function WriteView() {
+ return (
+
+ {/* formatting toolbar */}
+
+
+ Sohne ▾
+
+
+
+ B
+
+
+ I
+
+
+ U
+
+
+
+
+
+
+
+
+
+
+
+ Assist
+
+
+
+ {/* document area + AI panel */}
+
+ {/* document scroll area */}
+
+
+
+ taOS Studios launch note
+
+
+ Draft · updated just now
+
+
+ taOS now ships a family of creative studios, each a focused workspace that runs
+ entirely on hardware you already own.{" "}
+
+ Whether you are building a business, a hobby project, or something just for the
+ house
+
+ , there is a studio with the tools you need.
+
+
+ What is ready today
+
+
+ Images Studio and Game Studio are available now. Coding Studio is rolling out, with
+ Design, Music, App, and Office studios close behind. Each one installs from the Store
+ in a single click.
+
+
+ Everything runs offline by default, on your cluster, with nothing leaving your network
+ unless you choose to share it.
+
+
+
+
+ {/* AI panel */}
+
+
+
+ );
+}
diff --git a/desktop/src/registry/app-registry.ts b/desktop/src/registry/app-registry.ts
index 304a32ed..592d9a46 100644
--- a/desktop/src/registry/app-registry.ts
+++ b/desktop/src/registry/app-registry.ts
@@ -42,6 +42,11 @@ const apps: AppManifest[] = [
{ id: "tasks", name: "Tasks", icon: "calendar-clock", category: "platform", component: () => import("@/apps/TasksApp").then((m) => ({ default: m.TasksApp })), defaultSize: { w: 800, h: 500 }, minSize: { w: 450, h: 350 }, singleton: true, pinned: false, launchpadOrder: 11 },
{ id: "import", name: "Import", icon: "upload", category: "platform", component: () => import("@/apps/ImportApp").then((m) => ({ default: m.ImportApp })), defaultSize: { w: 700, h: 450 }, minSize: { w: 400, h: 300 }, singleton: true, pinned: false, launchpadOrder: 12 },
{ id: "images", name: "Images", icon: "image", category: "platform", component: () => import("@/apps/ImagesApp").then((m) => ({ default: m.ImagesApp })), defaultSize: { w: 900, h: 600 }, minSize: { w: 500, h: 400 }, singleton: true, pinned: false, launchpadOrder: 13 },
+ { id: "coding-studio", name: "Coding Studio", icon: "code-2", category: "platform", component: () => import("@/apps/CodingStudioApp").then((m) => ({ default: m.CodingStudioApp })), defaultSize: { w: 1080, h: 760 }, minSize: { w: 680, h: 540 }, singleton: true, pinned: false, launchpadOrder: 13.25, optional: true },
+ { id: "design-studio", name: "Design Studio", icon: "palette", category: "platform", component: () => import("@/apps/DesignStudioApp").then((m) => ({ default: m.DesignStudioApp })), defaultSize: { w: 1080, h: 720 }, minSize: { w: 680, h: 520 }, singleton: true, pinned: false, launchpadOrder: 13.26, optional: true },
+ { id: "music-studio", name: "Music Studio", icon: "music", category: "platform", component: () => import("@/apps/MusicStudioApp").then((m) => ({ default: m.MusicStudioApp })), defaultSize: { w: 1080, h: 720 }, minSize: { w: 700, h: 540 }, singleton: true, pinned: false, launchpadOrder: 13.27, optional: true },
+ { id: "app-studio", name: "App Studio", icon: "blocks", category: "platform", component: () => import("@/apps/AppStudioApp").then((m) => ({ default: m.AppStudioApp })), defaultSize: { w: 1080, h: 720 }, minSize: { w: 680, h: 520 }, singleton: true, pinned: false, launchpadOrder: 13.28, optional: true },
+ { id: "office-suite", name: "Office Suite", icon: "file-text", category: "platform", component: () => import("@/apps/OfficeSuiteApp").then((m) => ({ default: m.OfficeSuiteApp })), defaultSize: { w: 1080, h: 720 }, minSize: { w: 680, h: 520 }, singleton: true, pinned: false, launchpadOrder: 13.29, optional: true },
{ id: "library", name: "Library", icon: "book-open", category: "platform", component: () => import("@/apps/LibraryApp").then((m) => ({ default: m.LibraryApp })), defaultSize: { w: 1000, h: 650 }, minSize: { w: 550, h: 400 }, singleton: true, pinned: true, launchpadOrder: 13.5 },
{ id: "reddit", name: "Reddit", icon: "scroll-text", category: "platform", component: () => import("@/apps/RedditApp").then((m) => ({ default: m.RedditApp })), defaultSize: { w: 1000, h: 650 }, minSize: { w: 550, h: 400 }, singleton: true, pinned: false, launchpadOrder: 14, optional: true },
{ id: "youtube-library", name: "YouTube", icon: "play-circle", category: "platform", component: () => import("@/apps/YouTubeApp").then((m) => ({ default: m.YouTubeApp })), defaultSize: { w: 1050, h: 700 }, minSize: { w: 600, h: 450 }, singleton: true, pinned: false, launchpadOrder: 14.5, optional: true },
diff --git a/tinyagentos/routes/apps.py b/tinyagentos/routes/apps.py
index 80e2d409..081bd875 100644
--- a/tinyagentos/routes/apps.py
+++ b/tinyagentos/routes/apps.py
@@ -26,7 +26,12 @@
# runtime location). The frontend owns name/icon/cover; the backend only tracks
# which ids are installed, gated to this allowlist so the endpoint can't be used
# to write arbitrary install rows.
-OPTIONAL_FRONTEND_APPS = {"reddit", "youtube-library", "github-browser", "x-monitor"}
+OPTIONAL_FRONTEND_APPS = {
+ "reddit", "youtube-library", "github-browser", "x-monitor",
+ # Creative Studios install the same way: a frontend-only optional app whose
+ # install row just flips the launcher visibility, no service spawned.
+ "coding-studio", "design-studio", "music-studio", "app-studio", "office-suite",
+}
_FRONTEND_APP_KIND = "frontend-app"