├── .gitignore ├── docs └── images │ └── Preview.PNG ├── .vscodeignore ├── test.js ├── CHANGELOG.md ├── homebrewery-assets ├── previewSpecific.css └── markdown.css ├── snippets ├── print.json ├── editor.json ├── tables.json └── phb.json ├── .vscode └── launch.json ├── README.md ├── pageBreaks.js ├── package.json └── extension.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .vscode-test/ 3 | *.vsix 4 | *.html 5 | 6 | -------------------------------------------------------------------------------- /docs/images/Preview.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathonius/homebrewery-vscode/HEAD/docs/images/Preview.PNG -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | test/** 4 | .gitignore 5 | jsconfig.json 6 | vsc-extension-quickstart.md 7 | .eslintrc.json 8 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | const Markdown = require('markdown-it'); 2 | const pageBreaks = require('./pageBreaks'); 3 | 4 | const md = new Markdown().use(pageBreaks); 5 | const html = md.render('\\page'); 6 | 7 | console.log(html); -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | ## 0.1.0 3 | - Added brew command to print to HTML 4 | 5 | ## 0.0.4 6 | - Added remaining snippets 7 | - Both manual and auto page numbering work. 8 | 9 | ## 0.0.3 10 | - Added toggle command to enable/disable homebrewery formatting 11 | 12 | ## 0.0.2 13 | - Added most snippets 14 | - Fixed empty file error 15 | 16 | ## 0.0.1 17 | - Initial Release 18 | -------------------------------------------------------------------------------- /homebrewery-assets/previewSpecific.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | line-height: 1; 4 | } 5 | 6 | .phb { 7 | border: 0; 8 | vertical-align: baseline; 9 | } 10 | 11 | .phb h1 { 12 | border-bottom-width: 0px; 13 | } 14 | 15 | .phb p, .phb blockquote, 16 | .phb h1, .phb h2, .phb h3, .phb h4, .phb h5, .phb h6 { 17 | margin: 0; 18 | } 19 | 20 | .phb th { 21 | padding: 0; 22 | } 23 | 24 | .phb table { 25 | border-collapse: collapse; 26 | border-spacing: 0; 27 | vertical-align: baseline; 28 | line-height: 1; 29 | } 30 | 31 | .phb p, .phb h5, .phb h6, .phb li, .phb strong, 32 | .phb th, .phb td, div.classTable h5 { 33 | color: black; 34 | } 35 | 36 | div.classTable tr { 37 | padding: 0; 38 | } -------------------------------------------------------------------------------- /snippets/print.json: -------------------------------------------------------------------------------- 1 | { 2 | "a4Size": { 3 | "scope": "markdown", 4 | "prefix": "brewA4PageSize", 5 | "description": "Apply A4 page size", 6 | "body" : [ 7 | "", 13 | "" 14 | ] 15 | }, 16 | "inkFriendly": { 17 | "scope": "markdown", 18 | "prefix": "brewInkFriendly", 19 | "description": "White backgrounds and hidden images.", 20 | "body": [ 21 | "", 26 | "" 27 | ] 28 | } 29 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that launches the extension inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "type": "node", 10 | "request": "launch", 11 | "name": "Launch Program", 12 | "program": "${workspaceFolder}/test.js" 13 | }, 14 | { 15 | "name": "Extension", 16 | "type": "extensionHost", 17 | "request": "launch", 18 | "runtimeExecutable": "${execPath}", 19 | "args": [ 20 | "--extensionDevelopmentPath=${workspaceFolder}" 21 | ] 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Styles the markdown preview pane like the [Homebrewery](http://homebrewery.naturalcrit.com/), so that you can create 5th Edition D&D homebrew in a more powerful application. 2 | 3 | ![preview-image](https://raw.githubusercontent.com/OfficerHalf/homebrewery-vscode/master/docs/images/Preview.PNG) 4 | 5 | ## Features 6 | - Most markdown and formatting from the Homebrewery is supported. 7 | - Use `\page` to create new pages. 8 | - Most of the same snippets The Homebrewery provides are available with the 'brew' prefix. Ex: `brewStatBlock` 9 | 10 | ## Commands 11 | #### `homebrewery.toggle` 12 | toggles the `homebrewery.enabled` setting 13 | 14 | ### `homebrewery.brew` 15 | print to HTML 16 | 17 | ## Settings 18 | #### `homebrewery.enabled` 19 | use homebrewery formatting in the markdown preview pane. `true` by default. 20 | 21 | ## Usage 22 | For best results, set the following options: 23 | - `"markdown.preview.scrollEditorWithPreview": false` 24 | - `"markdown.preview.scrollPreviewWithEditor": false` 25 | - `"markdown.preview.markEditorSelection": false` 26 | 27 | This prevents the preview jumping around and stops the formatting breaking when mousing over selections in the preview window. 28 | 29 | ## Known Issues 30 | - Any div element used requires a new line between the div and its content 31 | - The HTML rendered by the `homebrewery.brew` command is sometimes _slightly_ different than the preview. 32 | - Images from external URLs may not be shown. This is due to security restrictions on Code's markdown preview. For best results, ensure that all image urls use `https://`. Though it is not recommended, you can also [disable security](https://code.visualstudio.com/docs/languages/markdown#_markdown-preview-security). 33 | - The preview will sometimes scroll to the wrong place. See [Usage](#usage) above. 34 | 35 | ## To-Do List 36 | - Allow for alternate styles and color palettes 37 | --- 38 | ## Release Notes 39 | ### 0.1.0 40 | - Added brew command to print to HTML 41 | 42 | ### 0.0.4 43 | - Added remaining snippets 44 | - Both manual and auto page numbering work. 45 | 46 | ### 0.0.3 47 | - Added toggle command to enable/disable homebrewery formatting 48 | 49 | See [Changelog](CHANGELOG.md) for more. 50 | -------------------------------------------------------------------------------- /pageBreaks.js: -------------------------------------------------------------------------------- 1 | const vscode = require('vscode'); 2 | 3 | function homebreweryEnabled() { 4 | return vscode.workspace.getConfiguration('homebrewery').get('enabled'); 5 | } 6 | 7 | function addWrapper(state) { 8 | if(state.tokens.length === 0 || !homebreweryEnabled()) { 9 | return; 10 | } 11 | if(state.tokens[0].type !== 'pageBr_open') { 12 | const open = new state.Token('pageBr_open', 'div', 1); 13 | open.attrPush(['class', 'phb']); 14 | open.attrPush(['id', 'p1']); 15 | open.attrPush(['style', 'margin-bottom: 30px;']); 16 | state.tokens.splice(0, 0, open); 17 | } 18 | if(state.tokens[state.tokens.length - 1].type !== 'pageBr_close') { 19 | const close = new state.Token('pageBr_close', 'div', -1); 20 | state.tokens.push(close); 21 | } 22 | } 23 | 24 | function replacePages(state) { 25 | if(state.tokens.length === 0 || !homebreweryEnabled()) { 26 | return; 27 | } 28 | 29 | let currentPage = 2; 30 | 31 | for (let i = state.tokens.length - 1; i >= 0; i--) { 32 | if (state.tokens[i].type !== 'inline') { continue; } 33 | if(state.tokens[i].content === '\\page') { 34 | let token; 35 | const inlineTokens = state.tokens[i].children; 36 | for(let j = inlineTokens.length - 1; j >= 0; j--) { 37 | token = inlineTokens[j]; 38 | if(token.type === 'text') { 39 | if(token.content === '\\page') { 40 | replaceToken(state, i, currentPage); 41 | currentPage++; 42 | break; 43 | } 44 | } 45 | } 46 | } 47 | } 48 | } 49 | 50 | function replaceToken(state, tokenPos, currentPage) { 51 | const close = new state.Token('pageBr_close', 'div', -1); 52 | const open = new state.Token('pageBr_open', 'div', 1); 53 | open.attrPush(['class', 'phb']); 54 | open.attrPush(['style', 'margin-bottom: 30px;']); 55 | open.attrPush(['id', `p${currentPage}`]) 56 | 57 | state.tokens[tokenPos-1] = close; 58 | state.tokens[tokenPos+1] = open; 59 | state.tokens.splice(tokenPos, 1); 60 | } 61 | 62 | module.exports = function replacePages_plugin(md, scheme) { 63 | md.core.ruler.before('replacements', 'homebrewery_wrapper', addWrapper); 64 | md.core.ruler.after('homebrewery_wrapper', 'homebrewery_pages', replacePages); 65 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "homebrewery-vscode", 3 | "displayName": "Homebrewery Markdown Preview", 4 | "description": "Renders markdown in the preview pane like the Homebrewery", 5 | "version": "0.1.0", 6 | "publisher": "officerhalf", 7 | "keywords": [ 8 | "markdown", 9 | "dnd", 10 | "homebrew", 11 | "homebrewery", 12 | "naturalcrit" 13 | ], 14 | "license": "MIT", 15 | "repository": { 16 | "url": "https://github.com/OfficerHalf/homebrewery-vscode.git" 17 | }, 18 | "bugs": { 19 | "url": "https://github.com/OfficerHalf/homebrewery-vscode/issues" 20 | }, 21 | "engines": { 22 | "vscode": "^1.23.0" 23 | }, 24 | "categories": [ 25 | "Other" 26 | ], 27 | "activationEvents": [ 28 | "onCommand:homebrewery.toggle", 29 | "onCommand:homebrewery.brew" 30 | ], 31 | "main": "./extension.js", 32 | "contributes": { 33 | "configuration": { 34 | "type": "object", 35 | "title": "Homebrewery configuration", 36 | "properties": { 37 | "homebrewery.enabled": { 38 | "type": "boolean", 39 | "default": true, 40 | "description": "Use homebrewery formatting in markdown preview pane" 41 | } 42 | } 43 | }, 44 | "commands": [ 45 | { 46 | "command": "homebrewery.toggle", 47 | "title": "Toggle Homebrewery Preview", 48 | "category": "Homebrewery" 49 | }, 50 | { 51 | "command": "homebrewery.brew", 52 | "title": "Print to HTML", 53 | "category": "Homebrewery" 54 | } 55 | ], 56 | "markdown.previewStyles": [ 57 | "./homebrewery-assets/previewSpecific.css", 58 | "./homebrewery-assets/phb.standaloneReduced.css" 59 | ], 60 | "markdown.markdownItPlugins": true, 61 | "snippets": [ 62 | { 63 | "language": "markdown", 64 | "path": "./snippets/phb.json" 65 | }, 66 | { 67 | "language": "markdown", 68 | "path": "./snippets/tables.json" 69 | }, 70 | { 71 | "language": "markdown", 72 | "path": "./snippets/editor.json" 73 | }, 74 | { 75 | "language": "markdown", 76 | "path": "./snippets/print.json" 77 | } 78 | ] 79 | }, 80 | "scripts": { 81 | "postinstall": "node ./node_modules/vscode/bin/install" 82 | }, 83 | "devDependencies": { 84 | "vscode": "^1.1.29" 85 | }, 86 | "dependencies": { 87 | "ncp": "^2.0.0" 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /extension.js: -------------------------------------------------------------------------------- 1 | const vscode = require('vscode'); 2 | const pageBreaks = require('./pageBreaks'); 3 | const path = require('path'); 4 | const ncp = require('ncp').ncp; 5 | const fs = require('fs'); 6 | 7 | let ogMD; 8 | 9 | function brew() { 10 | const editor = vscode.window.activeTextEditor; 11 | const doc = editor.document; 12 | 13 | if(!editor || doc.languageId != 'markdown') { 14 | vscode.window.showErrorMessage('Homebrewery: No valid Markdown file'); 15 | return; 16 | } 17 | 18 | else if(doc.isUntitled) { 19 | vscode.window.showErrorMessage('Homebrewery: Please save the file first'); 20 | return; 21 | } 22 | 23 | if(doc.isDirty) { 24 | doc.save(); 25 | } 26 | 27 | vscode.window.setStatusBarMessage(`Printing '${path.basename(doc.fileName)}' to HTML ...`, 1000); 28 | let outPath = doc.fileName.replace(/\.\w+?$/, `.html`); 29 | outPath = outPath.replace(/^([cdefghij]):\\/, function (match, p1) { 30 | return `${p1.toUpperCase()}:\\`; // Capitalize drive letter 31 | }); 32 | if(!outPath.endsWith('.html')) { 33 | outPath += '.html'; 34 | } 35 | 36 | // const md = new Markdown({html: true}).use(pageBreaks); 37 | const body = ogMD.render(doc.getText()); 38 | const html = ` 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | ${body} 48 | 49 | `; 50 | 51 | fs.writeFile(outPath, html, 'utf-8', function (err) { 52 | if (err) { console.log(err); } 53 | }); 54 | 55 | const assetPath = path.join(vscode.extensions.getExtension('officerhalf.homebrewery-vscode').extensionPath, 'homebrewery-assets'); 56 | ncp(assetPath, path.dirname(outPath), (err) => { 57 | if(err) { 58 | console.error(err); 59 | } 60 | }); 61 | } 62 | 63 | function activate(context) { 64 | context.subscriptions.push(vscode.commands.registerCommand('homebrewery.brew', brew)); 65 | 66 | context.subscriptions.push(vscode.commands.registerCommand('homebrewery.toggle', () =>{ 67 | const settings = vscode.workspace.getConfiguration('homebrewery'); 68 | settings.update('enabled', !settings.get('enabled'), true); 69 | })); 70 | 71 | context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(cfg => { 72 | if(cfg.affectsConfiguration('homebrewery.enabled')) { 73 | vscode.commands.executeCommand('markdown.preview.refresh', undefined); 74 | } 75 | })); 76 | 77 | return { 78 | extendMarkdownIt(md) { 79 | ogMD = md; 80 | return md.use(pageBreaks); 81 | } 82 | }; 83 | } 84 | 85 | exports.activate = activate; -------------------------------------------------------------------------------- /snippets/editor.json: -------------------------------------------------------------------------------- 1 | { 2 | "columnBreak": { 3 | "scope": "markdown", 4 | "prefix": "brewColumnBreak", 5 | "description": "Begin a new column", 6 | "body": [ 7 | "```", 8 | "```", 9 | "" 10 | ] 11 | }, 12 | "newPage": { 13 | "scope": "markdown", 14 | "prefix": "brewNewPage", 15 | "description": "Begin a new page", 16 | "body": "\\page" 17 | }, 18 | "verticalSpacing": { 19 | "scope": "markdown", 20 | "prefix": "brewVerticalSpacing", 21 | "description": "Add a margin between two elements", 22 | "body": [ 23 | "
", 24 | "", 25 | "" 26 | ] 27 | }, 28 | "wideBlock": { 29 | "scope": "markdown", 30 | "prefix": "brewWideBlock", 31 | "description": "Span the page", 32 | "body": [ 33 | "
", 34 | "", 35 | "Everything in here will be extra wide. Tables, text, everything! Beware though, CSS columns can behave a bit weird sometimes.", 36 | "
", 37 | "" 38 | ] 39 | }, 40 | "image": { 41 | "scope": "markdown", 42 | "prefix": "brewImage", 43 | "description": "Add an image. May not render in Code.", 44 | "body": [ 45 | "", 48 | "Credit: Kyounghwan Kim" 49 | ] 50 | }, 51 | "backgroundImage": { 52 | "scope": "markdown", 53 | "prefix": "brewBackgroundImage", 54 | "description": "Add a background image. May not render in Code.", 55 | "body": [ 56 | "" 59 | ] 60 | }, 61 | "pageNumber": { 62 | "scope": "markdown", 63 | "prefix": "brewPageNumber", 64 | "description": "Add a page number to the bottom of the page.", 65 | "body": [ 66 | "
1
", 67 | "
PART 1 | FANCINESS
", 68 | "", 69 | "" 70 | ] 71 | }, 72 | "autoPageNumber": { 73 | "scope": "markdown", 74 | "prefix": "brewAutoPageNumber", 75 | "description": "Add a page number to the bottom of the page.", 76 | "body": [ 77 | "
", 78 | "" 79 | ] 80 | }, 81 | "pageLink": { 82 | "scope": "markdown", 83 | "prefix": "brewPageLink", 84 | "description": "A link to a specific page number", 85 | "body": "[Click here](#p3) to go to page 3" 86 | }, 87 | "tableOfContents": { 88 | "scope": "markdown", 89 | "prefix": "brewTOC", 90 | "description": "A table of contents", 91 | "body": [ 92 | "
", 93 | "", 94 | "##### Table Of Contents", 95 | "", 96 | "
", 97 | "" 98 | ] 99 | } 100 | } -------------------------------------------------------------------------------- /homebrewery-assets/markdown.css: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | body { 7 | font-family: "Segoe WPC", "Segoe UI", "SFUIText-Light", "HelveticaNeue-Light", sans-serif, "Droid Sans Fallback"; 8 | font-size: 14px; 9 | padding: 0 26px; 10 | line-height: 22px; 11 | word-wrap: break-word; 12 | } 13 | 14 | #code-csp-warning { 15 | position: fixed; 16 | top: 0; 17 | right: 0; 18 | color: white; 19 | margin: 16px; 20 | text-align: center; 21 | font-size: 12px; 22 | font-family: sans-serif; 23 | background-color:#444444; 24 | cursor: pointer; 25 | padding: 6px; 26 | box-shadow: 1px 1px 1px rgba(0,0,0,.25); 27 | } 28 | 29 | #code-csp-warning:hover { 30 | text-decoration: none; 31 | background-color:#007acc; 32 | box-shadow: 2px 2px 2px rgba(0,0,0,.25); 33 | } 34 | 35 | 36 | body.scrollBeyondLastLine { 37 | margin-bottom: calc(100vh - 22px); 38 | } 39 | 40 | body.showEditorSelection .code-line { 41 | position: relative; 42 | } 43 | 44 | body.showEditorSelection .code-active-line:before, 45 | body.showEditorSelection .code-line:hover:before { 46 | content: ""; 47 | display: block; 48 | position: absolute; 49 | top: 0; 50 | left: -12px; 51 | height: 100%; 52 | } 53 | 54 | body.showEditorSelection li.code-active-line:before, 55 | body.showEditorSelection li.code-line:hover:before { 56 | left: -30px; 57 | } 58 | 59 | .vscode-light.showEditorSelection .code-active-line:before { 60 | border-left: 3px solid rgba(0, 0, 0, 0.15); 61 | } 62 | 63 | .vscode-light.showEditorSelection .code-line:hover:before { 64 | border-left: 3px solid rgba(0, 0, 0, 0.40); 65 | } 66 | 67 | .vscode-light.showEditorSelection .code-line .code-line:hover:before { 68 | border-left: none; 69 | } 70 | 71 | .vscode-dark.showEditorSelection .code-active-line:before { 72 | border-left: 3px solid rgba(255, 255, 255, 0.4); 73 | } 74 | 75 | .vscode-dark.showEditorSelection .code-line:hover:before { 76 | border-left: 3px solid rgba(255, 255, 255, 0.60); 77 | } 78 | 79 | .vscode-dark.showEditorSelection .code-line .code-line:hover:before { 80 | border-left: none; 81 | } 82 | 83 | .vscode-high-contrast.showEditorSelection .code-active-line:before { 84 | border-left: 3px solid rgba(255, 160, 0, 0.7); 85 | } 86 | 87 | .vscode-high-contrast.showEditorSelection .code-line:hover:before { 88 | border-left: 3px solid rgba(255, 160, 0, 1); 89 | } 90 | 91 | .vscode-high-contrast.showEditorSelection .code-line .code-line:hover:before { 92 | border-left: none; 93 | } 94 | 95 | img { 96 | max-width: 100%; 97 | max-height: 100%; 98 | } 99 | 100 | a { 101 | text-decoration: none; 102 | } 103 | 104 | a:hover { 105 | text-decoration: underline; 106 | } 107 | 108 | a:focus, 109 | input:focus, 110 | select:focus, 111 | textarea:focus { 112 | outline: 1px solid -webkit-focus-ring-color; 113 | outline-offset: -1px; 114 | } 115 | 116 | hr { 117 | border: 0; 118 | height: 2px; 119 | border-bottom: 2px solid; 120 | } 121 | 122 | h1 { 123 | padding-bottom: 0.3em; 124 | line-height: 1.2; 125 | border-bottom-width: 1px; 126 | border-bottom-style: solid; 127 | } 128 | 129 | h1, h2, h3 { 130 | font-weight: normal; 131 | } 132 | 133 | h1 code, 134 | h2 code, 135 | h3 code, 136 | h4 code, 137 | h5 code, 138 | h6 code { 139 | font-size: inherit; 140 | line-height: auto; 141 | } 142 | 143 | table { 144 | border-collapse: collapse; 145 | } 146 | 147 | table > thead > tr > th { 148 | text-align: left; 149 | border-bottom: 1px solid; 150 | } 151 | 152 | table > thead > tr > th, 153 | table > thead > tr > td, 154 | table > tbody > tr > th, 155 | table > tbody > tr > td { 156 | padding: 5px 10px; 157 | } 158 | 159 | table > tbody > tr + tr > td { 160 | border-top: 1px solid; 161 | } 162 | 163 | blockquote { 164 | margin: 0 7px 0 5px; 165 | padding: 0 16px 0 10px; 166 | border-left-width: 5px; 167 | border-left-style: solid; 168 | } 169 | 170 | code { 171 | font-family: Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback"; 172 | font-size: 14px; 173 | line-height: 19px; 174 | } 175 | 176 | body.wordWrap pre { 177 | white-space: pre-wrap; 178 | } 179 | 180 | .mac code { 181 | font-size: 12px; 182 | line-height: 18px; 183 | } 184 | 185 | pre:not(.hljs), 186 | pre.hljs code > div { 187 | padding: 16px; 188 | border-radius: 3px; 189 | overflow: auto; 190 | } 191 | 192 | /** Theming */ 193 | 194 | pre code { 195 | color: var(--vscode-editor-foreground); 196 | } 197 | 198 | 199 | .vscode-light pre:not(.hljs), 200 | .vscode-light code > div { 201 | background-color: rgba(220, 220, 220, 0.4); 202 | } 203 | 204 | .vscode-dark pre:not(.hljs), 205 | .vscode-dark code > div { 206 | background-color: rgba(10, 10, 10, 0.4); 207 | } 208 | 209 | .vscode-high-contrast pre:not(.hljs), 210 | .vscode-high-contrast code > div { 211 | background-color: rgb(0, 0, 0); 212 | } 213 | 214 | .vscode-high-contrast h1 { 215 | border-color: rgb(0, 0, 0); 216 | } 217 | 218 | .vscode-light table > thead > tr > th { 219 | border-color: rgba(0, 0, 0, 0.69); 220 | } 221 | 222 | .vscode-dark table > thead > tr > th { 223 | border-color: rgba(255, 255, 255, 0.69); 224 | } 225 | 226 | .vscode-light h1, 227 | .vscode-light hr, 228 | .vscode-light table > tbody > tr + tr > td { 229 | border-color: rgba(0, 0, 0, 0.18); 230 | } 231 | 232 | .vscode-dark h1, 233 | .vscode-dark hr, 234 | .vscode-dark table > tbody > tr + tr > td { 235 | border-color: rgba(255, 255, 255, 0.18); 236 | } 237 | -------------------------------------------------------------------------------- /snippets/tables.json: -------------------------------------------------------------------------------- 1 | { 2 | "classTableWide": { 3 | "scope": "markdown", 4 | "prefix": "brewClassTable", 5 | "description": "A two column class table", 6 | "body": [ 7 | "
", 8 | "", 9 | "##### The Fancyman", 10 | "| Level | Proficiency Bonus | Features | Cantrips Known | Spells Known | 1st | 2nd | 3rd | 4th | 5th | 6th | 7th | 8th | 9th |", 11 | "|:---:|:---:|:---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|", 12 | "| 1st | +2 | ─ | 3 | 1 | 2 | — | — | — | — | — | — | — | — |", 13 | "| 2nd | +2 | Demonic Anthropology | 4 | 2 | 3 | — | — | — | — | — | — | — | — |", 14 | "| 3rd | +2 | Biochemical Sorcery | 4 | 3 | 4 | 1 | — | — | — | — | — | — | — |", 15 | "| 4th | +2 | Ability Score Improvement, Sixgun Poisoner | 5 | 3 | 4 | 2 | — | — | — | — | — | — | — |", 16 | "| 5th | +3 | Pharmaceutical Gunslinger | 5 | 3 | 4 | 3 | 1 | — | — | — | — | — | — |", 17 | "| 6th | +3 | Ability Score Improvement, Spiritual Biochemistry | 6 | 3 | 4 | 3 | 1 | — | — | — | — | — | — |", 18 | "| 7th | +3 | Mathematical Pharmacist | 6 | 4 | 4 | 3 | 1 | — | — | — | — | — | — |", 19 | "| 8th | +3 | Ability Score Improvement | 7 | 5 | 4 | 3 | 1 | — | — | — | — | — | — |", 20 | "| 9th | +4 | Police Cultist | 8 | 5 | 4 | 3 | 1 | — | — | — | — | — | — |", 21 | "| 10th | +4 | Consecrated Biochemistry | 9 | 5 | 4 | 3 | 1 | — | — | — | — | — | — |", 22 | "| 11th | +4 | Pharmaceutical Gunslinger | 9 | 5 | 4 | 3 | 2 | — | — | — | — | — | — |", 23 | "| 12th | +4 | Ability Score Improvement, Sixgun Poisoner | 10 | 5 | 4 | 3 | 3 | 1 | — | — | — | — | — |", 24 | "| 13th | +5 | Spiritual Biochemistry | 10 | 5 | 4 | 3 | 3 | 3 | — | — | — | — | — |", 25 | "| 14th | +5 | Ability Score Improvement, Spiritual Biochemistry | 11 | 6 | 4 | 3 | 3 | 3 | 1 | — | — | — | — |", 26 | "| 15th | +5 | Malefic Chemist | 11 | 7 | 4 | 3 | 3 | 3 | 3 | — | — | — | — |", 27 | "| 16th | +5 | Ability Score Improvement, Nuclear Illusionism | 12 | 8 | 4 | 3 | 3 | 3 | 3 | — | — | — | — |", 28 | "| 17th | +6 | Astrological Botany | 12 | 8 | 4 | 3 | 3 | 3 | 3 | — | — | — | — |", 29 | "| 18th | +6 | Civil Alchemy | 13 | 8 | 4 | 3 | 3 | 3 | 3 | 2 | — | — | — |", 30 | "| 19th | +6 | Ability Score Improvement | 14 | 9 | 4 | 3 | 3 | 3 | 3 | 2 | — | — | — |", 31 | "| 20th | +6 | Malefic Chemist | 15 | 10 | 4 | 3 | 3 | 3 | 3 | 2 | — | — | — |", 32 | "
", 33 | "" 34 | ] 35 | }, 36 | "classTable": { 37 | "scope": "markdown", 38 | "prefix": "brewHalfClassTable", 39 | "description": "A single column class table", 40 | "body": [ 41 | "
", 42 | "", 43 | "##### The Fancyman", 44 | "| Level | Proficiency Bonus | Features | Seismological Divination|", 45 | "|:---:|:---:|:---|:---:|", 46 | "| 1st | +2 | Genetic Banishing | +1 |", 47 | "| 2nd | +2 | Hermetic Geography | +1 |", 48 | "| 3rd | +2 | Phased Linguist | +2 |", 49 | "| 4th | +2 | Ability Score Improvement, Spell Analyst | +3 |", 50 | "| 5th | +3 | ─ | +4 |", 51 | "| 6th | +3 | Ability Score Improvement, Plasma Outlaw | +4 |", 52 | "| 7th | +3 | Infernal Banker | +4 |", 53 | "| 8th | +3 | Ability Score Improvement, Phased Linguist | +4 |", 54 | "| 9th | +4 | Spiritual Biochemistry | +4 |", 55 | "| 10th | +4 | ─ | +4 |", 56 | "| 11th | +4 | Seismological Divination | +4 |", 57 | "| 12th | +4 | Ability Score Improvement | +5 |", 58 | "| 13th | +5 | Gunslinger Corruptor | +6 |", 59 | "| 14th | +5 | Ability Score Improvement | +7 |", 60 | "| 15th | +5 | Spiritual Biochemistry | +7 |", 61 | "| 16th | +5 | Ability Score Improvement, Exo Interfacer | +8 |", 62 | "| 17th | +6 | Biochemical Sorcery | +9 |", 63 | "| 18th | +6 | Pharmaceutical Gunslinger | +9 |", 64 | "| 19th | +6 | Ability Score Improvement | +10 |", 65 | "| 20th | +6 | Police Cultist | +11 |", 66 | "
", 67 | "" 68 | ] 69 | }, 70 | "table": { 71 | "scope": "markdown", 72 | "prefix": "brewTable", 73 | "description": "A single column table", 74 | "body": [ 75 | "##### Cookie Tastiness", 76 | "| Tastiness | Cookie Type |", 77 | "|:----:|:-------------|", 78 | "| -5 | Raisin |", 79 | "| 8th | Chocolate Chip |", 80 | "| 11th | 2 or lower |", 81 | "| 14th | 3 or lower |", 82 | "| 17th | 4 or lower |", 83 | "" 84 | ] 85 | }, 86 | "tableWide": { 87 | "scope": "markdown", 88 | "prefix": "brewWideTable", 89 | "description": "A two column table", 90 | "body": [ 91 | "
", 92 | "", 93 | "##### Cookie Tastiness", 94 | "| Tastiness | Cookie Type |", 95 | "|:----:|:-------------|", 96 | "| -5 | Raisin |", 97 | "| 8th | Chocolate Chip |", 98 | "| 11th | 2 or lower |", 99 | "| 14th | 3 or lower |", 100 | "| 17th | 4 or lower |", 101 | "
", 102 | "" 103 | ] 104 | }, 105 | "tableSplit": { 106 | "scope": "markdown", 107 | "prefix": "brewSplitTable", 108 | "description": "A two column table that fits in a single page column", 109 | "body": [ 110 | "
", 111 | "", 112 | "| d10 | Damage Type |", 113 | "|:---:|:------------|", 114 | "| 1 | Acid |", 115 | "| 2 | Cold |", 116 | "| 3 | Fire |", 117 | "| 4 | Force |", 118 | "| 5 | Lightning |", 119 | "", 120 | "```", 121 | "```", 122 | "", 123 | "| d10 | Damage Type |", 124 | "|:---:|:------------|", 125 | "| 6 | Necrotic |", 126 | "| 7 | Poison |", 127 | "| 8 | Psychic |", 128 | "| 9 | Radiant |", 129 | "| 10 | Thunder |", 130 | "
", 131 | "" 132 | ] 133 | } 134 | } -------------------------------------------------------------------------------- /snippets/phb.json: -------------------------------------------------------------------------------- 1 | { 2 | "spell": { 3 | "scope": "markdown", 4 | "prefix": "brewSpell", 5 | "description": "A spell block", 6 | "body": [ 7 | "#### Ball of Annoyance", 8 | "*1st-level illusion*", 9 | "___", 10 | "- **Casting Time:** 1 action", 11 | "- **Range:** 30 feet", 12 | "- **Components:** M, S, V (a crushed button worth at least 1cp, a small doll)", 13 | "- **Duration:** Concentration, up to 10 minutes", 14 | "", 15 | "A flame, equivalent in brightness to a torch, springs from from an object that you touch. ", 16 | "The effect look like a regular flame, but it creates no heat and doesn't use oxygen. ", 17 | "A *continual flame* can be covered or hidden but not smothered or quenched.", 18 | "" 19 | ] 20 | }, 21 | "spellList": { 22 | "scope": "markdown", 23 | "prefix": "brewSpellList", 24 | "description": "A spell list", 25 | "body": [ 26 | "
", 27 | "", 28 | "##### Cantrips (0 Level) ", 29 | "- Heal Bad Hygene", 30 | "- Sorcerous Dandruff Globe", 31 | "- Illusionary Transfiguration of the Babysitter", 32 | "- Mystic Spell of the Poser", 33 | "- Hellish Cage of Mucus", 34 | "- Sorcerous Enchantment of the Chimneysweep", 35 | "- Ball of Annoyance", 36 | "- Spiritual Invocation of the Costumers", 37 | "- Dispell Piles in Dentist", 38 | "- Divine Spell of Crossdressing", 39 | "- Irritate Peanut Butter Fairy ", 40 | "", 41 | "##### 2nd Level ", 42 | "- Sorcerous Enchantment of the Chimneysweep", 43 | "- Illusionary Transfiguration of the Babysitter", 44 | "- Occult Transfiguration of Foot Fetish", 45 | "- Talk to Groupie", 46 | "- Erruption of Immaturity", 47 | "- Create Acne", 48 | "- Overwhelming Enchantment of the Chocolate Fairy", 49 | "- Flaming Disc of Inconvenience", 50 | "- Luminous Erruption of Tea", 51 | "- Tinsel Blast", 52 | "- Spiritual Invocation of the Costumers", 53 | "- Dominate Ramen Giant", 54 | "- Astral Rite of Acne", 55 | "- Alchemical Evocation of the Goths", 56 | "- Occult Globe of Salad Dressing ", 57 | "", 58 | "##### 3rd Level ", 59 | "- Ball of Annoyance", 60 | "- Eliminate Florists", 61 | "- Steak Sauce Ray", 62 | "- Erruption of Immaturity", 63 | "- Create Nervousness ", 64 | "", 65 | "##### 4th Level ", 66 | "- Protection from Mucus Giant", 67 | "- Ultimate Ritual of Mouthwash", 68 | "- Dispell Piles in Dentist", 69 | "- Alchemical Evocation of the Goths", 70 | "- Occult Globe of Salad Dressing", 71 | "- Cage of Yarn", 72 | "- Heal Bad Hygene", 73 | "- Create Acne ", 74 | "", 75 | "##### 5th Level ", 76 | "- Hellish Cage of Mucus", 77 | "- Necromantic Armor of Salad Dressing", 78 | "- Spiritual Invocation of the Costumers", 79 | "- Illusionary Transfiguration of the Babysitter", 80 | "- Overwhelming Enchantment of the Chocolate Fairy", 81 | "- Tinsel Blast", 82 | "- Cursed Ritual of Bad Hair", 83 | "- Occult Globe of Salad Dressing", 84 | "- Heavenly Transfiguration of the Cream Devil", 85 | "- Steak Sauce Ray", 86 | "- Occult Transfiguration of Foot Fetish", 87 | "- Irritate Peanut Butter Fairy ", 88 | "", 89 | "##### 6th Level ", 90 | "- Eliminate Vindictiveness in Gym Teacher", 91 | "- Astounding Pasta Puddle", 92 | "- Heavenly Transfiguration of the Cream Devil", 93 | "- Talk to Groupie", 94 | "- Ball of Annoyance ", 95 | "", 96 | "##### 7th Level ", 97 | "- Cursed Ritual of Bad Hair", 98 | "- Ultimate Rite of the Confetti Angel", 99 | "- Erruption of Immaturity", 100 | "- Eliminate Florists", 101 | "- Dominate Ramen Giant", 102 | "- Ball of Annoyance", 103 | "- Sorcerous Enchantment of the Chimneysweep", 104 | "- Luminous Erruption of Tea", 105 | "- Tinsel Blast", 106 | "- Heal Bad Hygene", 107 | "- Ultimate Ritual of Mouthwash", 108 | "- Cure Baldness", 109 | "- Create Nervousness", 110 | "- Irritate Peanut Butter Fairy", 111 | "- Alchemical Evocation of the Goths ", 112 | "", 113 | "##### 8th Level ", 114 | "- Cure Baldness", 115 | "- Divine Spell of Crossdressing", 116 | "- Create Acne", 117 | "- Luminous Erruption of Tea", 118 | "- Call Fangirl", 119 | "- Overwhelming Enchantment of the Chocolate Fairy", 120 | "- Cursed Ritual of Bad Hair", 121 | "- Create Nervousness ", 122 | "", 123 | "##### 9th Level ", 124 | "- Heavenly Transfiguration of the Cream Devil", 125 | "- Create Nervousness", 126 | "- Astounding Pasta Puddle", 127 | "- Occult Globe of Salad Dressing", 128 | "- Steak Sauce Ray", 129 | "- Cursed Ramen Erruption", 130 | "- Irritate Peanut Butter Fairy", 131 | "- Erruption of Immaturity", 132 | "- Protection from Mucus Giant", 133 | "- Luminous Erruption of Tea ", 134 | "", 135 | "
" 136 | ] 137 | }, 138 | "classFeature": { 139 | "scope": "markdown", 140 | "prefix": "brewClassFeature", 141 | "description": "The beginnings of a class", 142 | "body": [ 143 | "## Class Features", 144 | "As a fancyman, you gain the following class features", 145 | "#### Hit Points", 146 | "___", 147 | "- **Hit Dice:** 1d8 per fancyman level", 148 | "- **Hit Points at 1st Level:** 8 + your Constitution modifier", 149 | "- **Hit Points at Higher Levels:** 1d8 (or 5) + your Constitution modifier per fancyman level after 1st", 150 | "", 151 | "#### Proficiencies", 152 | "___", 153 | "- **Armor:** Light armor, Heavy armor", 154 | "- **Weapons:** Martial weapons, Squeegee", 155 | "- **Tools:** one musical instrument", 156 | "", 157 | "___", 158 | "- **Saving Throws:** Constitution, Dexerity", 159 | "- **Skills:** Choose two from Investigation, Intimidation, Athletics, Sleight of Hand, Perception, Medicine", 160 | "", 161 | "#### Equipment", 162 | "You start with the following equipment, in addition to the equipment granted by your background:", 163 | "- *(a)* a martial weapon and a shield or *(b)* two martial weapons", 164 | "- *(a)* five javelins or *(b)* any simple melee weapon", 165 | "- a cherished lost sock", 166 | "", 167 | "" 168 | ] 169 | }, 170 | "note": { 171 | "scope": "markdown", 172 | "prefix": "brewNote", 173 | "description": "Use a note to point out interesting info.", 174 | "body": [ 175 | "> ##### Time to Drop Knowledge", 176 | "> Use notes to point out some interesting information. ", 177 | "> ", 178 | "> **Tables and lists** both work within a note." 179 | ] 180 | }, 181 | "descriptive": { 182 | "scope": "markdown", 183 | "prefix": "brewDescriptive", 184 | "description": "Use descriptions to set a scene.", 185 | "body": [ 186 | "
", 187 | "", 188 | "##### Time to Drop Knowledge", 189 | "Use notes to point out some interesting information. ", 190 | "", 191 | "**Tables and lists** both work within a note.", 192 | "
" 193 | ] 194 | }, 195 | "statBlock": { 196 | "scope": "markdown", 197 | "prefix": "brewStatBlock", 198 | "description": "A single column monster stat block", 199 | "body": [ 200 | "___", 201 | "> ## Gum Elemental", 202 | ">*Large fiend, lawful bogus*", 203 | "> ___", 204 | "> - **Armor Class** 20", 205 | "> - **Hit Points** 30(1d4 + 5)", 206 | "> - **Speed** 26ft.", 207 | ">___", 208 | ">|STR|DEX|CON|INT|WIS|CHA|", 209 | ">|:---:|:---:|:---:|:---:|:---:|:---:|", 210 | ">|16 (+3)|15 (+3)|7 (-1)|12 (+1)|12 (+1)|5 (-2)|", 211 | ">___", 212 | "> - **Condition Immunities** None", 213 | "> - **Senses** passive Perception 7", 214 | "> - **Languages** Latin, Jive", 215 | "> - **Challenge** 12 (5345 XP)", 216 | "> ___", 217 | "> ***Pack Tactics.*** These guys work together. Like super well, you don't even know.", 218 | "> ### Actions", 219 | "> ***Gory Body Sweep.*** *Melee Weapon Attack:* +4 to hit, reach 5ft., one target. *Hit* 5 (1d6 + 2) ", 220 | "" 221 | ] 222 | }, 223 | "statBlockWide": { 224 | "scope": "markdown", 225 | "prefix": "brewWideStatBlock", 226 | "description": "A monster stat block that spans two columns", 227 | "body": [ 228 | "___", 229 | "___", 230 | "> ## Gum Elemental", 231 | ">*Tiny annoyance, narrow-minded neutral*", 232 | "> ___", 233 | "> - **Armor Class** 19", 234 | "> - **Hit Points** 2(1d4 + 5)", 235 | "> - **Speed** 37ft.", 236 | ">___", 237 | ">|STR|DEX|CON|INT|WIS|CHA|", 238 | ">|:---:|:---:|:---:|:---:|:---:|:---:|", 239 | ">|9 (+0)|9 (+0)|11 (+1)|13 (+2)|5 (-2)|13 (+2)|", 240 | ">___", 241 | "> - **Condition Immunities** buzzed, melancholy", 242 | "> - **Senses** passive Perception 3", 243 | "> - **Languages** None", 244 | "> - **Challenge** 10 (8167 XP)", 245 | "> ___", 246 | "> ***Pack Tactics.*** These guys work together. Like super well, you don't even know.", 247 | ">", 248 | "> ***Pack Tactics.*** These guys work together. Like super well, you don't even know.", 249 | ">", 250 | "> ***Pack Tactics.*** These guys work together. Like super well, you don't even know.", 251 | ">", 252 | "> ***Pack Tactics.*** These guys work together. Like super well, you don't even know.", 253 | ">", 254 | "> ***False Appearance. *** While the armor reamin motionless, it is indistinguishable from a normal suit of armor.", 255 | ">", 256 | "> ***Pack Tactics.*** These guys work together. Like super well, you don't even know.", 257 | "> ### Actions", 258 | "> ***Crossed Splash.*** *Melee Weapon Attack:* +4 to hit, reach 5ft., one target. *Hit* 5 (1d6 + 2) ", 259 | ">", 260 | "> ***Somersault Stump Fists.*** *Melee Weapon Attack:* +4 to hit, reach 5ft., one target. *Hit* 5 (1d6 + 2) ", 261 | ">", 262 | "> ***Tilt-a-whirl Eye Takedown.*** *Melee Weapon Attack:* +4 to hit, reach 5ft., one target. *Hit* 5 (1d6 + 2) ", 263 | ">", 264 | "> ***Bulldog Rake.*** *Melee Weapon Attack:* +4 to hit, reach 5ft., one target. *Hit* 5 (1d6 + 2) ", 265 | "" 266 | ] 267 | }, 268 | "coverpage": { 269 | "scope": "markdown", 270 | "prefix": "brewCoverPage", 271 | "description": "A cover page with subtitle", 272 | "body": [ 273 | "", 277 | "", 278 | "
", 279 | "", 280 | "# Yellow Divinity", 281 | "", 282 | "
", 283 | "
", 284 | "", 285 | "##### In a land of corruption, two cyberneticists and a dungeon delver search for freedom.", 286 | "
", 287 | "", 288 | "\\page", 289 | "" 290 | ] 291 | } 292 | } --------------------------------------------------------------------------------