diff --git a/components.d.ts b/components.d.ts
index e4682712..1c185756 100644
--- a/components.d.ts
+++ b/components.d.ts
@@ -50,6 +50,7 @@ declare module '@vue/runtime-core' {
     'CModal.demo': typeof import('./src/ui/c-modal/c-modal.demo.vue')['default']
     CModalValue: typeof import('./src/ui/c-modal-value/c-modal-value.vue')['default']
     'CModalValue.demo': typeof import('./src/ui/c-modal-value/c-modal-value.demo.vue')['default']
+    CMonacoEditor: typeof import('./src/ui/c-monaco-editor/c-monaco-editor.vue')['default']
     CollapsibleToolMenu: typeof import('./src/components/CollapsibleToolMenu.vue')['default']
     ColorConverter: typeof import('./src/tools/color-converter/color-converter.vue')['default']
     ColoredCard: typeof import('./src/components/ColoredCard.vue')['default']
diff --git a/package.json b/package.json
index 8fe222d2..2e3eb5c2 100644
--- a/package.json
+++ b/package.json
@@ -35,6 +35,7 @@
     "release": "node ./scripts/release.mjs"
   },
   "dependencies": {
+    "@guolao/vue-monaco-editor": "^1.4.1",
     "@it-tools/bip39": "^0.0.4",
     "@it-tools/oggen": "^1.3.0",
     "@sindresorhus/slugify": "^2.2.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index e8f30939..b0bf9bb3 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -5,6 +5,9 @@ settings:
   excludeLinksFromLockfile: false
 
 dependencies:
+  '@guolao/vue-monaco-editor':
+    specifier: ^1.4.1
+    version: 1.5.1(monaco-editor@0.43.0)(vue@3.3.4)
   '@it-tools/bip39':
     specifier: ^0.0.4
     version: 0.0.4
@@ -2153,6 +2156,22 @@ packages:
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     dev: true
 
+  /@guolao/vue-monaco-editor@1.5.1(monaco-editor@0.43.0)(vue@3.3.4):
+    resolution: {integrity: sha512-nhbQHDAwsxrdH/yitcrBgAkN8Cae0IEiYe/M3LWK8bSJRfapkbMyfTHE6Gcxsxa/6efSUZAPDo8dJWBDx5GZyA==}
+    peerDependencies:
+      '@vue/composition-api': ^1.7.1
+      monaco-editor: '>=0.43.0'
+      vue: ^2.6.14 || >=3.0.0
+    peerDependenciesMeta:
+      '@vue/composition-api':
+        optional: true
+    dependencies:
+      '@monaco-editor/loader': 1.4.0(monaco-editor@0.43.0)
+      monaco-editor: 0.43.0
+      vue: 3.3.4
+      vue-demi: 0.14.7(vue@3.3.4)
+    dev: false
+
   /@humanwhocodes/config-array@0.11.10:
     resolution: {integrity: sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==}
     engines: {node: '>=10.10.0'}
@@ -2420,6 +2439,15 @@ packages:
     resolution: {integrity: sha512-mrC4y8n88BYvgcgzq9bvTlDgFyi2zuvzmPilRvRc3Uz1iIvq8mDhxJ0rHKFUNzPEScpDvJdIujqiDrulMqiudA==}
     dev: true
 
+  /@monaco-editor/loader@1.4.0(monaco-editor@0.43.0):
+    resolution: {integrity: sha512-00ioBig0x642hytVspPl7DbQyaSWRaolYie/UFNjoTdvoKPzo6xrXLhTk9ixgIKcLH5b5vDOjVNiGyY+uDCUlg==}
+    peerDependencies:
+      monaco-editor: '>= 0.21.0 < 1'
+    dependencies:
+      monaco-editor: 0.43.0
+      state-local: 1.0.7
+    dev: false
+
   /@nodelib/fs.scandir@2.1.5:
     resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
     engines: {node: '>= 8'}
@@ -8218,6 +8246,10 @@ packages:
     resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
     dev: true
 
+  /state-local@1.0.7:
+    resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==}
+    dev: false
+
   /std-env@3.3.3:
     resolution: {integrity: sha512-Rz6yejtVyWnVjC1RFvNmYL10kgjC49EOghxWn0RFqlCHGFpQx+Xe7yW3I4ceK1SGrWIGMjD5Kbue8W/udkbMJg==}
     dev: true
diff --git a/src/main.ts b/src/main.ts
index 36ba3b7f..cdd79132 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -2,6 +2,9 @@ import { createApp } from 'vue';
 import { createPinia } from 'pinia';
 import { createHead } from '@vueuse/head';
 
+import { install as VueMonacoEditorPlugin, loader } from '@guolao/vue-monaco-editor';
+import * as monaco from 'monaco-editor';
+
 import { registerSW } from 'virtual:pwa-register';
 import { plausible } from './plugins/plausible.plugin';
 
@@ -13,10 +16,14 @@ import App from './App.vue';
 import router from './router';
 import { i18nPlugin } from './plugins/i18n.plugin';
 
+// loaded monaco-editor from `node_modules`
+loader.config({ monaco });
+
 registerSW();
 
 const app = createApp(App);
 
+app.use(VueMonacoEditorPlugin);
 app.use(createPinia());
 app.use(createHead());
 app.use(i18nPlugin);
diff --git a/src/ui/c-monaco-editor/c-monaco-editor.vue b/src/ui/c-monaco-editor/c-monaco-editor.vue
new file mode 100644
index 00000000..e3b53437
--- /dev/null
+++ b/src/ui/c-monaco-editor/c-monaco-editor.vue
@@ -0,0 +1,124 @@
+
+
+
+
+
+   emits('beforeMount', monaco)"
+    @mount="(editor: monacoEditor.editor.IStandaloneCodeEditor, monaco: MonacoEditor) => emits('mount', editor, monaco)"
+    @change="(value: string | undefined, event: monacoEditor.editor.IModelContentChangedEvent) => emits('change', value, event)"
+    @validate="(markers: monacoEditor.editor.IMarker[]) => emits('validate', markers)"
+  />
+