diff --git a/docs/src/tutorial/hello-world.md b/docs/src/tutorial/hello-world.md
index 07a2d5df..441e6b4e 100644
--- a/docs/src/tutorial/hello-world.md
+++ b/docs/src/tutorial/hello-world.md
@@ -4,7 +4,7 @@
使用[@vue/cli](https://cli.vuejs.org/zh/guide/installation.html)初始化项目
-```
+```bash
npm install -g @vue/cli
```
@@ -24,7 +24,7 @@ npm install -g @vue/cli
[关于@vue/cli的详细教程可以查看官方文档](https://cli.vuejs.org/zh/guide/installation.html)
-```
+```bash
vue create hello-world
cd hello-world
@@ -50,7 +50,7 @@ cd hello-world
## 添加依赖
-```
+```bash
npm install --save @tmagic/editor @tmagic/form element-plus
```
@@ -119,7 +119,7 @@ body {
## 运行项目
-```
+```bash
npm run serve
```
diff --git a/docs/src/tutorial/runtime.md b/docs/src/tutorial/runtime.md
index 77d609fb..c15f3ce7 100644
--- a/docs/src/tutorial/runtime.md
+++ b/docs/src/tutorial/runtime.md
@@ -1 +1,203 @@
-# 2.Runtime
\ No newline at end of file
+# 2.Runtime
+
+## 创建项目
+
+[关于@vue/cli的详细教程可以查看官方文档](https://cli.vuejs.org/zh/guide/installation.html)
+
+### 创建editor项目
+
+将[上一教程](./hello-world.md)中的[hello-world](https://github.com/jia000/tmagic-tutorial/tree/master/course1/hello-world)复制过来,改名hello-editor
+
+
+### 创建runtime项目
+
+```bash
+vue create editor-runtime
+
+cd editor-runtime
+```
+
+删除src/components/HelloWorld.vue
+
+## 实现runtime
+
+将hello-editor中的render函数实现移植到runtime项目中
+
+新建ui-page.vue文件
+
+```vue
+
+
+
+
+
+```
+
+将以下代码覆盖到src/App.vue中
+
+```vue
+
+
+
+
+
+```
+
+## 启动runtime
+
+```bash
+npm run serve -- --port=8078
+```
+
+## 修改editor
+
+删除render props,添加runtimeUrl
+
+修改样式
+
+```vue
+
+
+
+
+
+
+
+```
+
+## 启动editor
+
+```bash
+cd hello-editor
+
+npm run serve -- --port=8080
+```
+
+## 跨域问题
+
+在editor-runtime项目下的vue.config.js中添加如下配置
+
+```javascript
+devServer: {
+ headers: {
+ 'Access-Control-Allow-Origin': '*',
+ },
+},
+```
+
+## runtime与editor通信
+
+到这里项目就可以正常访问了,但是会发现添加组件没有反应。
+
+这是因为在runtime中无法直接获取到editor中的dsl,所以需要通过editor注入到window的magic api来交互
+
+在App.vue中通过监听message,来准备知道magic注入时机,然后调用magic.onRuntimeReady,示例代码如下
+
+```ts
+const root = ref();
+
+window.addEventListener('message', ({ data }) => {
+ if (!data.tmagicRuntimeReady) {
+ return;
+ }
+
+ (window as any).magic?.onRuntimeReady({
+ /** 当编辑器的dsl对象变化时会调用 */
+ updateRootConfig(config: any) {
+ root.value = config;
+ },
+
+ /** 当编辑器的切换页面时会调用 */
+ updatePageId(id: string) {
+ page.value = root.value?.items?.find((item: any) => item.id === id);
+ },
+
+ /** 新增组件时调用 */
+ add({ config }: any) {
+ const parent = config.type === 'page' ? root.value : page.value;
+ parent.items?.push(config);
+ },
+
+ /** 更新组件时调用 */
+ update({ config }: any) {
+ const index = page.value.items?.findIndex((child: any) => child.id === config.id);
+ page.value.items.splice(index, 1, reactive(config));
+ },
+
+ /** 删除组件时调用 */
+ remove({ id }: any) {
+ const index = page.value.items?.findIndex((child: any) => child.id === id);
+ page.value.items.splice(index, 1);
+ },
+ });
+});
+
+```
+
+## 同步页面dom给编辑器
+
+由于组件渲染在runtime中,对于编辑器来说是个黑盒,并不知道哪个dom节点才是页面(对于dsl的解析渲染可能是千奇百怪的),所以需要将页面的dom节点同步给编辑器
+
+```ts
+watch(page, async () => {
+ // page配置变化后,需要等dom更新
+ await nextTick();
+ (window as any).magic.onPageElUpdate(pageComp.value?.$el);
+});
+```
+
+以上就是一个简单runtime实现,以及与编辑的交互,这是一个不完善的实现,但是其中已经几乎覆盖所有需要关心的内容
+
+当前教程中实现了一个简单的page,tmagic提供了一个比较完善的实现,将在下一节介绍