├── styles.css ├── .gitignore ├── versions.json ├── .github └── workflows │ ├── main.yml │ └── publish.yml ├── manifest.json ├── .eslintrc.js ├── tsconfig.json ├── rollup.config.js ├── package.json ├── LICENSE ├── README.md ├── main.ts └── kroki-test.md /styles.css: -------------------------------------------------------------------------------- 1 | .settings_area { 2 | margin-left: 5px; 3 | margin-right: 5px; 4 | font-size: 14px; 5 | width: 100%; 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Intellij 2 | *.iml 3 | .idea 4 | 5 | # npm 6 | node_modules 7 | package-lock.json 8 | 9 | # build 10 | main.js 11 | *.js.map 12 | 13 | # data / settings 14 | data.json -------------------------------------------------------------------------------- /versions.json: -------------------------------------------------------------------------------- 1 | { 2 | "1.0.0": "0.12.5", 3 | "1.1.0": "0.12.5", 4 | "1.1.1": "0.12.5", 5 | "1.2.0": "0.12.5", 6 | "1.2.1": "0.12.5", 7 | "1.2.2": "0.12.5", 8 | "1.2.3": "0.13.25", 9 | "1.2.4": "0.13.25" 10 | } -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | branches: [master] 8 | 9 | jobs: 10 | lint-and-test: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | 15 | - name: Install modules 16 | run: yarn 17 | 18 | - name: Lint 19 | run: yarn run lint 20 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "obsidian-kroki", 3 | "name": "Kroki", 4 | "version": "1.2.4", 5 | "minAppVersion": "0.13.25", 6 | "description": "Render Mermaid, PlantUML, GraphViz, D2, Excalidraw, Vega, Pikchr, WireViz, Structurizr and many others diagrams using Kroki", 7 | "author": "Greg Zuro", 8 | "authorUrl": "https://github.com/gregzuro/", 9 | "isDesktopOnly": false 10 | } 11 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: "@typescript-eslint/parser", 4 | plugins: ["@typescript-eslint"], 5 | extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"], 6 | rules: { 7 | "@typescript-eslint/no-unused-vars": [ 8 | 2, 9 | { args: "all", argsIgnorePattern: "^_" }, 10 | ], 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "inlineSourceMap": true, 5 | "inlineSources": true, 6 | "module": "ESNext", 7 | "target": "es6", 8 | "allowJs": true, 9 | "noImplicitAny": true, 10 | "moduleResolution": "node", 11 | "importHelpers": true, 12 | "lib": [ 13 | "dom", 14 | "es5", 15 | "scripthost", 16 | "es2015", 17 | "esnext" 18 | ] 19 | }, 20 | "include": [ 21 | "**/*.ts" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import typescript from '@rollup/plugin-typescript'; 2 | import {nodeResolve} from '@rollup/plugin-node-resolve'; 3 | import commonjs from '@rollup/plugin-commonjs'; 4 | 5 | const banner = 6 | `/* 7 | THIS IS A GENERATED/BUNDLED FILE BY ROLLUP 8 | if you want to view the source visit the plugins github repository 9 | */ 10 | `; 11 | 12 | export default { 13 | input: 'main.ts', 14 | output: { 15 | dir: '.', 16 | sourcemap: 'inline', 17 | format: 'cjs', 18 | exports: 'default', 19 | banner, 20 | }, 21 | external: ['obsidian'], 22 | plugins: [ 23 | typescript(), 24 | nodeResolve({browser: true}), 25 | commonjs(), 26 | ] 27 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "obsidian-kroki", 3 | "version": "1.2.4", 4 | "description": "Kroki rendering for obsidian.md", 5 | "main": "main.js", 6 | "scripts": { 7 | "dev": "rollup --config rollup.config.js -w", 8 | "build": "rollup --config rollup.config.js", 9 | "lint": "eslint . --ext .ts" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "MIT", 14 | "devDependencies": { 15 | "@rollup/plugin-commonjs": "^15.1.0", 16 | "@rollup/plugin-node-resolve": "^9.0.0", 17 | "@rollup/plugin-typescript": "^6.0.0", 18 | "@types/node": "^14.14.2", 19 | "@typescript-eslint/eslint-plugin": "^4.18.0", 20 | "@typescript-eslint/parser": "^4.18.0", 21 | "eslint": "^7.22.0", 22 | "obsidian": "https://github.com/obsidianmd/obsidian-api/tarball/master", 23 | "rollup": "^2.32.1", 24 | "tslib": "^2.0.3", 25 | "typescript": "^4.0.3", 26 | "@types/pako": "^1.0.1", 27 | "pako": "^1.0.10" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Greg Zuro 4 | Copyright (c) 2021 Johannes Theiner 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Obsidian Kroki 2 | 3 | Render [Kroki](https://kroki.io) Diagrams in [Obsidian](https://obsidian.md). 4 | 5 | This plugin uses, by default, the [Kroki](https://kroki.io) server for rendering, but specifying an alternate one via this plugin's options is encouraged. 6 | 7 | If you can't find an alternate, then you can host your own server as [described here](https://kroki.io/#install). 8 | 9 | This plugin is a modified and slightly expanded version of the [obsidian-plantuml](https://github.com/joethei/obsidian-plantuml) plugin by Johannes Theiner. 10 | 11 | ## Usage 12 | Create a fenced codeblock using one of the diagram types supported by kroki as the language. 13 | See the [Kroki site](https://kroki.io) for a complete list of supported diagram types. 14 | Specify your diagram code inside the codeblock. 15 | 16 | ## Examples 17 | 18 | See [kroki-test.md](kroki-test.md) for examples of each of the currently supported diagram types. 19 | 20 | ## Installation 21 | 22 | ### Inside Obsidian 23 | 24 | `Settings > Third-party plugins > Community Plugins > Browse` and search for `Kroki`. 25 | 26 | ### Manually installing the plugin 27 | 28 | - Clone this repo 29 | - `npm i` or `yarn` to install dependencies 30 | - `npm run build` 31 | - Copy over `main.js`, `styles.css`, `manifest.json` to your vault `VaultFolder/.obsidian/plugins/obsidian-kroki/`. 32 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Build plugin 2 | 3 | on: 4 | push: 5 | # Sequence of patterns matched against refs/tags 6 | tags: 7 | - "*" # Push events to matching any tag format, i.e. 1.0, 20.15.10 8 | 9 | env: 10 | PLUGIN_NAME: obsidian-kroki 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | - name: Use Node.js 19 | uses: actions/setup-node@v1 20 | with: 21 | node-version: "14.x" # You might need to adjust this value to your own version 22 | - name: Build 23 | id: build 24 | run: | 25 | npm install -g yarn 26 | yarn 27 | yarn run build --if-present 28 | mkdir ${{ env.PLUGIN_NAME }} 29 | cp main.js manifest.json ${{ env.PLUGIN_NAME }} 30 | zip -r ${{ env.PLUGIN_NAME }}.zip ${{ env.PLUGIN_NAME }} 31 | ls 32 | echo "::set-output name=tag_name::$(git tag --sort version:refname | tail -n 1)" 33 | - name: Create Release 34 | id: create_release 35 | uses: actions/create-release@v1 36 | env: 37 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 38 | VERSION: ${{ github.ref }} 39 | with: 40 | tag_name: ${{ github.ref }} 41 | release_name: ${{ github.ref }} 42 | draft: false 43 | prerelease: false 44 | - name: Upload zip file 45 | id: upload-zip 46 | uses: actions/upload-release-asset@v1 47 | env: 48 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 49 | with: 50 | upload_url: ${{ steps.create_release.outputs.upload_url }} 51 | asset_path: ./${{ env.PLUGIN_NAME }}.zip 52 | asset_name: ${{ env.PLUGIN_NAME }}-${{ steps.build.outputs.tag_name }}.zip 53 | asset_content_type: application/zip 54 | - name: Upload main.js 55 | id: upload-main 56 | uses: actions/upload-release-asset@v1 57 | env: 58 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 59 | with: 60 | upload_url: ${{ steps.create_release.outputs.upload_url }} 61 | asset_path: ./main.js 62 | asset_name: main.js 63 | asset_content_type: text/javascript 64 | - name: Upload manifest.json 65 | id: upload-manifest 66 | uses: actions/upload-release-asset@v1 67 | env: 68 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 69 | with: 70 | upload_url: ${{ steps.create_release.outputs.upload_url }} 71 | asset_path: ./manifest.json 72 | asset_name: manifest.json 73 | asset_content_type: application/json 74 | - name: Upload styles.css 75 | id: upload-styles 76 | uses: actions/upload-release-asset@v1 77 | env: 78 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 79 | with: 80 | upload_url: ${{ steps.create_release.outputs.upload_url }} 81 | asset_path: ./styles.css 82 | asset_name: styles.css 83 | asset_content_type: text/css 84 | -------------------------------------------------------------------------------- /main.ts: -------------------------------------------------------------------------------- 1 | import { App, MarkdownPostProcessorContext, Plugin, PluginSettingTab, Setting, ToggleComponent, request } from 'obsidian'; 2 | 3 | import * as pako from 'pako'; 4 | 5 | interface KrokiSettings { 6 | server_url: string, 7 | header: string; 8 | diagramTypes: { 9 | prettyName: string; 10 | krokiBlockName: string; 11 | obsidianBlockName: string; 12 | description: string; 13 | url: string; 14 | enabled: boolean; 15 | toggle: ToggleComponent; 16 | }[] 17 | } 18 | 19 | const DEFAULT_SETTINGS: KrokiSettings = { 20 | server_url: 'https://kroki.io/', 21 | header: '', 22 | diagramTypes: [ 23 | { prettyName: "BlockDiag", krokiBlockName: "blockdiag", obsidianBlockName: "blockdiag", description: "block diag !!", url: "https://github.com/blockdiag/blockdiag", enabled: true, toggle: null }, 24 | { prettyName: "BPMN", krokiBlockName: "bpmn", obsidianBlockName: "bpmn", description: "", url: "https://github.com/bpmn-io/bpmn-js", enabled: true, toggle: null }, 25 | { prettyName: "Bytefield", krokiBlockName: "bytefield", obsidianBlockName: "bytefield", description: "", url: "https://github.com/Deep-Symmetry/bytefield-svg/", enabled: true, toggle: null }, 26 | { prettyName: "SeqDiag", krokiBlockName: "seqdiag", obsidianBlockName: "seqdiag", description: "", url: "https://github.com/blockdiag/seqdiag", enabled: true, toggle: null }, 27 | { prettyName: "ActDiag", krokiBlockName: "actdiag", obsidianBlockName: "actdiag", description: "", url: "https://github.com/blockdiag/actdiag", enabled: true, toggle: null }, 28 | { prettyName: "NwDiag", krokiBlockName: "nwdiag", obsidianBlockName: "nwdiag", description: "Nw Diag !!!", url: "https://github.com/blockdiag/nwdiag", enabled: true, toggle: null }, 29 | { prettyName: "PacketDiag", krokiBlockName: "packetdiag", obsidianBlockName: "packetdiag", description: "", url: "https://github.com/blockdiag/nwdiag", enabled: true, toggle: null }, 30 | { prettyName: "RackDiag", krokiBlockName: "rackdiag", obsidianBlockName: "rackdiag", description: "", url: "https://github.com/blockdiag/nwdiag", enabled: true, toggle: null }, 31 | { prettyName: "C4 with PlantUML", krokiBlockName: "c4plantuml", obsidianBlockName: "c4plantuml", description: "", url: "https://github.com/RicardoNiepel/C4-PlantUML", enabled: true, toggle: null }, 32 | { prettyName: "Ditaa", krokiBlockName: "ditaa", obsidianBlockName: "ditaa", description: "", url: "http://ditaa.sourceforge.net/", enabled: true, toggle: null }, 33 | { prettyName: "Diagrams.net", krokiBlockName: "diagramsnet", obsidianBlockName: "diagramsnet", description: "", url: "https://github.com/jgraph/drawio", enabled: false, toggle: null }, 34 | { prettyName: "Erd", krokiBlockName: "erd", obsidianBlockName: "erd", description: "", url: "https://github.com/BurntSushi/erd", enabled: true, toggle: null }, 35 | { prettyName: "Excalidraw", krokiBlockName: "excalidraw", obsidianBlockName: "excalidraw", description: "", url: "https://github.com/excalidraw/excalidraw", enabled: true, toggle: null }, 36 | { prettyName: "GraphViz", krokiBlockName: "graphviz", obsidianBlockName: "graphviz", description: "", url: "https://www.graphviz.org/", enabled: true, toggle: null }, 37 | { prettyName: "Mermaid", krokiBlockName: "mermaid", obsidianBlockName: "mermaid", description: "", url: "https://github.com/knsv/mermaid", enabled: false, toggle: null }, 38 | { prettyName: "Nomnoml", krokiBlockName: "nomnoml", obsidianBlockName: "nomnoml", description: "", url: "https://github.com/skanaar/nomnoml", enabled: true, toggle: null }, 39 | { prettyName: "Pikchr", krokiBlockName: "pikchr", obsidianBlockName: "pikchr", description: "", url: "https://github.com/drhsqlite/pikchr", enabled: true, toggle: null }, 40 | { prettyName: "PlantUML", krokiBlockName: "plantuml", obsidianBlockName: "plantuml", description: "", url: "https://github.com/plantuml/plantuml", enabled: false, toggle: null }, 41 | { prettyName: "Structurizr", krokiBlockName: "structurizr", obsidianBlockName: "structurizr", description: "", url: "https://structurizr.com/", enabled: true, toggle: null }, 42 | { prettyName: "Svgbob", krokiBlockName: "svgbob", obsidianBlockName: "svgbob", description: "", url: "https://github.com/ivanceras/svgbob", enabled: true, toggle: null }, 43 | { prettyName: "UMlet", krokiBlockName: "umlet", obsidianBlockName: "umlet", description: "", url: "https://github.com/umlet/umlet", enabled: true, toggle: null }, 44 | { prettyName: "Vega", krokiBlockName: "vega", obsidianBlockName: "vega", description: "", url: "https://github.com/vega/vega", enabled: true, toggle: null }, 45 | { prettyName: "Vega-Lite", krokiBlockName: "vegalite", obsidianBlockName: "vegalite", description: "", url: "https://github.com/vega/vega-lite", enabled: true, toggle: null }, 46 | { prettyName: "D2", krokiBlockName: "d2", obsidianBlockName: "d2", description: "", url: "https://github.com/terrastruct/d2", enabled: true, toggle: null }, 47 | { prettyName: "WireViz", krokiBlockName: "wireviz", obsidianBlockName: "wireviz", description: "", url: "https://github.com/formatc1702/WireViz", enabled: true, toggle: null }, 48 | { prettyName: "WaveDrom", krokiBlockName: "wavedrom", obsidianBlockName: "wavedrom", description: "", url: "https://github.com/wavedrom/wavedrom", enabled: true, toggle: null } 49 | ] 50 | 51 | } 52 | 53 | export default class KrokiPlugin extends Plugin { 54 | settings: KrokiSettings; 55 | 56 | svgProcessor = async (diagType: string, source: string, el: HTMLElement, _: MarkdownPostProcessorContext) => { 57 | const dest = document.createElement('div'); 58 | const urlPrefix = this.settings.server_url + diagType + "/svg/"; 59 | source = source.replace(/ /gi, " "); 60 | 61 | // encode the source 62 | // per: https://docs.kroki.io/kroki/setup/encode-diagram/#javascript 63 | const data = new TextEncoder().encode(source); 64 | const compressed = pako.deflate(data, { level: 9 }); 65 | const encodedSource = Buffer.from(compressed) 66 | .toString('base64') 67 | .replace(/\+/g, '-').replace(/\//g, '_'); 68 | 69 | const img = document.createElement("img"); 70 | img.src = urlPrefix + encodedSource; 71 | img.useMap = "#" + encodedSource; 72 | 73 | const result = await request({ method: 'GET', url: urlPrefix + encodedSource }); 74 | 75 | // if (result.ok) { 76 | dest.innerHTML = result; 77 | dest.children[0].setAttr("name", encodedSource); 78 | // } 79 | el.appendChild(dest); 80 | }; 81 | 82 | async onload(): Promise { 83 | console.log('loading plugin kroki'); 84 | await this.loadSettings(); 85 | 86 | this.addSettingTab(new KrokiSettingsTab(this.app, this)); 87 | 88 | // register a processor for each of the enabled diagram types 89 | for (let diagramType of this.settings.diagramTypes) { 90 | if (diagramType.enabled === true) { 91 | console.log("kroki is enabling: " + diagramType.prettyName); 92 | this.registerMarkdownCodeBlockProcessor(diagramType.obsidianBlockName, 93 | (source: string, el: HTMLElement, _: MarkdownPostProcessorContext) => { 94 | this.svgProcessor(diagramType.krokiBlockName, source, el, _) // this name is used to build the url, so it must be the kroki one 95 | }) 96 | } else { 97 | console.log("kroki is not enabling:", diagramType.prettyName); 98 | } 99 | } 100 | 101 | } 102 | 103 | onunload(): void { 104 | console.log('unloading plugin kroki'); 105 | } 106 | 107 | async loadSettings(): Promise { 108 | this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); 109 | } 110 | 111 | async saveSettings(): Promise { 112 | await this.saveData(this.settings); 113 | } 114 | } 115 | 116 | class KrokiSettingsTab extends PluginSettingTab { 117 | plugin: KrokiPlugin; 118 | 119 | constructor(app: App, plugin: KrokiPlugin) { 120 | super(app, plugin); 121 | this.plugin = plugin; 122 | } 123 | 124 | diagramTypeUrl(blockName: string, url: string) { 125 | let fragment = document.createDocumentFragment(); 126 | let a = document.createElement('a'); 127 | a.textContent = url 128 | a.setAttribute("href", url); 129 | 130 | fragment.append(a); 131 | return fragment; 132 | } 133 | 134 | display(): void { 135 | const { containerEl } = this; 136 | 137 | containerEl.empty(); 138 | 139 | this.containerEl.createEl("h3", { 140 | text: "General", 141 | }); 142 | 143 | new Setting(containerEl).setName("Server URL") 144 | .setDesc("Kroki Server URL") 145 | .addText(text => text.setPlaceholder(DEFAULT_SETTINGS.server_url) 146 | .setValue(this.plugin.settings.server_url) 147 | .onChange(async (value) => { 148 | this.plugin.settings.server_url = ensureTrailingSlash(value); 149 | await this.plugin.saveSettings(); 150 | } 151 | ) 152 | ); 153 | new Setting(containerEl).setName("Header") 154 | .setDesc("Included at the head in every diagram. Useful for specifying a common theme (.puml file)") 155 | .addTextArea(text => { 156 | text.setPlaceholder("!include https://raw.githubusercontent.com/....puml\n") 157 | .setValue(this.plugin.settings.header) 158 | .onChange(async (value) => { 159 | this.plugin.settings.header = value; 160 | await this.plugin.saveSettings(); 161 | } 162 | ) 163 | text.inputEl.setAttr("rows", 4); 164 | text.inputEl.addClass("settings_area") 165 | } 166 | ); 167 | 168 | this.containerEl.createEl("h3", { 169 | text: "Diagram Type (enable and 'language')", 170 | }); 171 | this.containerEl.createEl("p", { 172 | text: "Enable each diagram type individually. If there are multiple possible processors for a given type, then you can specify an alternate name for the diagram's 'language'", 173 | }); 174 | this.containerEl.createEl("p", { 175 | text: "NB that any changes here will require a re-load before becoming effective.", 176 | }); 177 | 178 | // loop through all the diagram types 179 | for (var i = 0; i < this.plugin.settings.diagramTypes.length; i++) { 180 | let diagramType = this.plugin.settings.diagramTypes[i]; 181 | new Setting(containerEl).setName(diagramType.prettyName) 182 | .setDesc(this.diagramTypeUrl(diagramType.krokiBlockName, diagramType.url)) 183 | 184 | .addToggle((t) => { 185 | t.setValue(diagramType.enabled); 186 | t.onChange(async (v) => { 187 | diagramType.enabled = v; 188 | await this.plugin.saveSettings(); 189 | }); 190 | // save the control for this diagram along with the diagram's other data 191 | diagramType.toggle = t; 192 | }) 193 | 194 | .addText(text => { 195 | text.setValue(diagramType.obsidianBlockName) 196 | .onChange(async (value) => { 197 | diagramType.obsidianBlockName = value; 198 | await this.plugin.saveSettings(); 199 | }); 200 | }); 201 | } 202 | } 203 | } 204 | 205 | function ensureTrailingSlash(url: string): string { 206 | if (!url.endsWith('/')) { 207 | return url + '/'; 208 | } 209 | return url; 210 | } 211 | -------------------------------------------------------------------------------- /kroki-test.md: -------------------------------------------------------------------------------- 1 | BlockDiag 2 | ```blockdiag 3 | blockdiag { 4 | Kroki -> generates -> "Block diagrams"; 5 | Kroki -> is -> "very easy!"; 6 | 7 | Kroki [color = "greenyellow"]; 8 | "Block diagrams" [color = "pink"]; 9 | "very easy!" [color = "orange"]; 10 | } 11 | ``` 12 | 13 | BPMN 14 | ```bpmn 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | OrderReceivedEvent 23 | _6-652 24 | _6-674 25 | CalmCustomerTask 26 | 27 | 28 | _6-463 29 | 30 | 31 | _6-514 32 | _6-565 33 | _6-616 34 | 35 | 36 | 37 | _6-630 38 | 39 | 40 | 41 | _6-630 42 | _6-691 43 | _6-693 44 | 45 | 46 | _6-691 47 | _6-746 48 | _6-748 49 | 50 | 51 | 52 | _6-748 53 | _6-746 54 | 55 | 56 | _6-693 57 | _6-632 58 | 59 | 60 | _6-632 61 | _6-634 62 | 63 | 64 | _6-634 65 | _6-636 66 | 67 | 68 | _6-636 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | _6-125 84 | 85 | 86 | _6-125 87 | _6-178 88 | 89 | 90 | _6-178 91 | _6-420 92 | 93 | 94 | _6-420 95 | _6-430 96 | _6-422 97 | _6-424 98 | 99 | 100 | _6-422 101 | _6-428 102 | 103 | 104 | 105 | _6-424 106 | _6-426 107 | 108 | 109 | 110 | 111 | 112 | _6-426 113 | _6-430 114 | 115 | 116 | _6-428 117 | _6-434 118 | 119 | 120 | _6-434 121 | _6-436 122 | 123 | 124 | _6-436 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | ``` 399 | 400 | Bytefield 401 | ```bytefield 402 | (defattrs :bg-green {:fill "#a0ffa0"}) 403 | (defattrs :bg-yellow {:fill "#ffffa0"}) 404 | (defattrs :bg-pink {:fill "#ffb0a0"}) 405 | (defattrs :bg-cyan {:fill "#a0fafa"}) 406 | (defattrs :bg-purple {:fill "#e4b5f7"}) 407 | 408 | (defn draw-group-label-header 409 | [span label] 410 | (draw-box (text label [:math {:font-size 12}]) {:span span :borders #{} :height 14})) 411 | 412 | (defn draw-remotedb-header 413 | [kind args] 414 | (draw-column-headers) 415 | (draw-group-label-header 5 "start") 416 | (draw-group-label-header 5 "TxID") 417 | (draw-group-label-header 3 "type") 418 | (draw-group-label-header 2 "args") 419 | (draw-group-label-header 1 "tags") 420 | (next-row 18) 421 | 422 | (draw-box 0x11 :bg-green) 423 | (draw-box 0x872349ae [{:span 4} :bg-green]) 424 | (draw-box 0x11 :bg-yellow) 425 | (draw-box (text "TxID" :math) [{:span 4} :bg-yellow]) 426 | (draw-box 0x10 :bg-pink) 427 | (draw-box (hex-text kind 4 :bold) [{:span 2} :bg-pink]) 428 | (draw-box 0x0f :bg-cyan) 429 | (draw-box (hex-text args 2 :bold) :bg-cyan) 430 | (draw-box 0x14 :bg-purple) 431 | 432 | (draw-box (text "0000000c" :hex [[:plain {:font-weight "light" :font-size 16}] " (12)"]) [{:span 4} :bg-purple]) 433 | (draw-box (hex-text 6 2 :bold) [:box-first :bg-purple]) 434 | (doseq [val [6 6 3 6 6 6 6 3]] 435 | (draw-box (hex-text val 2 :bold) [:box-related :bg-purple])) 436 | (doseq [val [0 0]] 437 | (draw-box val [:box-related :bg-purple])) 438 | (draw-box 0 [:box-last :bg-purple])) 439 | 440 | (draw-remotedb-header 0x4702 9) 441 | 442 | (draw-box 0x11) 443 | (draw-box 0x2104 {:span 4}) 444 | (draw-box 0x11) 445 | (draw-box 0 {:span 4}) 446 | (draw-box 0x11) 447 | (draw-box (text "length" [:math] [:sub 1]) {:span 4}) 448 | (draw-box 0x14) 449 | 450 | (draw-box (text "length" [:math] [:sub 1]) {:span 4}) 451 | (draw-gap "Cue and loop point bytes") 452 | 453 | (draw-box nil :box-below) 454 | (draw-box 0x11) 455 | (draw-box 0x36 {:span 4}) 456 | (draw-box 0x11) 457 | (draw-box (text "num" [:math] [:sub "hot"]) {:span 4}) 458 | (draw-box 0x11) 459 | (draw-box (text "num" [:math] [:sub "cue"]) {:span 4}) 460 | 461 | (draw-box 0x11) 462 | (draw-box (text "length" [:math] [:sub 2]) {:span 4}) 463 | (draw-box 0x14) 464 | (draw-box (text "length" [:math] [:sub 2]) {:span 4}) 465 | (draw-gap "Unknown bytes" {:min-label-columns 6}) 466 | (draw-bottom) 467 | ``` 468 | 469 | SeqDiag 470 | ```seqdiag 471 | seqdiag { 472 | browser -> webserver [label = "GET /seqdiag/svg/base64"]; 473 | webserver -> processor [label = "Convert text to image"]; 474 | webserver <-- processor; 475 | browser <-- webserver; 476 | } 477 | ``` 478 | 479 | ActDiag 480 | ```actdiag 481 | actdiag { 482 | write -> convert -> image 483 | 484 | lane user { 485 | label = "User" 486 | write [label = "Writing text"]; 487 | image [label = "Get diagram image"]; 488 | } 489 | lane Kroki { 490 | convert [label = "Convert text to image"]; 491 | } 492 | } 493 | ``` 494 | 495 | NwDiag 496 | ```nwdiag 497 | nwdiag { 498 | network dmz { 499 | address = "210.x.x.x/24" 500 | 501 | web01 [address = "210.x.x.1"]; 502 | web02 [address = "210.x.x.2"]; 503 | } 504 | network internal { 505 | address = "172.x.x.x/24"; 506 | 507 | web01 [address = "172.x.x.1"]; 508 | web02 [address = "172.x.x.2"]; 509 | db01; 510 | db02; 511 | } 512 | } 513 | ``` 514 | 515 | PacketDiag 516 | ```packetdiag 517 | packetdiag { 518 | colwidth = 32; 519 | node_height = 72; 520 | 521 | 0-15: Source Port; 522 | 16-31: Destination Port; 523 | 32-63: Sequence Number; 524 | 64-95: Acknowledgment Number; 525 | 96-99: Data Offset; 526 | 100-105: Reserved; 527 | 106: URG [rotate = 270]; 528 | 107: ACK [rotate = 270]; 529 | 108: PSH [rotate = 270]; 530 | 109: RST [rotate = 270]; 531 | 110: SYN [rotate = 270]; 532 | 111: FIN [rotate = 270]; 533 | 112-127: Window; 534 | 128-143: Checksum; 535 | 144-159: Urgent Pointer; 536 | 160-191: (Options and Padding); 537 | 192-223: data [colheight = 3]; 538 | } 539 | ``` 540 | 541 | RackDiag 542 | ```rackdiag 543 | rackdiag { 544 | 16U; 545 | 1: UPS [2U]; 546 | 3: DB Server; 547 | 4: Web Server; 548 | 5: Web Server; 549 | 6: Web Server; 550 | 7: Load Balancer; 551 | 8: L3 Switch; 552 | } 553 | ``` 554 | 555 | C4 with PlantUML 556 | ```c4plantuml 557 | @startuml 558 | !include C4_Context.puml 559 | 560 | title System Context diagram for Internet Banking System 561 | 562 | Person(customer, "Banking Customer", "A customer of the bank, with personal bank accounts.") 563 | System(banking_system, "Internet Banking System", "Allows customers to check their accounts.") 564 | 565 | System_Ext(mail_system, "E-mail system", "The internal Microsoft Exchange e-mail system.") 566 | System_Ext(mainframe, "Mainframe Banking System", "Stores all of the core banking information.") 567 | 568 | Rel(customer, banking_system, "Uses") 569 | Rel_Back(customer, mail_system, "Sends e-mails to") 570 | Rel_Neighbor(banking_system, mail_system, "Sends e-mails", "SMTP") 571 | Rel(banking_system, mainframe, "Uses") 572 | @enduml 573 | ``` 574 | 575 | Ditaa 576 | ```ditaa 577 | +--------+ 578 | | | 579 | | User | 580 | | | 581 | +--------+ 582 | ^ 583 | request | 584 | v 585 | +-------------+ 586 | | | 587 | | Kroki | 588 | | |---+ 589 | +-------------+ | 590 | ^ ^ | inflate 591 | | | | 592 | v +---------+ 593 | +-------------+ 594 | | | 595 | | Ditaa | 596 | | |----+ 597 | +-------------+ | 598 | ^ | process 599 | | | 600 | +-------+ 601 | 602 | ``` 603 | 604 | Diagrams.net 605 | ```diagramsnet 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | ``` 693 | 694 | Erd 695 | ```erd 696 | [Person] 697 | *name 698 | height 699 | weight 700 | +birth_location_id 701 | 702 | [Location] 703 | *id 704 | city 705 | state 706 | country 707 | 708 | Person *--1 Location 709 | ``` 710 | 711 | Excalidraw 712 | ```excalidraw 713 | { 714 | "type": "excalidraw", 715 | "version": 2, 716 | "source": "https://excalidraw.com", 717 | "elements": [ 718 | { 719 | "type": "rectangle", 720 | "version": 175, 721 | "versionNonce": 279344008, 722 | "isDeleted": false, 723 | "id": "2ZYh24ed28FJ0yE-S3YNY", 724 | "fillStyle": "hachure", 725 | "strokeWidth": 1, 726 | "strokeStyle": "solid", 727 | "roughness": 1, 728 | "opacity": 100, 729 | "angle": 0, 730 | "x": 580, 731 | "y": 140, 732 | "strokeColor": "#000000", 733 | "backgroundColor": "#15aabf", 734 | "width": 80, 735 | "height": 19.999999999999996, 736 | "seed": 521916552, 737 | "groupIds": [], 738 | "strokeSharpness": "sharp", 739 | "boundElementIds": [ 740 | "Be1y2yzhV3Zd4nwCro__8" 741 | ] 742 | }, 743 | { 744 | "type": "rectangle", 745 | "version": 180, 746 | "versionNonce": 164784376, 747 | "isDeleted": false, 748 | "id": "bO0OVt6m7LowYpq22ePCA", 749 | "fillStyle": "hachure", 750 | "strokeWidth": 1, 751 | "strokeStyle": "solid", 752 | "roughness": 1, 753 | "opacity": 100, 754 | "angle": 0, 755 | "x": 660, 756 | "y": 140, 757 | "strokeColor": "#000000", 758 | "backgroundColor": "#4c6ef5", 759 | "width": 120, 760 | "height": 19.999999999999996, 761 | "seed": 1303206904, 762 | "groupIds": [], 763 | "strokeSharpness": "sharp", 764 | "boundElementIds": [ 765 | "KaCO9-QjUenSyCuuanoTo" 766 | ] 767 | }, 768 | { 769 | "type": "rectangle", 770 | "version": 183, 771 | "versionNonce": 27181704, 772 | "isDeleted": false, 773 | "id": "jz0Huq9-s6pNxDw0RqHcR", 774 | "fillStyle": "hachure", 775 | "strokeWidth": 1, 776 | "strokeStyle": "solid", 777 | "roughness": 1, 778 | "opacity": 100, 779 | "angle": 0, 780 | "x": 780, 781 | "y": 140, 782 | "strokeColor": "#000000", 783 | "backgroundColor": "#fab005", 784 | "width": 180, 785 | "height": 19.999999999999996, 786 | "seed": 861962120, 787 | "groupIds": [], 788 | "strokeSharpness": "sharp", 789 | "boundElementIds": [ 790 | "74ifmqmu0vN0NK0_0FwPm" 791 | ] 792 | }, 793 | { 794 | "type": "rectangle", 795 | "version": 192, 796 | "versionNonce": 2123008504, 797 | "isDeleted": false, 798 | "id": "UnmNTmwJtm6moubcGtSgB", 799 | "fillStyle": "hachure", 800 | "strokeWidth": 1, 801 | "strokeStyle": "solid", 802 | "roughness": 1, 803 | "opacity": 100, 804 | "angle": 0, 805 | "x": 960, 806 | "y": 140, 807 | "strokeColor": "#000000", 808 | "backgroundColor": "#fa5252", 809 | "width": 80, 810 | "height": 19.999999999999996, 811 | "seed": 277814520, 812 | "groupIds": [], 813 | "strokeSharpness": "sharp", 814 | "boundElementIds": [ 815 | "1v60NED2criGG-wo9-oQL" 816 | ] 817 | }, 818 | { 819 | "type": "rectangle", 820 | "version": 202, 821 | "versionNonce": 1823814024, 822 | "isDeleted": false, 823 | "id": "of76J4WOJHnHi0L61Vst_", 824 | "fillStyle": "hachure", 825 | "strokeWidth": 1, 826 | "strokeStyle": "solid", 827 | "roughness": 1, 828 | "opacity": 100, 829 | "angle": 0, 830 | "x": 1040, 831 | "y": 140, 832 | "strokeColor": "#000000", 833 | "backgroundColor": "#be4bdb", 834 | "width": 180, 835 | "height": 19.999999999999996, 836 | "seed": 1496796808, 837 | "groupIds": [], 838 | "strokeSharpness": "sharp", 839 | "boundElementIds": [ 840 | "jjuPzyRneMv3f65lps_6a" 841 | ] 842 | }, 843 | { 844 | "type": "rectangle", 845 | "version": 193, 846 | "versionNonce": 1234602744, 847 | "isDeleted": false, 848 | "id": "SlvbjeV-9lXbcrlKib-hj", 849 | "fillStyle": "hachure", 850 | "strokeWidth": 1, 851 | "strokeStyle": "solid", 852 | "roughness": 1, 853 | "opacity": 100, 854 | "angle": 0, 855 | "x": 1220, 856 | "y": 140, 857 | "strokeColor": "#000000", 858 | "backgroundColor": "#868e96", 859 | "width": 60, 860 | "height": 19.999999999999996, 861 | "seed": 1938865656, 862 | "groupIds": [], 863 | "strokeSharpness": "sharp", 864 | "boundElementIds": [ 865 | "5QQzhw_uqk_rBaW2wMriT" 866 | ] 867 | }, 868 | { 869 | "type": "text", 870 | "version": 81, 871 | "versionNonce": 1188901129, 872 | "isDeleted": false, 873 | "id": "vrdt3JfbD2Xwz4K4TWScI", 874 | "fillStyle": "hachure", 875 | "strokeWidth": 1, 876 | "strokeStyle": "solid", 877 | "roughness": 1, 878 | "opacity": 100, 879 | "angle": 0, 880 | "x": 840, 881 | "y": -60, 882 | "strokeColor": "#000000", 883 | "backgroundColor": "#868e96", 884 | "width": 190, 885 | "height": 45, 886 | "seed": 1499217288, 887 | "groupIds": [], 888 | "strokeSharpness": "sharp", 889 | "boundElementIds": [], 890 | "fontSize": 36, 891 | "fontFamily": 1, 892 | "text": "JavaScript", 893 | "baseline": 32, 894 | "textAlign": "left", 895 | "verticalAlign": "top" 896 | }, 897 | { 898 | "type": "arrow", 899 | "version": 343, 900 | "versionNonce": 1369065096, 901 | "isDeleted": false, 902 | "id": "Be1y2yzhV3Zd4nwCro__8", 903 | "fillStyle": "hachure", 904 | "strokeWidth": 1, 905 | "strokeStyle": "solid", 906 | "roughness": 1, 907 | "opacity": 100, 908 | "angle": 0, 909 | "x": 597.5075333823274, 910 | "y": 299, 911 | "strokeColor": "#000000", 912 | "backgroundColor": "#868e96", 913 | "width": 40, 914 | "height": 139, 915 | "seed": 666255096, 916 | "groupIds": [], 917 | "strokeSharpness": "round", 918 | "boundElementIds": [], 919 | "startBinding": { 920 | "focus": -0.41953339688473495, 921 | "gap": 1, 922 | "elementId": "UxgtvUBaIPnDWJZ9kUQH8" 923 | }, 924 | "endBinding": { 925 | "focus": -0.11111111111111113, 926 | "gap": 1, 927 | "elementId": "2ZYh24ed28FJ0yE-S3YNY" 928 | }, 929 | "points": [ 930 | [ 931 | 0, 932 | 0 933 | ], 934 | [ 935 | -17.507533382327438, 936 | -59 937 | ], 938 | [ 939 | 22.492466617672562, 940 | -139 941 | ] 942 | ], 943 | "lastCommittedPoint": null, 944 | "startArrowhead": null, 945 | "endArrowhead": "arrow" 946 | }, 947 | { 948 | "type": "text", 949 | "version": 81, 950 | "versionNonce": 690339976, 951 | "isDeleted": false, 952 | "id": "UxgtvUBaIPnDWJZ9kUQH8", 953 | "fillStyle": "hachure", 954 | "strokeWidth": 1, 955 | "strokeStyle": "solid", 956 | "roughness": 1, 957 | "opacity": 100, 958 | "angle": 0, 959 | "x": 580, 960 | "y": 300, 961 | "strokeColor": "#000000", 962 | "backgroundColor": "#868e96", 963 | "width": 94, 964 | "height": 45, 965 | "seed": 84626568, 966 | "groupIds": [], 967 | "strokeSharpness": "sharp", 968 | "boundElementIds": [ 969 | "Be1y2yzhV3Zd4nwCro__8" 970 | ], 971 | "fontSize": 36, 972 | "fontFamily": 1, 973 | "text": "Fetch", 974 | "baseline": 32, 975 | "textAlign": "left", 976 | "verticalAlign": "top" 977 | }, 978 | { 979 | "type": "rectangle", 980 | "version": 60, 981 | "versionNonce": 897215480, 982 | "isDeleted": false, 983 | "id": "-Lq0agjWQ31TR_Av5Z4HW", 984 | "fillStyle": "hachure", 985 | "strokeWidth": 1, 986 | "strokeStyle": "solid", 987 | "roughness": 1, 988 | "opacity": 100, 989 | "angle": 0, 990 | "x": 520, 991 | "y": -60, 992 | "strokeColor": "#000000", 993 | "backgroundColor": "transparent", 994 | "width": 820, 995 | "height": 540, 996 | "seed": 495165432, 997 | "groupIds": [], 998 | "strokeSharpness": "sharp", 999 | "boundElementIds": [ 1000 | "jjuPzyRneMv3f65lps_6a" 1001 | ] 1002 | }, 1003 | { 1004 | "type": "arrow", 1005 | "version": 537, 1006 | "versionNonce": 1626949112, 1007 | "isDeleted": false, 1008 | "id": "KaCO9-QjUenSyCuuanoTo", 1009 | "fillStyle": "hachure", 1010 | "strokeWidth": 1, 1011 | "strokeStyle": "solid", 1012 | "roughness": 1, 1013 | "opacity": 100, 1014 | "angle": 0, 1015 | "x": 721.0588599991052, 1016 | "y": 60.17790458606555, 1017 | "strokeColor": "#000000", 1018 | "backgroundColor": "#868e96", 1019 | "width": 1.0588599991051524, 1020 | "height": 79.82209541393445, 1021 | "seed": 637565832, 1022 | "groupIds": [], 1023 | "strokeSharpness": "round", 1024 | "boundElementIds": [], 1025 | "startBinding": null, 1026 | "endBinding": { 1027 | "focus": 0, 1028 | "gap": 1, 1029 | "elementId": "bO0OVt6m7LowYpq22ePCA" 1030 | }, 1031 | "points": [ 1032 | [ 1033 | 0, 1034 | 0 1035 | ], 1036 | [ 1037 | -1.0588599991051524, 1038 | 39.82209541393445 1039 | ], 1040 | [ 1041 | -1.0588599991051524, 1042 | 79.82209541393445 1043 | ] 1044 | ], 1045 | "lastCommittedPoint": null, 1046 | "startArrowhead": null, 1047 | "endArrowhead": "arrow" 1048 | }, 1049 | { 1050 | "type": "text", 1051 | "version": 112, 1052 | "versionNonce": 358083143, 1053 | "isDeleted": false, 1054 | "id": "4hEOdlcwK6AHyVhjc-MXS", 1055 | "fillStyle": "hachure", 1056 | "strokeWidth": 1, 1057 | "strokeStyle": "solid", 1058 | "roughness": 1, 1059 | "opacity": 100, 1060 | "angle": 0, 1061 | "x": 660, 1062 | "y": 20, 1063 | "strokeColor": "#000000", 1064 | "backgroundColor": "#868e96", 1065 | "width": 103, 1066 | "height": 45, 1067 | "seed": 352116984, 1068 | "groupIds": [], 1069 | "strokeSharpness": "sharp", 1070 | "boundElementIds": [], 1071 | "fontSize": 36, 1072 | "fontFamily": 1, 1073 | "text": "Parse", 1074 | "baseline": 32, 1075 | "textAlign": "left", 1076 | "verticalAlign": "top" 1077 | }, 1078 | { 1079 | "type": "arrow", 1080 | "version": 534, 1081 | "versionNonce": 983577992, 1082 | "isDeleted": false, 1083 | "id": "74ifmqmu0vN0NK0_0FwPm", 1084 | "fillStyle": "hachure", 1085 | "strokeWidth": 1, 1086 | "strokeStyle": "solid", 1087 | "roughness": 1, 1088 | "opacity": 100, 1089 | "angle": 0, 1090 | "x": 841.6574209245741, 1091 | "y": 219, 1092 | "strokeColor": "#000000", 1093 | "backgroundColor": "#868e96", 1094 | "width": 43.15128973100309, 1095 | "height": 59.174989629909305, 1096 | "seed": 1853344392, 1097 | "groupIds": [], 1098 | "strokeSharpness": "round", 1099 | "boundElementIds": [], 1100 | "startBinding": { 1101 | "focus": 0.09211398277003865, 1102 | "gap": 1, 1103 | "elementId": "K4so-arfr0JX0NJx8vd7T" 1104 | }, 1105 | "endBinding": { 1106 | "focus": -0.2163077865936296, 1107 | "gap": 1, 1108 | "elementId": "jz0Huq9-s6pNxDw0RqHcR" 1109 | }, 1110 | "points": [ 1111 | [ 1112 | 0, 1113 | 0 1114 | ], 1115 | [ 1116 | -1.6574209245741258, 1117 | 1 1118 | ], 1119 | [ 1120 | 41.493868806428964, 1121 | -58.174989629909305 1122 | ] 1123 | ], 1124 | "lastCommittedPoint": null, 1125 | "startArrowhead": null, 1126 | "endArrowhead": "arrow" 1127 | }, 1128 | { 1129 | "type": "text", 1130 | "version": 118, 1131 | "versionNonce": 1185705864, 1132 | "isDeleted": false, 1133 | "id": "K4so-arfr0JX0NJx8vd7T", 1134 | "fillStyle": "hachure", 1135 | "strokeWidth": 1, 1136 | "strokeStyle": "solid", 1137 | "roughness": 1, 1138 | "opacity": 100, 1139 | "angle": 0, 1140 | "x": 640, 1141 | "y": 220, 1142 | "strokeColor": "#000000", 1143 | "backgroundColor": "#868e96", 1144 | "width": 366, 1145 | "height": 45, 1146 | "seed": 765854200, 1147 | "groupIds": [], 1148 | "strokeSharpness": "sharp", 1149 | "boundElementIds": [ 1150 | "74ifmqmu0vN0NK0_0FwPm" 1151 | ], 1152 | "fontSize": 36, 1153 | "fontFamily": 1, 1154 | "text": "Compile and Optimize", 1155 | "baseline": 32, 1156 | "textAlign": "left", 1157 | "verticalAlign": "top" 1158 | }, 1159 | { 1160 | "type": "arrow", 1161 | "version": 791, 1162 | "versionNonce": 1724761848, 1163 | "isDeleted": false, 1164 | "id": "1v60NED2criGG-wo9-oQL", 1165 | "fillStyle": "hachure", 1166 | "strokeWidth": 1, 1167 | "strokeStyle": "solid", 1168 | "roughness": 1, 1169 | "opacity": 100, 1170 | "angle": 0, 1171 | "x": 960, 1172 | "y": 320, 1173 | "strokeColor": "#000000", 1174 | "backgroundColor": "#868e96", 1175 | "width": 80, 1176 | "height": 160, 1177 | "seed": 1764571528, 1178 | "groupIds": [], 1179 | "strokeSharpness": "round", 1180 | "boundElementIds": [], 1181 | "startBinding": { 1182 | "focus": -0.1637630662020906, 1183 | "gap": 1, 1184 | "elementId": "dviXudWNxiHYQMZfqHWsH" 1185 | }, 1186 | "endBinding": { 1187 | "focus": 0.07692307692307691, 1188 | "gap": 1, 1189 | "elementId": "UnmNTmwJtm6moubcGtSgB" 1190 | }, 1191 | "points": [ 1192 | [ 1193 | 0, 1194 | 0 1195 | ], 1196 | [ 1197 | 80, 1198 | -40 1199 | ], 1200 | [ 1201 | 40, 1202 | -160 1203 | ] 1204 | ], 1205 | "lastCommittedPoint": null, 1206 | "startArrowhead": null, 1207 | "endArrowhead": "arrow" 1208 | }, 1209 | { 1210 | "type": "text", 1211 | "version": 194, 1212 | "versionNonce": 473574648, 1213 | "isDeleted": false, 1214 | "id": "dviXudWNxiHYQMZfqHWsH", 1215 | "fillStyle": "hachure", 1216 | "strokeWidth": 1, 1217 | "strokeStyle": "solid", 1218 | "roughness": 1, 1219 | "opacity": 100, 1220 | "angle": 0, 1221 | "x": 720, 1222 | "y": 320, 1223 | "strokeColor": "#000000", 1224 | "backgroundColor": "#868e96", 1225 | "width": 484, 1226 | "height": 45, 1227 | "seed": 1988297464, 1228 | "groupIds": [], 1229 | "strokeSharpness": "sharp", 1230 | "boundElementIds": [ 1231 | "1v60NED2criGG-wo9-oQL" 1232 | ], 1233 | "fontSize": 36, 1234 | "fontFamily": 1, 1235 | "text": "Re-optimize and Deoptimize", 1236 | "baseline": 32, 1237 | "textAlign": "left", 1238 | "verticalAlign": "top" 1239 | }, 1240 | { 1241 | "type": "arrow", 1242 | "version": 708, 1243 | "versionNonce": 185615496, 1244 | "isDeleted": false, 1245 | "id": "jjuPzyRneMv3f65lps_6a", 1246 | "fillStyle": "hachure", 1247 | "strokeWidth": 1, 1248 | "strokeStyle": "solid", 1249 | "roughness": 1, 1250 | "opacity": 100, 1251 | "angle": 0, 1252 | "x": 1140, 1253 | "y": 80, 1254 | "strokeColor": "#000000", 1255 | "backgroundColor": "#868e96", 1256 | "width": 20, 1257 | "height": 60, 1258 | "seed": 1767688328, 1259 | "groupIds": [], 1260 | "strokeSharpness": "round", 1261 | "boundElementIds": [], 1262 | "startBinding": { 1263 | "focus": -0.3021784319542362, 1264 | "gap": 14.800415739789742, 1265 | "elementId": "qhkjvI1VmWZdnKvU5QKZK" 1266 | }, 1267 | "endBinding": { 1268 | "focus": 0.15789473684210528, 1269 | "gap": 1, 1270 | "elementId": "of76J4WOJHnHi0L61Vst_" 1271 | }, 1272 | "points": [ 1273 | [ 1274 | 0, 1275 | 0 1276 | ], 1277 | [ 1278 | -20, 1279 | 20 1280 | ], 1281 | [ 1282 | 0, 1283 | 60 1284 | ] 1285 | ], 1286 | "lastCommittedPoint": null, 1287 | "startArrowhead": null, 1288 | "endArrowhead": "arrow" 1289 | }, 1290 | { 1291 | "type": "text", 1292 | "version": 213, 1293 | "versionNonce": 2105884296, 1294 | "isDeleted": false, 1295 | "id": "qhkjvI1VmWZdnKvU5QKZK", 1296 | "fillStyle": "hachure", 1297 | "strokeWidth": 1, 1298 | "strokeStyle": "solid", 1299 | "roughness": 1, 1300 | "opacity": 100, 1301 | "angle": 0, 1302 | "x": 1080, 1303 | "y": 20.19958426021026, 1304 | "strokeColor": "#000000", 1305 | "backgroundColor": "#868e96", 1306 | "width": 139, 1307 | "height": 45, 1308 | "seed": 2115494904, 1309 | "groupIds": [], 1310 | "strokeSharpness": "sharp", 1311 | "boundElementIds": [ 1312 | "jjuPzyRneMv3f65lps_6a" 1313 | ], 1314 | "fontSize": 36, 1315 | "fontFamily": 1, 1316 | "text": "Execute", 1317 | "baseline": 32, 1318 | "textAlign": "left", 1319 | "verticalAlign": "top" 1320 | }, 1321 | { 1322 | "type": "arrow", 1323 | "version": 707, 1324 | "versionNonce": 543827960, 1325 | "isDeleted": false, 1326 | "id": "5QQzhw_uqk_rBaW2wMriT", 1327 | "fillStyle": "hachure", 1328 | "strokeWidth": 1, 1329 | "strokeStyle": "solid", 1330 | "roughness": 1, 1331 | "opacity": 100, 1332 | "angle": 0, 1333 | "x": 1220, 1334 | "y": 240, 1335 | "strokeColor": "#000000", 1336 | "backgroundColor": "#868e96", 1337 | "width": 20, 1338 | "height": 80, 1339 | "seed": 2059564936, 1340 | "groupIds": [], 1341 | "strokeSharpness": "round", 1342 | "boundElementIds": [], 1343 | "startBinding": { 1344 | "focus": 0.7391304347826086, 1345 | "gap": 2, 1346 | "elementId": "C6fyzTg2FHAmrRYfC_THm" 1347 | }, 1348 | "endBinding": { 1349 | "focus": 0.3333333333333333, 1350 | "gap": 1, 1351 | "elementId": "SlvbjeV-9lXbcrlKib-hj" 1352 | }, 1353 | "points": [ 1354 | [ 1355 | 0, 1356 | 0 1357 | ], 1358 | [ 1359 | 20, 1360 | -40 1361 | ], 1362 | [ 1363 | 20, 1364 | -80 1365 | ] 1366 | ], 1367 | "lastCommittedPoint": null, 1368 | "startArrowhead": null, 1369 | "endArrowhead": "arrow" 1370 | }, 1371 | { 1372 | "type": "text", 1373 | "version": 227, 1374 | "versionNonce": 2002374136, 1375 | "isDeleted": false, 1376 | "id": "C6fyzTg2FHAmrRYfC_THm", 1377 | "fillStyle": "hachure", 1378 | "strokeWidth": 1, 1379 | "strokeStyle": "solid", 1380 | "roughness": 1, 1381 | "opacity": 100, 1382 | "angle": 0, 1383 | "x": 1160, 1384 | "y": 220, 1385 | "strokeColor": "#000000", 1386 | "backgroundColor": "#868e96", 1387 | "width": 58, 1388 | "height": 45, 1389 | "seed": 1651025144, 1390 | "groupIds": [], 1391 | "strokeSharpness": "sharp", 1392 | "boundElementIds": [ 1393 | "5QQzhw_uqk_rBaW2wMriT" 1394 | ], 1395 | "fontSize": 36, 1396 | "fontFamily": 1, 1397 | "text": "GC", 1398 | "baseline": 32, 1399 | "textAlign": "left", 1400 | "verticalAlign": "top" 1401 | } 1402 | ], 1403 | "appState": { 1404 | "viewBackgroundColor": "#ffffff", 1405 | "gridSize": 20 1406 | } 1407 | } 1408 | ``` 1409 | 1410 | GraphViz 1411 | ```graphviz 1412 | digraph D { 1413 | subgraph cluster_p { 1414 | label = "Kroki"; 1415 | subgraph cluster_c1 { 1416 | label = "Server"; 1417 | Filebeat; 1418 | subgraph cluster_gc_1 { 1419 | label = "Docker/Server"; 1420 | Java; 1421 | } 1422 | subgraph cluster_gc_2 { 1423 | label = "Docker/Mermaid"; 1424 | "Node.js"; 1425 | "Puppeteer"; 1426 | "Chrome"; 1427 | } 1428 | } 1429 | subgraph cluster_c2 { 1430 | label = "CLI"; 1431 | Golang; 1432 | } 1433 | } 1434 | } 1435 | ``` 1436 | 1437 | Mermaid 1438 | ```kroki-mermaid 1439 | graph TD 1440 | A[ Anyone ] -->|Can help | B( Go to github.com/yuzutech/kroki ) 1441 | B --> C{ How to contribute? } 1442 | C --> D[ Reporting bugs ] 1443 | C --> E[ Sharing ideas ] 1444 | C --> F[ Advocating ] 1445 | ``` 1446 | 1447 | Nomnoml 1448 | ```nomnoml 1449 | [Pirate|eyeCount: Int|raid();pillage()| 1450 | [beard]--[parrot] 1451 | [beard]-:>[foul mouth] 1452 | ] 1453 | 1454 | [Marauder]<:--[Pirate] 1455 | [Pirate]- 0..7[mischief] 1456 | [jollyness]->[Pirate] 1457 | [jollyness]->[rum] 1458 | [jollyness]->[singing] 1459 | [Pirate]-> *[rum|tastiness: Int|swig()] 1460 | [Pirate]->[singing] 1461 | [singing]<->[rum] 1462 | ``` 1463 | 1464 | Pikchr 1465 | ```pikchr 1466 | $r = 0.2in 1467 | linerad = 0.75*$r 1468 | linewid = 0.25 1469 | 1470 | # Start and end blocks 1471 | # 1472 | box "element" bold fit 1473 | line down 50% from last box.sw 1474 | dot rad 250% color black 1475 | X0: last.e + (0.3,0) 1476 | arrow from last dot to X0 1477 | move right 3.9in 1478 | box wid 5% ht 25% fill black 1479 | X9: last.w - (0.3,0) 1480 | arrow from X9 to last box.w 1481 | 1482 | 1483 | # The main rule that goes straight through from start to finish 1484 | # 1485 | box "object-definition" italic fit at 11/16 way between X0 and X9 1486 | arrow to X9 1487 | arrow from X0 to last box.w 1488 | 1489 | # The LABEL: rule 1490 | # 1491 | arrow right $r from X0 then down 1.25*$r then right $r 1492 | oval " LABEL " fit 1493 | arrow 50% 1494 | oval "\":\"" fit 1495 | arrow 200% 1496 | box "position" italic fit 1497 | arrow 1498 | line right until even with X9 - ($r,0) \ 1499 | then up until even with X9 then to X9 1500 | arrow from last oval.e right $r*0.5 then up $r*0.8 right $r*0.8 1501 | line up $r*0.45 right $r*0.45 then right 1502 | 1503 | # The VARIABLE = rule 1504 | # 1505 | arrow right $r from X0 then down 2.5*$r then right $r 1506 | oval " VARIABLE " fit 1507 | arrow 70% 1508 | box "assignment-operator" italic fit 1509 | arrow 70% 1510 | box "expr" italic fit 1511 | line right until even with X9 - ($r,0) \ 1512 | then up until even with X9 then to X9 1513 | 1514 | # The PRINT rule 1515 | # 1516 | arrow right $r from X0 then down 3.75*$r then right $r 1517 | oval "\"print\"" fit 1518 | arrow 1519 | box "print-args" italic fit 1520 | line right until even with X9 - ($r,0) \ 1521 | then up until even with X9 then to X9 1522 | ``` 1523 | 1524 | PlantUML 1525 | ```kroki-plantuml 1526 | Bob -> Alice : hello [[https://www.google.com]] 1527 | Alice -> Wander: hello 1528 | Wonderland -> next: hello 1529 | next -> Last: hello 1530 | Last -> next: hello 1531 | next -> Wonderland : hello 1532 | Wonderland -> Alice : WTF? 1533 | Alice -> Bob: hello 1534 | ``` 1535 | 1536 | Svgbob 1537 | ```svgbob 1538 | .-,( ),-. 1539 | ___ _ .-( )-. 1540 | [___]|=| -->( ) __________ 1541 | /::/ |_| '-( ).-' --->[_...__... ] 1542 | '-.( ).-' 1543 | \ ____ __ 1544 | '--->| | |==| 1545 | |____| | | 1546 | /::::/ |__| 1547 | ``` 1548 | 1549 | UMlet (https://gitter.im/kroki-project/community?at=5fa9255d7cac87158f96c750) 1550 | ```umlet 1551 | com.umlet.element.base.Class8025011040<<artefact>> 1552 | Namecom.umlet.element.custom.Artefact8018011050Namecom.umlet.element.custom.Node2020250330><<device>> 1553 | >Servercom.umlet.element.custom.Node40100200220><<execution environment>> 1554 | >AppServer 1555 | ``` 1556 | 1557 | Vega 1558 | ```vega 1559 | { 1560 | "$schema": "https://vega.github.io/schema/vega/v5.json", 1561 | "width": 400, 1562 | "height": 200, 1563 | "padding": 5, 1564 | 1565 | "data": [ 1566 | { 1567 | "name": "table", 1568 | "values": [ 1569 | {"category": "A", "amount": 28}, 1570 | {"category": "B", "amount": 55}, 1571 | {"category": "C", "amount": 43}, 1572 | {"category": "D", "amount": 91}, 1573 | {"category": "E", "amount": 81}, 1574 | {"category": "F", "amount": 53}, 1575 | {"category": "G", "amount": 19}, 1576 | {"category": "H", "amount": 87} 1577 | ] 1578 | } 1579 | ], 1580 | 1581 | "signals": [ 1582 | { 1583 | "name": "tooltip", 1584 | "value": {}, 1585 | "on": [ 1586 | {"events": "rect:mouseover", "update": "datum"}, 1587 | {"events": "rect:mouseout", "update": "{}"} 1588 | ] 1589 | } 1590 | ], 1591 | 1592 | "scales": [ 1593 | { 1594 | "name": "xscale", 1595 | "type": "band", 1596 | "domain": {"data": "table", "field": "category"}, 1597 | "range": "width", 1598 | "padding": 0.05, 1599 | "round": true 1600 | }, 1601 | { 1602 | "name": "yscale", 1603 | "domain": {"data": "table", "field": "amount"}, 1604 | "nice": true, 1605 | "range": "height" 1606 | } 1607 | ], 1608 | 1609 | "axes": [ 1610 | { "orient": "bottom", "scale": "xscale" }, 1611 | { "orient": "left", "scale": "yscale" } 1612 | ], 1613 | 1614 | "marks": [ 1615 | { 1616 | "type": "rect", 1617 | "from": {"data":"table"}, 1618 | "encode": { 1619 | "enter": { 1620 | "x": {"scale": "xscale", "field": "category"}, 1621 | "width": {"scale": "xscale", "band": 1}, 1622 | "y": {"scale": "yscale", "field": "amount"}, 1623 | "y2": {"scale": "yscale", "value": 0} 1624 | }, 1625 | "update": { 1626 | "fill": {"value": "steelblue"} 1627 | }, 1628 | "hover": { 1629 | "fill": {"value": "red"} 1630 | } 1631 | } 1632 | }, 1633 | { 1634 | "type": "text", 1635 | "encode": { 1636 | "enter": { 1637 | "align": {"value": "center"}, 1638 | "baseline": {"value": "bottom"}, 1639 | "fill": {"value": "#333"} 1640 | }, 1641 | "update": { 1642 | "x": {"scale": "xscale", "signal": "tooltip.category", "band": 0.5}, 1643 | "y": {"scale": "yscale", "signal": "tooltip.amount", "offset": -2}, 1644 | "text": {"signal": "tooltip.amount"}, 1645 | "fillOpacity": [ 1646 | {"test": "datum === tooltip", "value": 0}, 1647 | {"value": 1} 1648 | ] 1649 | } 1650 | } 1651 | } 1652 | ] 1653 | } 1654 | ``` 1655 | 1656 | Vega-Lite 1657 | ```vegalite 1658 | { 1659 | "$schema": "https://vega.github.io/schema/vega-lite/v4.json", 1660 | "description": "Horizontally concatenated charts that show different types of discretizing scales.", 1661 | "data": { 1662 | "values": [ 1663 | {"a": "A", "b": 28}, 1664 | {"a": "B", "b": 55}, 1665 | {"a": "C", "b": 43}, 1666 | {"a": "D", "b": 91}, 1667 | {"a": "E", "b": 81}, 1668 | {"a": "F", "b": 53}, 1669 | {"a": "G", "b": 19}, 1670 | {"a": "H", "b": 87}, 1671 | {"a": "I", "b": 52} 1672 | ] 1673 | }, 1674 | "hconcat": [ 1675 | { 1676 | "mark": "circle", 1677 | "encoding": { 1678 | "y": { 1679 | "field": "b", 1680 | "type": "nominal", 1681 | "sort": null, 1682 | "axis": { 1683 | "ticks": false, 1684 | "domain": false, 1685 | "title": null 1686 | } 1687 | }, 1688 | "size": { 1689 | "field": "b", 1690 | "type": "quantitative", 1691 | "scale": { 1692 | "type": "quantize" 1693 | } 1694 | }, 1695 | "color": { 1696 | "field": "b", 1697 | "type": "quantitative", 1698 | "scale": { 1699 | "type": "quantize", 1700 | "zero": true 1701 | }, 1702 | "legend": { 1703 | "title": "Quantize" 1704 | } 1705 | } 1706 | } 1707 | }, 1708 | { 1709 | "mark": "circle", 1710 | "encoding": { 1711 | "y": { 1712 | "field": "b", 1713 | "type": "nominal", 1714 | "sort": null, 1715 | "axis": { 1716 | "ticks": false, 1717 | "domain": false, 1718 | "title": null 1719 | } 1720 | }, 1721 | "size": { 1722 | "field": "b", 1723 | "type": "quantitative", 1724 | "scale": { 1725 | "type": "quantile", 1726 | "range": [80, 160, 240, 320, 400] 1727 | } 1728 | }, 1729 | "color": { 1730 | "field": "b", 1731 | "type": "quantitative", 1732 | "scale": { 1733 | "type": "quantile", 1734 | "scheme": "magma" 1735 | }, 1736 | "legend": { 1737 | "format": "d", 1738 | "title": "Quantile" 1739 | } 1740 | } 1741 | } 1742 | }, 1743 | { 1744 | "mark": "circle", 1745 | "encoding": { 1746 | "y": { 1747 | "field": "b", 1748 | "type": "nominal", 1749 | "sort": null, 1750 | "axis": { 1751 | "ticks": false, 1752 | "domain": false, 1753 | "title": null 1754 | } 1755 | }, 1756 | "size": { 1757 | "field": "b", 1758 | "type": "quantitative", 1759 | "scale": { 1760 | "type": "threshold", 1761 | "domain": [30, 70], 1762 | "range": [80, 200, 320] 1763 | } 1764 | }, 1765 | "color": { 1766 | "field": "b", 1767 | "type": "quantitative", 1768 | "scale": { 1769 | "type": "threshold", 1770 | "domain": [30, 70], 1771 | "scheme": "viridis" 1772 | }, 1773 | "legend": { 1774 | "title": "Threshold" 1775 | } 1776 | } 1777 | } 1778 | } 1779 | ], 1780 | "resolve": { 1781 | "scale": { 1782 | "color": "independent", 1783 | "size": "independent" 1784 | } 1785 | } 1786 | } 1787 | ``` 1788 | 1789 | D2 1790 | ```d2 1791 | D2 Parser: { 1792 | shape: class 1793 | 1794 | # Default visibility is + so no need to specify. 1795 | +reader: io.RuneReader 1796 | readerPos: d2ast.Position 1797 | 1798 | # Private field. 1799 | -lookahead: "[]rune" 1800 | 1801 | # Protected field. 1802 | # We have to escape the # to prevent the line from being parsed as a comment. 1803 | \#lookaheadPos: d2ast.Position 1804 | 1805 | +peek(): (r rune, eof bool) 1806 | rewind() 1807 | commit() 1808 | 1809 | \#peekn(n int): (s string, eof bool) 1810 | } 1811 | 1812 | "github.com/terrastruct/d2parser.git" -> D2 Parser 1813 | ``` 1814 | 1815 | WaveDrom 1816 | ```wavedrom 1817 | { signal: [ 1818 | { name: "clk", wave: "p.....|..." }, 1819 | { name: "Data", wave: "x.345x|=.x", data: ["head", "body", "tail", "data"] }, 1820 | { name: "Request", wave: "0.1..0|1.0" }, 1821 | {}, 1822 | { name: "Acknowledge", wave: "1.....|01." } 1823 | ]} 1824 | ``` 1825 | 1826 | WireViz 1827 | ```wireviz 1828 | connectors: 1829 | X1: 1830 | type: D-Sub 1831 | subtype: female 1832 | pinlabels: [DCD, RX, TX, DTR, GND, DSR, RTS, CTS, RI] 1833 | X2: 1834 | type: Molex KK 254 1835 | subtype: female 1836 | pinlabels: [GND, RX, TX] 1837 | 1838 | cables: 1839 | W1: 1840 | gauge: 0.25 mm2 1841 | length: 0.2 1842 | color_code: DIN 1843 | wirecount: 3 1844 | shield: true 1845 | 1846 | connections: 1847 | - 1848 | - X1: [5,2,3] 1849 | - W1: [1,2,3] 1850 | - X2: [1,3,2] 1851 | - 1852 | - X1: 5 1853 | - W1: s 1854 | ``` 1855 | --------------------------------------------------------------------------------