diff --git a/src/lib/serial/index.ts b/src/lib/serial/index.ts
new file mode 100644
index 0000000..dba1c5e
--- /dev/null
+++ b/src/lib/serial/index.ts
@@ -0,0 +1,2 @@
+export * from './serial.service';
+export * from './serial.types';
diff --git a/src/lib/serial/serial.providers.svelte b/src/lib/serial/serial.providers.svelte
new file mode 100644
index 0000000..c630296
--- /dev/null
+++ b/src/lib/serial/serial.providers.svelte
@@ -0,0 +1,103 @@
+
+
+{@render children?.()}
diff --git a/src/lib/serial/serial.service.ts b/src/lib/serial/serial.service.ts
new file mode 100644
index 0000000..5f77530
--- /dev/null
+++ b/src/lib/serial/serial.service.ts
@@ -0,0 +1,108 @@
+// src/lib/serial/serial.service.ts
+// Web Serial API implementation
+// Requires: @types/w3c-web-serial
+
+/**
+ * 内部IO资源
+ */
+let reader: ReadableStreamDefaultReader | null = null;
+let writer: WritableStreamDefaultWriter | null = null;
+
+let isOpen = false;
+
+/**
+ * 判断当前环境是否支持Web Serial API
+ */
+export function isWebSerialSupported(): boolean {
+ return typeof navigator !== 'undefined' && 'serial' in navigator;
+}
+
+/**
+ * 请求用户选择串口设备
+ */
+export async function requestPort(
+ filters?: SerialPortRequestOptions['filters']
+): Promise {
+ if (!isWebSerialSupported()) {
+ throw new Error('Web Serial API is not supported in this environment.');
+ }
+
+ const port = await navigator.serial.requestPort(
+ filters ? { filters } : undefined
+ );
+
+ return port ?? null;
+}
+
+/**
+ * 打开串口
+ */
+export async function openPort(
+ port: SerialPort,
+ options: SerialOptions
+): Promise {
+ if (isOpen) {
+ // 串口已经打开,直接返回
+ return;
+ }
+
+ await port.open(options);
+ isOpen = true;
+
+ // 初始化reader和writer
+ reader = port.readable?.getReader() ?? null;
+ writer = port.writable?.getWriter() ?? null;
+}
+
+/**
+ * 关闭串口
+ */
+export async function closePort(port: SerialPort) {
+ if (!isOpen) {
+ // 串口未打开,直接返回
+ return;
+ }
+
+ await reader?.cancel();
+ reader?.releaseLock();
+ await writer?.close();
+ writer?.releaseLock();
+
+ reader = null;
+ writer = null;
+ isOpen = false;
+
+ await port.close();
+}
+
+/**
+ * 向串口写入数据
+ */
+export async function write(data: Uint8Array): Promise {
+ if (!writer) {
+ throw new Error('Serial port is not writable.');
+ }
+ await writer.write(data);
+}
+
+/**
+ * 开始读取串口数据循环
+ */
+export async function startReadLoop(
+ onData: (chunk: Uint8Array) => void,
+ onError?: (err: unknown) => void
+): Promise {
+ if (!reader) {
+ throw new Error('Serial port is not readable.');
+ }
+
+ try {
+ while (true) {
+ const { value, done } = await reader.read();
+ if (done) break;
+ if (value) onData(value);
+ }
+ } catch (err) {
+ onError?.(err);
+ }
+}
diff --git a/src/lib/serial/serial.store.ts b/src/lib/serial/serial.store.ts
new file mode 100644
index 0000000..23a1cbb
--- /dev/null
+++ b/src/lib/serial/serial.store.ts
@@ -0,0 +1,13 @@
+import { writable } from 'svelte/store';
+import { createContext } from 'svelte';
+import type { SerialState, SerialContext } from './serial.types';
+
+export const serialState = writable({
+ port: null,
+ portName: null,
+ status: 'idle',
+ error: undefined,
+});
+
+export const [getSerialContext, setSerialContext] =
+ createContext();
diff --git a/src/lib/serial/serial.types.ts b/src/lib/serial/serial.types.ts
new file mode 100644
index 0000000..393dace
--- /dev/null
+++ b/src/lib/serial/serial.types.ts
@@ -0,0 +1,24 @@
+import type { Readable } from 'svelte/store';
+
+export type SerialStatus =
+ | 'idle'
+ | 'requesting'
+ | 'connecting'
+ | 'connected'
+ | 'disconnecting'
+ | 'error';
+
+export type SerialState = {
+ port: SerialPort | null;
+ portName: string | null;
+ status: SerialStatus;
+ error?: string;
+};
+
+export type SerialContext = {
+ state: Readable;
+ requestPort: () => Promise;
+ openPort: (options: SerialOptions) => Promise;
+ reopenPort: (options: SerialOptions) => Promise;
+ closePort: () => Promise;
+};
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
index e801ec7..b200ce1 100644
--- a/src/routes/+layout.svelte
+++ b/src/routes/+layout.svelte
@@ -1,9 +1,13 @@
-{@render children()}
+
+
+ {@render children()}
+