handleMouseMove(e)}
95 | onMouseOver={e => handleMouseOver(e)}
96 | onMouseDown={e => handleMouseDown(e)}
97 | />
98 | )
99 | }
100 |
--------------------------------------------------------------------------------
/src/utils/saveToDropbox.js:
--------------------------------------------------------------------------------
1 | //import domtoimage from "dom-to-image"
2 | import { saveSvgAsPng } from "save-svg-as-png"
3 | import { Dropbox } from "dropbox"
4 | import store from "../models/CanvasStore"
5 | import React from "react"
6 | import ReactDOM from "react-dom"
7 | import { rawSvgCell } from "../components/Cell"
8 |
9 | export function saveToDropbox() {
10 | let scale = "scale(" + store.exportSizeMultiplier + ")"
11 | let style = {
12 | transform: scale,
13 | "transform-origin": "top left",
14 | }
15 |
16 | const ACCESS_TOKEN = "6epNSr0tHAQAAAAAAAAdD86QBYJlisfk9uIkgYSH6FZ5fSvBoPvKFEq3vqqxR1uv"
17 | const dbx = new Dropbox({
18 | accessToken: ACCESS_TOKEN,
19 | })
20 |
21 | if (
22 | store.userFullName.trim() == "" ||
23 | store.userEmail.trim() == "" ||
24 | store.userCountry.trim() == ""
25 | ) {
26 | document.getElementById("dropbox-response").innerText =
27 | "Please fill in your info."
28 | return
29 | }
30 |
31 | store.hideGrid = true
32 |
33 |
34 | const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg")
35 | svg.setAttribute("width", Number(store.widthPixels))
36 | svg.setAttribute("height", Number(store.heightPixels))
37 | svg.setAttributeNS(
38 | "http://www.w3.org/2000/xmlns/",
39 | "xmlns:xlink",
40 | "http://www.w3.org/1999/xlink"
41 | )
42 |
43 | const cells = (
44 |
45 | {store.canvas.map((row, y) => (
46 |
47 | {row.map((cell, x) => (
48 |
49 | {rawSvgCell({
50 | glyphPath: cell[0],
51 | svgWidth: cell[1],
52 | svgHeight: cell[2],
53 | svgBaseline: cell[3],
54 | glyphOffsetX: cell[4],
55 | glyphFontSizeModifier: cell[5],
56 | rotationAmount: cell[6],
57 | flipGlyph: cell[7],
58 | glyphInvertedShape: cell[8],
59 | glyphOffsetY: cell[9],
60 | })}
61 |
62 | ))}
63 |
64 | ))}
65 |
66 | )
67 |
68 | ReactDOM.render(cells, svg)
69 |
70 | const blob = new Blob([
71 | `${svg.outerHTML}`,
72 | ])
73 |
74 | dbx
75 | .filesUpload({
76 | path:
77 | "/" +
78 | store.fileName +
79 | " " +
80 | store.userFullName +
81 | " " +
82 | store.userEmail +
83 | " " +
84 | store.userCountry +
85 | ".svg",
86 | contents: blob,
87 | })
88 | .then(function(response) {
89 | document.getElementById("dropbox-response").innerText =
90 | "Sent successfully! Thank you!"
91 | console.log(response)
92 | })
93 | .catch(function(error) {
94 | document.getElementById("dropbox-response").innerText =
95 | "Sorry something went wrong! Contact hlotvonen@gmail.com"
96 | console.error(error)
97 | })
98 | }
99 |
--------------------------------------------------------------------------------
/src/utils/colorConversion.js:
--------------------------------------------------------------------------------
1 | export const rgbToHex = (r, g, b) => '#' + [r, g, b].map(x => {
2 | const hex = x.toString(16)
3 | return hex.length === 1 ? '0' + hex : hex
4 | }).join('')
5 |
6 | export const hexToRgb = hex =>
7 | hex.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i
8 | ,(m, r, g, b) => '#' + r + r + g + g + b + b)
9 | .substring(1).match(/.{2}/g)
10 | .map(x => parseInt(x, 16))
11 |
12 | export const colorBlend = (a, b, intensity) => {
13 | intensity = typeof intensity === 'undefined' ? 1 : intensity
14 | return a.reduce(function (result, current, index) {
15 | let value = (a[index] < 128) ? (2 * b[index] * a[index] / 255) : (255 - 2 * (255 - a[index]) * (255 - b[index]) / 255)
16 | value = (value * intensity + (a[index] * (1 - intensity)))
17 | return result.concat(Math.min(Math.round(value), 255))
18 | }, [])
19 | }
20 |
21 | /**
22 | * Takes HSL values (H between 0 and 360, S and L each between 0 and 100) and returns the corresponding RGB values (each between 0 and 255)
23 | * Based on pseudo-code in the W3 Color Model document (http://www.w3.org/TR/2011/REC-css3-color-20110607/#hsl-color)
24 | */
25 | export const hslToRgb = (h, s, l) => {
26 | let m1, m2, m3, r, g, b;
27 |
28 | h = h / 360;
29 | s = s / 100;
30 | l = l / 100;
31 |
32 | m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
33 |
34 | m1 = l * 2 - m2;
35 |
36 | r = hueToRgb(m1, m2, h + 1/3);
37 | g = hueToRgb(m1, m2, h);
38 | b = hueToRgb(m1, m2, h - 1/3);
39 |
40 | return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]
41 | }
42 |
43 | export const hueToRgb = (m1, m2, h) => {
44 | if(h < 0) {
45 | h = h + 1;
46 | } else if(h > 1) {
47 | h = h - 1;
48 | }
49 |
50 | if(h*6 < 1) {
51 | return m1 + (m2 - m1) * h * 6;
52 | } else if(h*2 < 1) {
53 | return m2;
54 | } else if(h*3 < 2) {
55 | return m1 + (m2 - m1) * (2/3 - h) * 6
56 | }
57 |
58 | return m1;
59 | }
60 |
61 | /**
62 | * Takes RGB values (each between 0 and 255) and returns the corresponding HSL values (H between 0 and 360, S and L each between 0 and 100).
63 | * Based on http://stackoverflow.com/a/9493060
64 | */
65 | export const rgbToHsl = (r, g, b) => {
66 | let max, min, h, s, l;
67 |
68 | r = r / 255;
69 | g = g / 255;
70 | b = b / 255;
71 |
72 | max = Math.max(r, g, b);
73 | min = Math.min(r, g, b);
74 |
75 | l = (min + max) / 2;
76 |
77 | let diff = max - min;
78 |
79 | if (diff == 0) {
80 | s = 0;
81 | h = 0;
82 | } else {
83 | if(l > 0.5) {
84 | s = (diff) / (2 - min - max)
85 | } else {
86 | s = diff / (max + min)
87 | }
88 |
89 | switch(max) {
90 | case r:
91 | h = (g - b) / diff + (g < b ? 6 : 0);
92 | break;
93 | case g:
94 | h = (b - r) / diff + 2;
95 | break;
96 | case b:
97 | h = (r - g) / diff + 4;
98 | break;
99 | }
100 | }
101 |
102 | return [Math.round(h * 60), Math.round(s * 100), Math.round(l * 100)];
103 | }
--------------------------------------------------------------------------------
/src/models/KeymappingsStore.js:
--------------------------------------------------------------------------------
1 | import { action, observable, computed, autorun, mobx, toJS } from "mobx"
2 | import store from "./CanvasStore"
3 | import colorstore from "./ColorStore"
4 |
5 | const EMPTY_GLYPH = ["M0 0", "1", "1", "0"]
6 | const KEYS = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]
7 |
8 | let keymappingsStorage
9 |
10 | class KeymappingsStore {
11 | constructor() {
12 | //load from localstorage if it's not the first time
13 | if (localStorage.keymapFirstRun) {
14 | keymappingsStorage = JSON.parse(localStorage.keymappingsStorage)
15 | this.sets = keymappingsStorage.sets
16 | //else create empty canvas
17 | } else {
18 | this.addSet()
19 | localStorage.setItem("keymapFirstRun", false)
20 | }
21 | //set localstorage, autorun will update it every time something changes
22 | autorun(() => {
23 | const keymappingsLocalstorage = {
24 | name: "keymappings",
25 | timestamp: Math.floor(Date.now() / 1000),
26 | sets: this.sets
27 | }
28 | localStorage.setItem("keymappingsStorage", JSON.stringify(keymappingsLocalstorage))
29 | })
30 | }
31 | @observable
32 | toggleMapping = false
33 | @observable
34 | selectedSetIndex = 0
35 | @observable
36 | sets = []
37 |
38 | @action
39 | handleChangeMapping = () => {
40 | this.toggleMapping = !this.toggleMapping
41 | document.getElementById("toggleMapping").checked = this.toggleMapping
42 | }
43 |
44 | @action
45 | selectSet = index => {
46 | if (index >= 0 && index < this.sets.length) {
47 | this.selectedSetIndex = index
48 | }
49 | }
50 |
51 | @action
52 | addSet = () => {
53 | const set = {}
54 | for (const keyName of KEYS) {
55 | set[keyName] = EMPTY_GLYPH
56 | }
57 | this.sets.push(set)
58 | this.selectedSetIndex = this.sets.length - 1
59 | }
60 |
61 | @action
62 | deleteSet = () => {
63 | this.sets.splice(this.selectedSetIndex, 1)
64 | this.selectedSetIndex = this.selectedSetIndex - 1
65 | }
66 |
67 | @action
68 | prevSet = () => {
69 | if (this.selectedSetIndex > 0) {
70 | this.selectedSetIndex = this.selectedSetIndex - 1
71 | }
72 | }
73 |
74 | @action
75 | nextSet = () => {
76 | if (this.selectedSetIndex < this.sets.length) {
77 | this.selectedSetIndex = this.selectedSetIndex + 1
78 | }
79 | }
80 |
81 | @action
82 | setMapping = (keyName, glyph) => {
83 | const selectedSet = this.sets[this.selectedSetIndex]
84 | selectedSet[keyName] = glyph
85 | }
86 |
87 | @action
88 | getMapping = keyName => {
89 | const selectedSet = this.sets[this.selectedSetIndex]
90 | store.canvas[store.selected_y][store.selected_x][store.selectedLayer] = [
91 | ...this.sets[this.selectedSetIndex][keyName],
92 | store.glyphOffsetX,
93 | store.glyphFontSizeModifier,
94 | store.rotationAmount,
95 | store.flipGlyph,
96 | store.glyphInvertedShape,
97 | store.glyphOffsetY,
98 | colorstore.colorIndex
99 | ]
100 | }
101 | }
102 |
103 | export default new KeymappingsStore()
104 |
--------------------------------------------------------------------------------
/src/models/ColorStore.js:
--------------------------------------------------------------------------------
1 | import { action, observable, computed, autorun, mobx, toJS } from "mobx"
2 | import store from "./CanvasStore"
3 | import { colorBlend } from "../utils/colorConversion"
4 | import colorPresets from '../utils/colorPresets.json';
5 |
6 | let colorStorage
7 |
8 | class ColorStore {
9 | constructor() {
10 | //load from localstorage if it's not the first time
11 | if (localStorage.colorFirstRun) {
12 | colorStorage = JSON.parse(localStorage.colorStorage)
13 | this.palettes = colorStorage.palettes
14 | //else create empty canvas
15 | } else {
16 | this.addPalette()
17 | localStorage.setItem("colorFirstRun", false)
18 | }
19 | //set localstorage, autorun will update it every time something changes
20 | autorun(() => {
21 | const colorLocalstorage = {
22 | name: "Color Palettes",
23 | timestamp: Math.floor(Date.now() / 1000),
24 | palettes: this.palettes
25 | }
26 | localStorage.setItem("colorStorage", JSON.stringify(colorLocalstorage))
27 | })
28 | }
29 |
30 | @observable
31 | colorIndex = 0
32 | @observable
33 | bgColorIndex = 255
34 | @observable
35 | cohesionIntensity = 0
36 | @observable
37 | cohesionOverlayColor = [255, 128, 32]
38 | @observable
39 | changingCohesionColor = false
40 | @observable
41 | coloringModeFg = false
42 | @observable
43 | coloringModeBg = false
44 | @observable
45 | showUsedColors = false
46 | @observable
47 | selectedPaletteIndex = 0
48 | @observable
49 | palettes = []
50 | @observable
51 | selectedPresetPalette = ""
52 |
53 | @action
54 | colorSelect = (i, e) => {
55 | if (!this.changingCohesionColor) {
56 | this.palettes[this.selectedPaletteIndex][this.colorIndex][i] = Number(e)
57 | if (e < 0) {
58 | this.palettes[this.selectedPaletteIndex][this.colorIndex][i] = 0
59 | }
60 | if (e > 255) {
61 | this.palettes[this.selectedPaletteIndex][this.colorIndex][i] = 255
62 | }
63 | } else {
64 | this.cohesionOverlayColor[i] = Number(e)
65 | if (e < 0) {
66 | this.cohesionOverlayColor[i] = 0
67 | }
68 | if (e > 255) {
69 | this.cohesionOverlayColor[i] = 255
70 | }
71 | }
72 | }
73 | @action
74 | setFgColorIndex = index => {
75 | this.colorIndex = index
76 | }
77 | @action
78 | setBgColorIndex = (e, index) => {
79 | this.bgColorIndex = index
80 | e.preventDefault()
81 | }
82 | @action
83 | changeIntensity = e => {
84 | this.cohesionIntensity = e
85 | }
86 | @action
87 | handleChangeCohesionColor = () => {
88 | this.changingCohesionColor = !this.changingCohesionColor
89 | }
90 |
91 |
92 | @action
93 | handlePresetSelectChange = e => {
94 | this.selectedPresetPalette = Number(e)
95 | this.palettes[this.selectedPaletteIndex] = colorPresets[Number(e)].palette
96 | }
97 |
98 | @action
99 | selectPalette = index => {
100 | if (index >= 0 && index < this.palettes.length) {
101 | this.selectedPaletteIndex = index
102 | }
103 | }
104 | @action
105 | addPalette = () => {
106 | this.palettes.push(colorPresets[0].palette)
107 | this.selectedPaletteIndex = this.palettes.length - 1
108 | }
109 |
110 | @action
111 | deletePalette = () => {
112 | if (this.selectedPaletteIndex > 0) {
113 | this.palettes.splice(this.selectedPaletteIndex, 1)
114 | this.selectedPaletteIndex -= 1
115 | }
116 | }
117 |
118 | @action
119 | prevSet = () => {
120 | if (this.selectedPaletteIndex > 0) {
121 | this.selectedPaletteIndex -= 1
122 | }
123 | }
124 |
125 | @action
126 | nextSet = () => {
127 | if (this.selectedPaletteIndex < this.palette.length) {
128 | this.selectedPaletteIndex += 1
129 | }
130 | }
131 |
132 |
133 |
134 | }
135 |
136 | export default new ColorStore()
137 |
--------------------------------------------------------------------------------
/src/components/ColorSliders.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react"
2 | import { observer } from "mobx-react"
3 | import { action } from "mobx"
4 | import colorStore from "../models/ColorStore"
5 | import store from "../models/CanvasStore"
6 | import ColorPalette from "./ColorPalette"
7 |
8 | const setGradient = (steps) => {
9 | let gradientString = "linear-gradient(to right,"
10 | let stepSize = 100 / (steps.length - 1);
11 | for(var i = 0; i < steps.length; i++) {
12 | gradientString += (i > 0 ? "," : "") + steps[i] + (i * stepSize) + "%"
13 | }
14 | return (
15 | gradientString + ")"
16 | )
17 | }
18 | const rgb = (r, g, b) => {
19 | return "rgb(" + r + "," + g + "," + b +")";
20 | }
21 |
22 | @observer
23 | class ColorSliders extends Component {
24 | render() {
25 | const rgbSlider = (name, index, gradient) => {
26 | return (
27 |
28 | colorStore.colorSelect(index, e.target.value)}
36 | style={{
37 | background: setGradient(gradient)
38 | }}
39 | />
40 | colorStore.colorSelect(index, e.target.value)}
46 | onFocus={() => store.toggleWriting()}
47 | onBlur={() => store.toggleWriting()}
48 | />
49 | {name}
50 |
51 | )
52 | }
53 | return (
54 |
55 |
56 | {rgbSlider(
57 | "R",
58 | 0,
59 | colorStore.changingCohesionColor
60 | ? [rgb(0, colorStore.cohesionOverlayColor[1], colorStore.cohesionOverlayColor[2]),rgb(255, colorStore.cohesionOverlayColor[1], colorStore.cohesionOverlayColor[2])]
61 | : [rgb(0, colorStore.palettes[colorStore.selectedPaletteIndex][colorStore.colorIndex][1], colorStore.palettes[colorStore.selectedPaletteIndex][colorStore.colorIndex][2]),rgb(255, colorStore.palettes[colorStore.selectedPaletteIndex][colorStore.colorIndex][1], colorStore.palettes[colorStore.selectedPaletteIndex][colorStore.colorIndex][2])]
62 | )}
63 | {rgbSlider(
64 | "G",
65 | 1,
66 | colorStore.changingCohesionColor
67 | ? [rgb(colorStore.cohesionOverlayColor[0], 0, colorStore.cohesionOverlayColor[2]),rgb(colorStore.cohesionOverlayColor[0], 255, colorStore.cohesionOverlayColor[2])]
68 | : [rgb(colorStore.palettes[colorStore.selectedPaletteIndex][colorStore.colorIndex][0], 0, colorStore.palettes[colorStore.selectedPaletteIndex][colorStore.colorIndex][2]),rgb(colorStore.palettes[colorStore.selectedPaletteIndex][colorStore.colorIndex][0], 255, colorStore.palettes[colorStore.selectedPaletteIndex][colorStore.colorIndex][2])]
69 | )}
70 | {rgbSlider(
71 | "B",
72 | 2,
73 | colorStore.changingCohesionColor
74 | ? [rgb(colorStore.cohesionOverlayColor[0], colorStore.cohesionOverlayColor[1], 0), rgb(colorStore.cohesionOverlayColor[0], colorStore.cohesionOverlayColor[1], 255)]
75 | : [rgb(colorStore.palettes[colorStore.selectedPaletteIndex][colorStore.colorIndex][0], colorStore.palettes[colorStore.selectedPaletteIndex][colorStore.colorIndex][1], 0), rgb(colorStore.palettes[colorStore.selectedPaletteIndex][colorStore.colorIndex][0], colorStore.palettes[colorStore.selectedPaletteIndex][colorStore.colorIndex][1], 255)]
76 | )}
77 |
78 |
87 |
88 | )
89 | }
90 | }
91 | export default observer(ColorSliders)
92 |
--------------------------------------------------------------------------------
/src/components/Canvas.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react"
2 | import { observer } from "mobx-react"
3 | import { action } from "mobx"
4 | import store from "../models/CanvasStore.js"
5 | import setstore from "../models/KeymappingsStore"
6 | import gridstore from "../models/GridStore.js"
7 | import Grid from "./Grid"
8 | import GridControls from "./GridControls"
9 | import Coordinates from "./Coordinates"
10 | import SelectedGlyph from "./SelectedGlyph"
11 | import QuickChooseColor from "./QuickChooseColor"
12 |
13 | class Canvas extends Component {
14 | componentDidMount() {
15 | document.addEventListener("keydown", this.handleKeyPress, false)
16 | document.addEventListener("keyup", this.handleKeyPressUp, false)
17 | }
18 | componentWillUnmount() {
19 | document.removeEventListener("keydown", this.handleKeyPress, false)
20 | document.removeEventListener("keyup", this.handleKeyPressUp, false)
21 | }
22 |
23 | @action
24 | handleKeyPress = event => {
25 | //disable shortcuts if focus is on input element
26 | if (!store.disableShortcuts && !store.typingMode) {
27 | const glyph = [
28 | store.glyphPath,
29 | store.svgWidth,
30 | store.svgHeight,
31 | store.svgBaseline,
32 | ]
33 |
34 | const handlers = !setstore.toggleMapping
35 | ? {
36 | ArrowRight: store.goRight,
37 | ArrowLeft: store.goLeft,
38 | ArrowDown: store.goDown,
39 | ArrowUp: store.goUp,
40 | " ": store.insertEmpty,
41 | Backspace: store.backSpace,
42 | Enter: store.insert,
43 | q: store.insert,
44 | e: store.insertEmptyCell,
45 | r: store.rotateGlyphRight,
46 | f: store.handleChangeFlip,
47 | h: store.handleChangeHideGrid,
48 | i: store.handleChangeInvertColor,
49 | b: store.handleChangePaintMode,
50 | z: store.handleUndoRedo,
51 | p: store.showPreview,
52 | b: store.insertBackground,
53 | v: store.colorFg,
54 | w: store.goUp,
55 | a: store.goLeft,
56 | s: store.goDown,
57 | d: store.goRight,
58 | x: store.showQuickChooseColor,
59 | c: store.copy,
60 | o: store.handleOffsetOn,
61 | ",": () => store.selectLayer("left"),
62 | ".": () => store.selectLayer("right"),
63 | "+": gridstore.zoomIn,
64 | "-": gridstore.zoomOut,
65 |
66 | //Modifier keys:
67 | Alt: store.handleAltDown,
68 | Meta: store.handleMetaDown,
69 | Control: store.handleCtrlDown,
70 | Shift: store.handleShiftDown,
71 |
72 | //Unused keys:
73 | //GNOPWX
74 | A: store.selectAll,
75 | S: store.makeSelection,
76 | C: store.copySelection,
77 | M: store.mirrorSelection,
78 | T: store.transposeSelection,
79 | R: store.rotateSelection,
80 | Y: store.rotateIndividuallySelection,
81 | U: store.flipIndividuallySelection,
82 | F: store.flipSelection,
83 | E: store.clearArea,
84 | Q: store.fillArea,
85 | B: store.fillBackgroundArea,
86 | V: store.colorFgSelectionArea,
87 | I: store.invertColorSelection,
88 | H: store.shiftAreaLeft,
89 | J: store.shiftAreaDown,
90 | K: store.shiftAreaUp,
91 | L: store.shiftAreaRight,
92 | D: store.emptySelection,
93 |
94 | m: setstore.handleChangeMapping,
95 | //draw glyph from keymap on to canvas
96 | 1: () => setstore.getMapping("1"),
97 | 2: () => setstore.getMapping("2"),
98 | 3: () => setstore.getMapping("3"),
99 | 4: () => setstore.getMapping("4"),
100 | 5: () => setstore.getMapping("5"),
101 | 6: () => setstore.getMapping("6"),
102 | 7: () => setstore.getMapping("7"),
103 | 8: () => setstore.getMapping("8"),
104 | 9: () => setstore.getMapping("9"),
105 | 0: () => setstore.getMapping("0"),
106 | }
107 | : {
108 | //assign selected glyph to keymap
109 | 1: () => setstore.setMapping("1", glyph),
110 | 2: () => setstore.setMapping("2", glyph),
111 | 3: () => setstore.setMapping("3", glyph),
112 | 4: () => setstore.setMapping("4", glyph),
113 | 5: () => setstore.setMapping("5", glyph),
114 | 6: () => setstore.setMapping("6", glyph),
115 | 7: () => setstore.setMapping("7", glyph),
116 | 8: () => setstore.setMapping("8", glyph),
117 | 9: () => setstore.setMapping("9", glyph),
118 | 0: () => setstore.setMapping("0", glyph),
119 | m: setstore.handleChangeMapping,
120 | }
121 |
122 | const handler = handlers[event.key]
123 |
124 | if (!handler) {
125 | return
126 | }
127 |
128 | handler()
129 | event.preventDefault()
130 | }
131 | }
132 |
133 | handleKeyPressUp = event => {
134 | const handlers = {
135 | Alt: store.handleAltUp,
136 | Control: store.handleCtrlUp,
137 | Meta: store.handleMetaUp,
138 | Shift: store.handleShiftUp,
139 | p: store.hidePreview,
140 | x: store.hideQuickChooseColor,
141 | o: store.handleOffsetOff,
142 | }
143 | const handler = handlers[event.key]
144 |
145 | if (!handler) {
146 | return
147 | }
148 |
149 | handler()
150 | event.preventDefault()
151 | }
152 |
153 | render() {
154 | return (
155 |
156 |
157 |
158 |
159 |
160 |
161 |
167 |
168 |
169 |
170 |
171 | )
172 | }
173 | }
174 |
175 | export default observer(Canvas)
176 |
--------------------------------------------------------------------------------
/src/components/Cell.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import store from "../models/CanvasStore"
3 | import colorStore from "../models/ColorStore"
4 | import { observer } from "mobx-react"
5 | import { colorBlend } from "../utils/colorConversion"
6 |
7 | const Cell = observer(props => {
8 | const [
9 | layer1,
10 | layer2,
11 | layer3,
12 | layer4
13 | ] = props.cell
14 |
15 | if(layer1[0] == "M0 0" && layer2[0] == "M0 0" && layer3[0] == "M0 0" && layer4[0] == "M0 0" ) {
16 | return (null)
17 | } else {
18 | return (
19 | rawSvgCell({
20 | layer1,
21 | layer2,
22 | layer3,
23 | layer4,
24 |
25 | }, props.x, props.y)
26 | )
27 | }
28 | })
29 | /*
30 | [
31 | 0: glyphPath,
32 | 1: svgWidth,
33 | 2: svgHeight,
34 | 3: svgBaseline,
35 | 4: glyphOffsetX,
36 | 5: glyphFontSizeModifier,
37 | 6: rotationAmount,
38 | 7: flipGlyph,
39 | 8: glyphInvertedShape,
40 | 9: glyphOffsetY
41 | ]
42 | */
43 | export const rawSvgCell = ({
44 | layer1,
45 | layer2,
46 | layer3,
47 | layer4
48 | }, x, y) => (
49 |
store.handleClickSVG(x, y)}
59 | >
60 | {
61 | layer1[0] === "M0 0" || store.hiddenLayers[0] == 0
62 | ? null
63 | : (
64 |
92 |
98 |
99 | )
100 | }
101 | {
102 | layer2[0] === "M0 0" || store.hiddenLayers[1] == 1
103 | ? null
104 | : (
105 |
131 |
137 |
138 | )
139 | }
140 | {
141 | layer3[0] === "M0 0" || store.hiddenLayers[2] == 2
142 | ? null
143 | : (
144 |
170 |
176 |
177 | )
178 | }
179 | {
180 | layer4[0] === "M0 0" || store.hiddenLayers[3] == 3
181 | ? null
182 | : (
183 |
209 |
215 |
216 | )
217 | }
218 |
219 | )
220 |
221 | export default Cell
--------------------------------------------------------------------------------
/src/components/GlyphSelect.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react"
2 | import { observer } from "mobx-react"
3 | import { observable, action } from "mobx"
4 | import store from "../models/CanvasStore.js"
5 | import { KEY_INTO_UNICODE } from "../utils/keyIntoUnicode"
6 |
7 | class GlyphSelect extends Component {
8 | pageNumber = observable.box(0)
9 | selectedFont = observable.box("Tesserae Core")
10 |
11 | constructor(props) {
12 | super(props)
13 |
14 | this.state = {
15 | off: 0,
16 | font: [],
17 | num: 100,
18 | gid: 0,
19 | uncd: null,
20 | fontfile: "",
21 | pages_total: 0,
22 | inverted: false,
23 | credits: null
24 | }
25 | }
26 | componentDidMount() {
27 | this.go()
28 | document.addEventListener("keydown", this.handleKeyPress, false)
29 | }
30 | componentWillUnmount() {
31 | document.removeEventListener("keydown", this.handleKeyPress, false)
32 | }
33 |
34 | go = () => {
35 | if (this.selectedFont == "Tesserae Core") {
36 | this.load("fonts/Tesserae-TypeDesign.otf", this.fontLoaded)
37 | this.credits = null
38 | } else if (this.selectedFont == "Tesserae Extended") {
39 | this.load("fonts/Tesserae-4x4Extended.otf", this.fontLoaded)
40 | this.credits = null
41 | } else if (this.selectedFont == "Unscii") {
42 | this.load("fonts/unscii-16.ttf", this.fontLoaded)
43 | this.credits = "http://pelulamu.net/unscii/"
44 | } else if (this.selectedFont == "Submona") {
45 | this.load("fonts/submona.ttf", this.fontLoaded)
46 | this.credits = "https://github.com/pera/submona-web-font"
47 | } else if (this.selectedFont == "RayMantaC64") {
48 | this.load("fonts/RayMantaC64-Regular.otf", this.fontLoaded)
49 | this.credits = "http://datadoor.net/"
50 | } else if (this.selectedFont == "ImagoMundiMei") {
51 | this.load("fonts/ImagoMundiMei-Regular.otf", this.fontLoaded)
52 | this.credits = "http://velvetyne.fr/imagomundimei/"
53 | } else if (this.selectedFont == "ScrollBorder") {
54 | this.load("fonts/ScrollBorder-Regular.otf", this.fontLoaded)
55 | this.credits = null
56 | }
57 |
58 | this.node = document.body
59 | this.node.addEventListener("drop", this.onDrop, false)
60 | this.node.addEventListener("dragenter", this.cancel, false)
61 | this.node.addEventListener("dragleave", this.cancel, false)
62 | this.node.addEventListener("dragover", this.cancel, false)
63 | }
64 |
65 | ShowCredits() {
66 | if (!this.credits) {
67 | return null;
68 | }
69 | return (
70 | <>
71 | {this.selectedFont} made by:
{this.credits}
72 | >
73 | );
74 | }
75 | load(path, resp) {
76 | let request = new XMLHttpRequest()
77 | request.open("GET", path, true)
78 | request.responseType = "arraybuffer"
79 | request.onload = function(e) {
80 | resp(e.target.response)
81 | }
82 | request.send()
83 | }
84 | cancel(e) {
85 | e.stopPropagation()
86 | e.preventDefault()
87 | }
88 | @action
89 | fontLoaded = resp => {
90 | this.setState({
91 | font: Typr.parse(resp),
92 | })
93 | this.setState({
94 | uncd: new Array(this.state.font.maxp.numGlyphs),
95 | })
96 |
97 | for (let i = 0; i < 100000; i++) {
98 | let gid = Typr.U.codeToGlyph(this.state.font, i)
99 | if (gid == 0) {
100 | continue
101 | }
102 | if (this.state.uncd[gid] == null) {
103 | this.state.uncd[gid] = [i]
104 | } else {
105 | this.state.uncd[gid].push(i)
106 | }
107 | }
108 |
109 | this.setState({
110 | gid: 0,
111 | off: 0,
112 | pages_total: Math.floor(this.glyphCnt() / this.state.num),
113 | })
114 |
115 | this.drawGlyphs()
116 | this.glyphToSVG()
117 |
118 | this.pageNumber.set(0)
119 |
120 | store.fontName = this.state.font.name.fullName
121 | }
122 | @action
123 | handleKeyPress = event => {
124 | if (store.typingMode && !store.disableShortcuts) {
125 | const handlers = {
126 | ArrowRight: store.goRight,
127 | ArrowLeft: store.goLeft,
128 | ArrowDown: store.goDown,
129 | ArrowUp: store.goUp,
130 | Backspace: store.backSpace,
131 | Escape: store.handleChangeTypingMode,
132 | Enter: store.enter,
133 | "§": store.insert,
134 | }
135 | const handler = handlers[event.key]
136 |
137 | if (event.key in handlers) {
138 | handler()
139 | }
140 | if (KEY_INTO_UNICODE[event.key] !== undefined) {
141 | let path = Typr.U.glyphToPath(
142 | this.state.font,
143 | Typr.U.codeToGlyph(
144 | this.state.font,
145 | KEY_INTO_UNICODE[event.key]
146 | )
147 | )
148 | let svgstring = Typr.U.pathToSVG(path)
149 | store.glyphPath = svgstring
150 | store.svgWidth = this.state.font.hhea.advanceWidthMax
151 | store.svgHeight =
152 | this.state.font.hhea.ascender +
153 | Math.abs(this.state.font.hhea.descender)
154 | store.svgBaseline = this.state.font.hhea.descender
155 |
156 | store.canvas[store.selected_y][store.selected_x][store.selectedLayer].replace(store.getSelectedGlyph())
157 | store.selected_x += 1
158 |
159 | if (store.selected_x == store.canvasWidth) {
160 | store.selected_x = 0
161 | if (store.selected_y < store.canvasHeight - 1) {
162 | store.selected_y += 1
163 | } else if (store.selected_y == store.canvasHeight) {
164 | store.selected_y -= 1
165 | }
166 | }
167 | }
168 | event.preventDefault()
169 | }
170 | }
171 | @action
172 | glyphToSVG = () => {
173 | let path = Typr.U.glyphToPath(this.state.font, this.state.gid)
174 | let svgstring = Typr.U.pathToSVG(path)
175 | store.glyphPath = svgstring
176 | store.svgWidth = this.state.font.hhea.advanceWidthMax
177 | store.svgHeight =
178 | this.state.font.hhea.ascender + Math.abs(this.state.font.hhea.descender)
179 | store.svgBaseline = this.state.font.hhea.descender
180 | }
181 | drawGlyphs = () => {
182 | let cont = document.getElementById("glyphcont")
183 | cont.innerHTML = ""
184 | let cnv = document.createElement("canvas")
185 | cnv.width = Math.floor(this.getDPR() * 40)
186 | cnv.height = Math.floor(this.getDPR() * 50) //scaleCnv(cnv);
187 | let ctx = cnv.getContext("2d")
188 |
189 | let lim = Math.min(this.state.off + this.state.num, this.glyphCnt())
190 | let scale = (32 * this.getDPR()) / this.state.font.head.unitsPerEm
191 |
192 |
193 | for (let i = this.state.off; i < lim; i++) {
194 | let path = Typr.U.glyphToPath(this.state.font, i)
195 |
196 | cnv.width = cnv.width
197 | ctx.translate(5 * this.getDPR(), Math.round(30 * this.getDPR()))
198 |
199 | if ( this.selectedFont == "Tesserae 4x4") {
200 | ctx.fillStyle = "#f5f5f5"
201 | ctx.fillRect(
202 | 0,
203 | Math.round(-25.7 * this.getDPR()),
204 | Math.round(25.7 * this.getDPR()),
205 | Math.round(25.7 * this.getDPR())
206 | )
207 | }
208 |
209 | if (this.state.inverted) {
210 | ctx.fillStyle = "black"
211 | ctx.fillRect(
212 | 0,
213 | Math.round(-25 * this.getDPR()),
214 | Math.round(25 * this.getDPR()),
215 | Math.round(25 * this.getDPR())
216 | )
217 | }
218 |
219 | ctx.fillStyle = "black"
220 | ctx.font = "16px monospace"
221 | ctx.fillText(i+1, 0, 16)
222 |
223 | ctx.scale(scale, -scale)
224 | Typr.U.pathToContext(path, ctx)
225 |
226 | if (this.state.inverted) {
227 | ctx.fillStyle = "#f5f5f5"
228 | } else {
229 | ctx.fillStyle = "black"
230 | }
231 | ctx.fill()
232 |
233 | let img = document.createElement("img")
234 | img.setAttribute(
235 | "style",
236 | "width:" +
237 | cnv.width / this.getDPR() +
238 | "px; height:" +
239 | cnv.height / this.getDPR() +
240 | "px"
241 | )
242 | img.gid = i
243 | img.onclick = this.glyphClick
244 | img.src = cnv.toDataURL()
245 | cont.appendChild(img)
246 | }
247 | }
248 |
249 | onDrop = e => {
250 | this.cancel(e)
251 | let fontLoaded = this.fontLoaded
252 | let r = new FileReader()
253 | let r64 = new FileReader()
254 | let file = e.dataTransfer.files[0]
255 | r.onload = function(e) {
256 | fontLoaded(e.target.result)
257 | }
258 | r.onloadend = function(e) {
259 | r64.readAsDataURL(file)
260 | r64.onloadend = function(e) {
261 | let base64result = r64.result.split(",")[1]
262 | }
263 | }
264 | r.readAsArrayBuffer(file)
265 | }
266 |
267 | glyphClick = e => {
268 | this.setState({ gid: e.target.gid })
269 | this.glyphToSVG()
270 | }
271 | getDPR() {
272 | return window["devicePixelRatio"] || 1
273 | }
274 | glyphCnt = () => {
275 | return this.state.font.maxp.numGlyphs
276 | }
277 | @action
278 | drawNext = () => {
279 | if (this.pageNumber.get() < this.state.pages_total) {
280 | this.updatePageNum(this.pageNumber.get() + 1)
281 | }
282 | }
283 | @action
284 | drawPrev = () => {
285 | if (this.pageNumber.get() > 0) {
286 | this.updatePageNum(this.pageNumber.get() - 1)
287 | }
288 | }
289 | @action
290 | updatePageNum = value => {
291 | this.pageNumber.set(value)
292 |
293 | if (value === "") {
294 | return
295 | }
296 |
297 | if (this.pageNumber.get() > this.state.pages_total) {
298 | this.pageNumber.set(this.state.pages_total)
299 | }
300 | if (isNaN(value)) {
301 | return
302 | }
303 |
304 | this.state.off = this.pageNumber * this.state.num
305 | this.drawGlyphs()
306 | }
307 | handleFontSelectChange = value => {
308 | this.selectedFont = value
309 | this.go()
310 | }
311 | handleChangeInvert = () => {
312 | this.state.inverted = !this.state.inverted
313 | this.drawGlyphs()
314 | }
315 | render() {
316 | return (
317 |
318 |
Glyph selection
319 | Select a preset font:
320 |
this.handleFontSelectChange(evt.target.value)}
323 | >
324 | Tesserae Core
325 | Tesserae Extended
326 | RayMantaC64 (Custom PETSCII)
327 | Unscii
328 | Submona (Swift_JIS)
329 | ImagoMundiMei
330 | ScrollBorder
331 |
332 |
333 |
334 |
this.drawPrev()}>
335 | Previous
336 |
337 |
this.drawNext()}>
338 | Next
339 |
340 |
341 | Select page:
342 | store.toggleWriting()}
351 | onBlur={() => store.toggleWriting()}
352 | onChange={evt => {
353 | if (evt.target.value === "") {
354 | this.pageNumber.set("")
355 | return
356 | }
357 |
358 | const parsedValue = parseInt(evt.target.value, 10)
359 | if (isNaN(parsedValue)) {
360 | this.updatePageNum(0)
361 | return
362 | }
363 |
364 | this.updatePageNum(Math.max(0, parsedValue - 1))
365 | }}
366 | />
367 | /{this.state.pages_total + 1}
368 | {" Invert:"}
369 |
375 |
376 |
377 |
this.drawPrev()}>
378 | Previous
379 |
380 |
this.drawNext()}>
381 | Next
382 |
383 |
384 |
385 | {this.ShowCredits()}
386 |
387 | )
388 | }
389 | }
390 | export default observer(GlyphSelect)
391 |
--------------------------------------------------------------------------------
/src/components/Settings.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { observer } from "mobx-react"
3 | import store from "../models/CanvasStore"
4 | import CanvasSizeModification from "./CanvasSizeModification"
5 | import CellWidth from "./CellWidth"
6 | import CellHeight from "./CellHeight"
7 | import FontSize from "./FontSize"
8 | import GlyphSelect from "./GlyphSelect"
9 | import HideGrid from "./HideGrid"
10 | import KeyMappings from "./KeyMappings"
11 | import SelectedGlyph from "./SelectedGlyph"
12 | import ExportButtons from "./ExportButtons"
13 | import SaveAsButton from "./SaveAsButton"
14 | import LoadButton from "./LoadButton"
15 | import LoadAndPlace from "./LoadAndPlace"
16 | import EmptyCanvas from "./EmptyCanvas"
17 | import SaveToDropboxButton from "./SaveToDropboxButton"
18 | import TypingMode from "./TypingMode"
19 | import PaintMode from "./PaintMode"
20 | import HistoryControls from "./HistoryControls"
21 | import GlyphOffset from "./GlyphOffset"
22 | import GlyphFontSizeModifier from "./GlyphFontSizeModifier"
23 | import GlyphClear from "./GlyphClear"
24 | import CanvasSizeInMillimeters from "./CanvasSizeInMillimeters"
25 | import LayerSelect from "./LayerSelect"
26 | import ColorSelect from "./ColorSelect"
27 | import { Tab, Tabs, TabList, TabPanel } from "react-tabs"
28 |
29 | @observer
30 | class Settings extends React.Component {
31 | render() {
32 | return (
33 |
34 |
35 |
36 | Draw
37 | Color
38 | Settings
39 | Save
40 | Help
41 |
42 |
43 |
44 | Glyph sets
45 |
46 |
47 | Select Layer
48 |
49 |
50 |
51 |
52 | Modes & Tools
53 |
54 |
58 |
62 |
66 |
67 | Glyph fine tuning
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | Canvas size
79 |
80 |
81 |
82 | Canvas size in millimeters
83 |
84 |
85 | Cell size
86 |
87 |
88 |
93 |
94 |
95 |
96 |
97 |
98 | Save / Load
99 |
103 |
104 |
105 |
106 | Export
107 |
111 |
112 | {/*
113 | Contribute to the new issue of GDC User Guide!
114 |
115 | If you would like to contribute your artwork to the upcoming
116 | GD.C User Guide v.2.0.0. zine, use the form below to submit your work. All contributions will be included to the zine. No limits!
117 |
118 | Last day to submit: 30.2.2019. The zine will be published during the late spring (date TBA) at Kosminen gallery in Helsinki.
119 |
120 | Contributors will receive a scanned pdf of the zine sent to email and can get the physical copy for the price of postage.
121 | The zines will be sold but only to cover printing costs and/or to fund future issues.
122 |
123 |
124 |
132 |
133 |
134 | By clicking the button above, you give permission to use your artwork in the zine and social media.
135 | Only your name and country will be published.
136 |
137 | */}
138 | License:
139 |
140 | You are free to use anything you make with GlyphDrawingClub
141 | anywhere (private or commercial), without credits or licensing
142 | info.
143 |
144 | Community links & project development:
145 |
149 | Github
150 |
151 |
152 |
153 |
154 | Instagram for examples & development updates
155 |
156 |
157 |
158 |
159 | Glyph Drawing Club blog
160 |
161 |
162 |
163 |
164 | Glyph Drawing Club discord channel for sharing, help, inspiration, community etc! Join now :)
165 |
166 |
167 |
168 |
169 | Basic tutorial
170 |
171 |
172 | Select the Draw tab from the
173 | sidebar
174 |
175 |
176 | Click on any glyph under Glyph
177 | selection.
178 |
179 |
180 | Press q to draw.
181 |
182 |
183 | Move around the canvas with{" "}
184 | arrow keys .
185 |
186 |
187 | Press f to flip,{" "}
188 | r to rotate or{" "}
189 | i to invert a glyph.
190 |
191 |
192 |
193 | Glyph Drawing Club is meant to be used with the keyboard, so check
194 | out all the shortcuts below!
195 |
196 |
197 | Complete tutorial
198 |
199 | You can find a complete tutorial & more at the{" "}
200 |
204 | Glyph Drawing Club Blog
205 |
206 |
207 |
208 | Keyboard Shortcuts
209 | Move
210 |
211 |
212 |
213 | Arrow keys or WASD
214 | Move
215 |
216 |
217 | Alt+Arrow keys
218 | Quickly move around the canvas
219 |
220 |
221 |
222 |
223 | Draw
224 | Hold down CTRL if you want to affect all layers
225 |
226 |
227 |
228 | q
229 | Draw (Place selected glyph)
230 |
231 |
232 | e or space
233 | Delete
234 |
235 |
236 | r
237 | Rotate
238 |
239 |
240 | f
241 | Flip
242 |
243 |
244 | i
245 | Invert
246 |
247 |
248 |
249 |
250 | Make glyph sets
251 |
252 |
253 |
254 | m
255 | Start mapping glyph sets. Press again to end mapping.
256 |
257 |
258 | Number keys 1–10
259 | Add selected glyph to set (when mapping is on)
260 |
261 |
262 | Number keys 1–10
263 | Insert glyph from set (when mapping is off)
264 |
265 |
266 |
267 |
268 | Extra
269 |
270 |
271 |
272 | Cmd/Ctrl+z
273 | Undo
274 |
275 |
276 | Cmd/Ctrl+Shift+z
277 | Redo
278 |
279 |
280 | h
281 | Hide Grid
282 |
283 |
284 | (hold) p
285 | Preview
286 |
287 |
288 | c
289 | Copy current glyph
290 |
291 |
292 |
293 |
294 | Area selection
295 | Hold down CTRL if you want to affect all layers
296 |
297 |
298 |
299 | Shift + s
300 |
301 | Start selection area. Use arrows keys to change the
302 | selection area. Press Shift + s again to lock selection area
303 |
304 |
305 |
306 | Shift + d
307 | Deselect area
308 |
309 |
310 | Shift + a
311 | Select all
312 |
313 |
314 | Shift + c
315 | Paste selected area
316 |
317 |
318 | Shift + m
319 | Mirror selected area
320 |
321 |
322 | Shift + f
323 | Flip selected area
324 |
325 |
326 | Shift + q
327 | Fill selected area with selected glyph
328 |
329 |
330 | Shift + e
331 | Empty selected area
332 |
333 |
334 | Shift + i
335 | Invert the colors of selected area
336 |
337 |
338 | Shift + y
339 | Rotate glyphs individually in selected area
340 |
341 |
342 | Shift + u
343 | Flip glyphs individually in selected area
344 |
345 |
346 | Shift + r
347 |
348 | Rotate selected area. Selection area has to be square (same
349 | amount of cells width & height)
350 |
351 |
352 |
353 | Shift + t
354 |
355 | Transpose selected area. Selection area has to be square
356 | (same amount of cells width & height)
357 |
358 |
359 |
360 | Shift + h
361 | Move selected area left
362 |
363 |
364 | Shift + j
365 | Move selected area down
366 |
367 |
368 | Shift + k
369 | Move selected area up
370 |
371 |
372 | Shift + l
373 | Move selected area right
374 |
375 |
376 |
377 |
378 | Coloring tools
379 |
380 |
381 |
382 | x
383 | Color palette quick access
384 |
385 |
386 | v
387 | Color foreground
388 |
389 |
390 | b
391 | Color background
392 |
393 |
394 | Shift + v
395 | Color selected area foreground
396 |
397 |
398 | Shift + b
399 | Color selected area background
400 |
401 |
402 |
403 |
404 |
405 |
406 | )
407 | }
408 | }
409 |
410 | export default Settings
411 |
--------------------------------------------------------------------------------
/style.css:
--------------------------------------------------------------------------------
1 | /* http://meyerweb.com/eric/tools/css/reset/
2 | v2.0 | 20110126
3 | License: none (public domain)
4 | */
5 |
6 | html, body, div, span, applet, object, iframe,
7 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
8 | a, abbr, acronym, address, big, cite, code,
9 | del, dfn, em, img, ins, kbd, q, s, samp,
10 | small, strike, strong, sub, sup, tt, var,
11 | b, u, i, center,
12 | dl, dt, dd, ol, ul, li,
13 | fieldset, form, label, legend,
14 | table, caption, tbody, tfoot, thead, tr, th, td,
15 | article, aside, canvas, details, embed,
16 | figure, figcaption, footer, header, hgroup,
17 | menu, nav, output, ruby, section, summary,
18 | time, mark, audio, video {
19 | margin: 0;
20 | padding: 0;
21 | border: 0;
22 | font-size: 100%;
23 | font: inherit;
24 | vertical-align: baseline;
25 | }
26 | /* HTML5 display-role reset for older browsers */
27 | article, aside, details, figcaption, figure,
28 | footer, header, hgroup, menu, nav, section {
29 | display: block;
30 | }
31 | body {
32 | line-height: 1;
33 | }
34 | ol, ul {
35 | list-style: none;
36 | }
37 | blockquote, q {
38 | quotes: none;
39 | }
40 | blockquote:before, blockquote:after,
41 | q:before, q:after {
42 | content: '';
43 | content: none;
44 | }
45 | table {
46 | border-collapse: collapse;
47 | border-spacing: 0;
48 | }
49 |
50 | /* ~~~~~~~~~~~~~~~~~~~~~
51 | document lvl
52 | ~~~~~~~~~~~~~~~~~~~~~ */
53 | html,
54 | body {
55 | height: 100vh;
56 | padding: 0;
57 | margin: 0;
58 | font-family: monospace;
59 | background: #ddd;
60 | }
61 | html {
62 | box-sizing: border-box;
63 | }
64 | *, *:before, *:after {
65 | box-sizing: inherit;
66 | }
67 | b {
68 | font-weight: bold;
69 | }
70 | em {
71 | font-style:italic;
72 | margin:10px 0;
73 | display: block;
74 | }
75 |
76 | /* ~~~~~~~~~~~~~~~~~~~~~
77 | top wrapper
78 | ~~~~~~~~~~~~~~~~~~~~~ */
79 | #root {
80 | height: 100%;
81 | }
82 | .flex_wrapper {
83 | height: 100%;
84 | width: 100%;
85 | display: flex;
86 | flex-direction: row;
87 | }
88 |
89 | /* ~~~~~~~~~~~~~~~~~~~~~
90 | canvas & grid
91 | ~~~~~~~~~~~~~~~~~~~~~ */
92 | .canvas_container {
93 | background: #ddd;
94 | display: flex;
95 | flex-direction: column;
96 | overflow: hidden;
97 | flex: 1;
98 | }
99 | .aligner {
100 | display: flex;
101 | flex: 1;
102 | flex-direction: column;
103 | align-items: center;
104 | justify-content: center;
105 | overflow: hidden;
106 | position: relative;
107 | }
108 | .grid {
109 | background: white;
110 | position: absolute;
111 | }
112 | .gridBg {
113 | background: white;
114 | }
115 | .gridBg,
116 | .gridFg {
117 | position: absolute;
118 | top:0;left:0;
119 | }
120 | .UiGrid {
121 | position: absolute;
122 | top:0;
123 | left:0;
124 | pointer-events: none;
125 | opacity: 0.5;
126 | }
127 | .UiLayer {
128 | position: absolute;
129 | top:0;
130 | left:0;
131 | pointer-events: none;
132 | }
133 | /* ~~~~~~~~~~~~~~~~~~~~~
134 | cells
135 | ~~~~~~~~~~~~~~~~~~~~~ */
136 | .row div {
137 | display: inline-block;
138 | vertical-align:top;
139 | overflow: visible;
140 | position: relative;
141 | }
142 | .row div svg {
143 | position: absolute;
144 | top: 0;
145 | left: 0;
146 | pointer-events: none;
147 | }
148 | .row div svg rect,
149 | .row div svg path {
150 | pointer-events: none;
151 | }
152 | /* ~~~~~~~~~~~~~~~~~~~~~
153 | grid numbers / cursor
154 | ~~~~~~~~~~~~~~~~~~~~~ */
155 | .rowNums div.rowNum {
156 | position: absolute;
157 | display: flex;
158 | align-items: center;
159 | justify-content: center;
160 | width: 30px;
161 | left: -30px;
162 | box-shadow: none;
163 | text-align: right;
164 | font-size: 0.6em;
165 | background: none;
166 | color: #888;
167 | }
168 | .rowNums div.rowNum.highlighted {
169 | color: red;
170 | }
171 | .colNums {
172 | width: 100%;
173 | position: relative;
174 | height: 0;
175 | }
176 | .colNum {
177 | width: auto;
178 | display: inline-flex;
179 | justify-content: center;
180 | align-items: center;
181 | font-size: 0.6em;
182 | background: none;
183 | color:#888;
184 | position: relative;
185 | height: 25px;
186 | top: -25px;
187 | }
188 | .colNum.highlighted {
189 | color: red;
190 | }
191 | /* ~~~~~~~~~~~~~~~~~~~~~
192 | selection highlight
193 | ~~~~~~~~~~~~~~~~~~~~~ */
194 | .selectionHighlight {
195 | top: 0;
196 | left: 0;
197 | position: absolute;
198 | pointer-events: none;
199 | background-image: linear-gradient(90deg, red 50%, transparent 50%), linear-gradient(90deg, red 50%, transparent 50%), linear-gradient(0deg, red 50%, transparent 50%), linear-gradient(0deg, red 50%, transparent 50%);
200 | background-repeat: repeat-x, repeat-x, repeat-y, repeat-y;
201 | background-size: 15px 1px, 15px 1px, 1px 15px, 1px 15px;
202 | background-position: left top, right bottom, left bottom, right top;
203 | animation: border-dance 1s infinite linear;
204 | }
205 | @keyframes border-dance {
206 | 0% {
207 | background-position: left top, right bottom, left bottom, right top;
208 | }
209 | 100% {
210 | background-position: left 15px top, right 15px bottom , left bottom 15px , right top 15px;
211 | }
212 | }
213 | .selectionHighlight.isSquare:after {
214 | content: 's';
215 | position: absolute;
216 | bottom:0;
217 | right:0;
218 | }
219 |
220 | /* ~~~~~~~~~~~~~~~~~~~~~
221 | coordinates
222 | ~~~~~~~~~~~~~~~~~~~~~ */
223 | .coordinates {
224 | position: absolute;
225 | top: 0;
226 | right: 5px;
227 | }
228 | /* ~~~~~~~~~~~~~~~~~~~~~
229 | colors
230 | ~~~~~~~~~~~~~~~~~~~~~ */
231 | .colorPalette {
232 | display: flex;
233 | flex-wrap: wrap;
234 | background: #eee;
235 | }
236 | .color {
237 | float:left;
238 | width:25px;
239 | height:25px;
240 | cursor:pointer;
241 | font-size:9px;
242 | }
243 | .selectedColor {
244 | box-shadow: 0 0 0 1px rgba(0,255,0,1);
245 | }
246 | .colorSliders {
247 | margin-top: 10px;
248 | display: flex;
249 | }
250 | .rgbSliders {
251 | flex: 1;
252 | }
253 | .rgbSlider input[type="range"] {
254 | -webkit-appearance: none;
255 | outline: none;
256 | border-radius:10px;
257 | }
258 | .colorPreview {
259 | flex: 1;
260 | }
261 | .intensitySlider {
262 | float: left;
263 | }
264 |
265 | /* ~~~~~~~~~~~~~~~~~~~~~
266 | grid move / zoom
267 | ~~~~~~~~~~~~~~~~~~~~~ */
268 | .grid_controls {
269 | position: absolute;
270 | bottom: 0;
271 | right: 5px;
272 | width: 70px;
273 | height: 100px;
274 | }
275 | .grid_controls button{
276 | width: 20px;
277 | height: 20px;
278 | padding: 0;
279 | margin-right: 3px;
280 | vertical-align: middle;
281 | border:none;
282 | background: #eee;
283 | box-shadow: 0 0 0 1px rgba(0,0,0,1);
284 | }
285 | .grid_controls button:hover {
286 | transform: scale(1.1);
287 | }
288 | .grid_controls .zoom {
289 | display: flex;
290 | justify-content: flex-end;
291 | margin-bottom: 5px
292 | }
293 | .grid_controls .zoom button:first-child {
294 | margin-right: 4px;
295 | }
296 | .grid_controls .move_y {
297 | display: block;
298 | margin: 3px auto;
299 | width: 25px;
300 | }
301 |
302 | /* ~~~~~~~~~~~~~~~~~~~~~
303 | hide grid checked
304 | ~~~~~~~~~~~~~~~~~~~~~ */
305 | .canvas_container.hideGrid {
306 | background: white;
307 | }
308 | .canvas_container.hideGrid .cursor,
309 | .canvas_container.hideGrid .colNums,
310 | .canvas_container.hideGrid .rowNums,
311 | .canvas_container.hideGrid .UiGrid {
312 | display: none;
313 | }
314 |
315 | /* ~~~~~~~~~~~~~~~~~~~~~
316 | text styles
317 | ~~~~~~~~~~~~~~~~~~~~~ */
318 | ol.instructions {
319 | list-style: initial;
320 | list-style-type:decimal;
321 | list-style-position: inside;
322 | margin-top: 0;
323 | }
324 | ol li {
325 | margin-top: 5px;
326 | }
327 | span.hotkey {
328 | background: #eee;
329 | padding: 2px;
330 | border-radius: 5px;
331 | }
332 | #dropbox-response {
333 | color:red;
334 | }
335 | h3 {
336 | width: 100%;
337 | background: #eee;
338 | font-weight: bold;
339 | padding: 0.5em;
340 | margin: 1em 0 0.5em 0;
341 | text-transform: uppercase;
342 | letter-spacing: 1px;
343 | }
344 | h4 {
345 | font-weight: bold;
346 | margin: 1em 0 0.5em 0;
347 | }
348 | table,
349 | tr {
350 | width: 100%;
351 | }
352 | tr {
353 | border-bottom:1px dotted grey;
354 | }
355 | td {
356 | padding-bottom: 2px;
357 | }
358 | table tr td {
359 | width: 65%;
360 | }
361 | table tr td:first-child {
362 | width: 35%;
363 | }
364 |
365 | /* ~~~~~~~~~~~~~~~~~~~~~
366 | controls
367 | ~~~~~~~~~~~~~~~~~~~~~ */
368 | .controls_container {
369 | background: white;
370 | width: 430px;
371 | padding: 5px;
372 | overflow-y: scroll;
373 | flex: none;
374 | box-shadow: 0 0 2px 0 rgba(0,0,0,0.3);
375 |
376 | }
377 | .control_component {
378 | display:block;
379 | margin-bottom: 0.5em;
380 | }
381 | .header {
382 | width: 30%;
383 | display:inline-block;
384 | }
385 | button {
386 | margin-right: 0.5em;
387 | font-family:monospace;
388 | }
389 | .page_selection,
390 | .control_inputs {
391 | display: inline-block;
392 | }
393 | #page_select_input.input-error {
394 | color:red;
395 | }
396 |
397 | #glyphcont img:hover {
398 | box-shadow: inset 0 0 0 1px rgba(255,0,0,1);
399 | cursor: pointer;
400 | }
401 | .select_set button.active {
402 | background-color: lime;
403 | }
404 | .settingsBlock {
405 | padding-bottom: 1em;
406 | }
407 | .layerSelect {
408 | display: flex;
409 | }
410 | .layerSelect div {
411 | flex:1;
412 | }
413 | /* ~~~~~~~~~~~~~~~~~~~~~
414 | Preview
415 | ~~~~~~~~~~~~~~~~~~~~~ */
416 | .preview {
417 | display: block;
418 | position: absolute;
419 | top:0;
420 | left:0;
421 | width: 100vw;
422 | height: 100vh;
423 | background: black;
424 | z-index: 1000;
425 | overflow: hidden;
426 | }
427 | .preview > div {
428 | position: absolute;
429 | top: 50%;
430 | left: 50%;
431 | transform: translateX(-50%) translateY(-50%);
432 | max-width: 100%;
433 | max-height: 100%;
434 | }
435 | .preview svg {
436 | overflow: visible;
437 | }
438 | /* ~~~~~~~~~~~~~~~~~~~~~
439 | QuickChooseColor
440 | ~~~~~~~~~~~~~~~~~~~~~ */
441 | .quickChooseColor {
442 | position: absolute;
443 | top:0;
444 | left:0;
445 | width:100%;
446 | height:100%;
447 | z-index: 999;
448 | display: flex;
449 | justify-content: center;
450 | align-items: center;
451 | }
452 | .quickChooseColor .paletteContainer {
453 | width:400px;
454 | box-shadow: 0 0 5px 0 rgba(0,0,0,0.3);
455 | }
456 | /* ~~~~~~~~~~~~~~~~~~~~~
457 | keymappings bar
458 | ~~~~~~~~~~~~~~~~~~~~~ */
459 | .KeyMappingsBar {
460 | width: 100%;
461 | background: white;
462 | display: flex;
463 | box-sizing:border-box;
464 | padding: 5px;
465 | }
466 | .KeyMappingsBar .Sets {
467 | flex: 1;
468 | }
469 | .KeyMappingsContainer {
470 | display: none;
471 | }
472 | .KeyMappingsFlexer {
473 | display: flex;
474 | flex-direction: row;
475 | }
476 | .KeyMappingsContainer .KeyMappingsFlexer div:first-child {
477 | order:1;
478 | }
479 | .KeyMappingsContainer.active {
480 | display: block;
481 | }
482 | .KeyMappingsContainer .KeyMappingsFlexer > div {
483 | text-align: center;
484 | box-sizing:border-box;
485 | width: 40px;
486 | border:none;
487 | display: inline-block;
488 | position: relative;
489 | overflow: visible;
490 | }
491 | .ToggleMapping,
492 | .select_set {
493 | display: inline-block;
494 | margin-right: 4px;
495 | }
496 |
497 | /* ~~~~~~~~~~~~~~~~~~~~~
498 | selected glyph in keymappings bar
499 | ~~~~~~~~~~~~~~~~~~~~~ */
500 | .selectedGlyph {
501 | position: relative;
502 | }
503 | .selectedGlyph .vector {
504 | height: 30px;
505 | width: 30px;
506 | border: 1px solid black;
507 | overflow: visible;
508 | box-sizing:border-box;
509 | position: relative;
510 | display: inline-block;
511 | }
512 | .SelectedGlyphContainer {
513 | width: 185px;
514 | height: 50px;
515 | margin-top: auto;
516 | position: absolute;
517 | left:10px;
518 | bottom: 10px;
519 | }
520 | .SelectedGlyphContainer .selectedGlyph {
521 | display: inline;
522 | }
523 | .SelectedGlyphContainer .selectedGlyph .vector {
524 | width: 50px;
525 | height: 50px;
526 | background: white;
527 | }
528 | #properties {
529 | display:block;
530 | width: 100px;
531 | margin-left: 5px;
532 | position: absolute;
533 | top: 0;
534 | left: 80px;
535 | }
536 | .selectedGlyph .vector svg {
537 | height: 100%;
538 | overflow: visible;
539 | position: absolute;
540 | top:0;left:0;right:0;bottom:0;
541 | margin:auto;
542 | }
543 |
544 | /* ~~~~~~~~~~~~~~~~~~~~~
545 | react-tabs
546 | ~~~~~~~~~~~~~~~~~~~~~ */
547 | .react-tabs {
548 | -webkit-tap-highlight-color: transparent;
549 | }
550 |
551 | .react-tabs__tab-list {
552 | border-bottom: 1px solid #aaa;
553 | margin: 0 0 10px;
554 | padding: 0;
555 | }
556 |
557 | .react-tabs__tab {
558 | display: inline-block;
559 | border: 1px solid transparent;
560 | border-bottom: none;
561 | bottom: -1px;
562 | position: relative;
563 | list-style: none;
564 | padding: 6px 12px;
565 | cursor: pointer;
566 | }
567 |
568 | .react-tabs__tab--selected {
569 | background: #fff;
570 | border-color: #aaa;
571 | color: black;
572 | border-radius: 5px 5px 0 0;
573 | }
574 |
575 | .react-tabs__tab--disabled {
576 | color: GrayText;
577 | cursor: default;
578 | }
579 |
580 | .react-tabs__tab:focus {
581 | box-shadow: 0 0 5px hsl(208, 99%, 50%);
582 | border-color: hsl(208, 99%, 50%);
583 | outline: none;
584 | }
585 |
586 | .react-tabs__tab:focus:after {
587 | content: "";
588 | position: absolute;
589 | height: 5px;
590 | left: -4px;
591 | right: -4px;
592 | bottom: -5px;
593 | background: #fff;
594 | }
595 |
596 | .react-tabs__tab-panel {
597 | display: none;
598 | }
599 |
600 | .react-tabs__tab-panel--selected {
601 | display: block;
602 | }
--------------------------------------------------------------------------------
/scripts/Typr.U.js:
--------------------------------------------------------------------------------
1 |
2 | if(Typr ==null) Typr = {};
3 | if(Typr.U==null) Typr.U = {};
4 |
5 |
6 | Typr.U.codeToGlyph = function(font, code)
7 | {
8 | var cmap = font.cmap;
9 |
10 |
11 | var tind = -1;
12 | if(cmap.p0e4!=null) tind = cmap.p0e4;
13 | else if(cmap.p3e1!=null) tind = cmap.p3e1;
14 | else if(cmap.p1e0!=null) tind = cmap.p1e0;
15 |
16 | if(tind==-1) throw "no familiar platform and encoding!";
17 |
18 | var tab = cmap.tables[tind];
19 |
20 | if(tab.format==0)
21 | {
22 | if(code>=tab.map.length) return 0;
23 | return tab.map[code];
24 | }
25 | else if(tab.format==4)
26 | {
27 | var sind = -1;
28 | for(var i=0; i
code) return 0;
31 |
32 | var gli = 0;
33 | if(tab.idRangeOffset[sind]!=0) gli = tab.glyphIdArray[(code-tab.startCount[sind]) + (tab.idRangeOffset[sind]>>1) - (tab.idRangeOffset.length-sind)];
34 | else gli = code + tab.idDelta[sind];
35 | return gli & 0xFFFF;
36 | }
37 | else if(tab.format==12)
38 | {
39 | if(code>tab.groups[tab.groups.length-1][1]) return 0;
40 | for(var i=0; i-1) Typr.U._simpleGlyph(gl, path);
69 | else Typr.U._compoGlyph (gl, font, path);
70 | }
71 | }
72 | Typr.U._simpleGlyph = function(gl, p)
73 | {
74 | for(var c=0; c=g) return cd.class[i];
138 | return 0;
139 | }
140 |
141 | Typr.U.getPairAdjustment = function(font, g1, g2)
142 | {
143 | if(font.GPOS)
144 | {
145 | var ltab = null;
146 | for(var i=0; irlim) continue;
259 | var good = true;
260 | for(var l=0; l> 1;
393 | stack.length = 0;
394 | haveWidth = true;
395 | }
396 | else if(v=="o3" || v=="o23") // vstem || vstemhm
397 | {
398 | var hasWidthArg;
399 |
400 | // The number of stem operators on the stack is always even.
401 | // If the value is uneven, that means a width is specified.
402 | hasWidthArg = stack.length % 2 !== 0;
403 | if (hasWidthArg && !haveWidth) {
404 | width = stack.shift() + font.Private.nominalWidthX;
405 | }
406 |
407 | nStems += stack.length >> 1;
408 | stack.length = 0;
409 | haveWidth = true;
410 | }
411 | else if(v=="o4")
412 | {
413 | if (stack.length > 1 && !haveWidth) {
414 | width = stack.shift() + font.Private.nominalWidthX;
415 | haveWidth = true;
416 | }
417 | if(open) Typr.U.P.closePath(p);
418 |
419 | y += stack.pop();
420 | Typr.U.P.moveTo(p,x,y); open=true;
421 | }
422 | else if(v=="o5")
423 | {
424 | while (stack.length > 0) {
425 | x += stack.shift();
426 | y += stack.shift();
427 | Typr.U.P.lineTo(p, x, y);
428 | }
429 | }
430 | else if(v=="o6" || v=="o7") // hlineto || vlineto
431 | {
432 | var count = stack.length;
433 | var isX = (v == "o6");
434 |
435 | for(var j=0; j Math.abs(c4y - y)) {
531 | x = c4x + stack.shift();
532 | } else {
533 | y = c4y + stack.shift();
534 | }
535 | Typr.U.P.curveTo(p, c1x, c1y, c2x, c2y, jpx, jpy);
536 | Typr.U.P.curveTo(p, c3x, c3y, c4x, c4y, x, y);
537 | }
538 | }
539 | else if(v=="o14")
540 | {
541 | if (stack.length > 0 && !haveWidth) {
542 | width = stack.shift() + font.nominalWidthX;
543 | haveWidth = true;
544 | }
545 | if(stack.length==4) // seac = standard encoding accented character
546 | {
547 |
548 | var asb = 0;
549 | var adx = stack.shift();
550 | var ady = stack.shift();
551 | var bchar = stack.shift();
552 | var achar = stack.shift();
553 |
554 |
555 | var bind = Typr.CFF.glyphBySE(font, bchar);
556 | var aind = Typr.CFF.glyphBySE(font, achar);
557 |
558 | //console.log(bchar, bind);
559 | //console.log(achar, aind);
560 | //state.x=x; state.y=y; state.nStems=nStems; state.haveWidth=haveWidth; state.width=width; state.open=open;
561 |
562 | Typr.U._drawCFF(font.CharStrings[bind], state,font,p);
563 | state.x = adx; state.y = ady;
564 | Typr.U._drawCFF(font.CharStrings[aind], state,font,p);
565 |
566 | //x=state.x; y=state.y; nStems=state.nStems; haveWidth=state.haveWidth; width=state.width; open=state.open;
567 | }
568 | if(open) { Typr.U.P.closePath(p); open=false; }
569 | }
570 | else if(v=="o19" || v=="o20")
571 | {
572 | var hasWidthArg;
573 |
574 | // The number of stem operators on the stack is always even.
575 | // If the value is uneven, that means a width is specified.
576 | hasWidthArg = stack.length % 2 !== 0;
577 | if (hasWidthArg && !haveWidth) {
578 | width = stack.shift() + font.Private.nominalWidthX;
579 | }
580 |
581 | nStems += stack.length >> 1;
582 | stack.length = 0;
583 | haveWidth = true;
584 |
585 | i += (nStems + 7) >> 3;
586 | }
587 |
588 | else if(v=="o21") {
589 | if (stack.length > 2 && !haveWidth) {
590 | width = stack.shift() + font.Private.nominalWidthX;
591 | haveWidth = true;
592 | }
593 |
594 | y += stack.pop();
595 | x += stack.pop();
596 |
597 | if(open) Typr.U.P.closePath(p);
598 | Typr.U.P.moveTo(p,x,y); open=true;
599 | }
600 | else if(v=="o22")
601 | {
602 | if (stack.length > 1 && !haveWidth) {
603 | width = stack.shift() + font.Private.nominalWidthX;
604 | haveWidth = true;
605 | }
606 |
607 | x += stack.pop();
608 |
609 | if(open) Typr.U.P.closePath(p);
610 | Typr.U.P.moveTo(p,x,y); open=true;
611 | }
612 | else if(v=="o25")
613 | {
614 | while (stack.length > 6) {
615 | x += stack.shift();
616 | y += stack.shift();
617 | Typr.U.P.lineTo(p, x, y);
618 | }
619 |
620 | c1x = x + stack.shift();
621 | c1y = y + stack.shift();
622 | c2x = c1x + stack.shift();
623 | c2y = c1y + stack.shift();
624 | x = c2x + stack.shift();
625 | y = c2y + stack.shift();
626 | Typr.U.P.curveTo(p, c1x, c1y, c2x, c2y, x, y);
627 | }
628 | else if(v=="o26")
629 | {
630 | if (stack.length % 2) {
631 | x += stack.shift();
632 | }
633 |
634 | while (stack.length > 0) {
635 | c1x = x;
636 | c1y = y + stack.shift();
637 | c2x = c1x + stack.shift();
638 | c2y = c1y + stack.shift();
639 | x = c2x;
640 | y = c2y + stack.shift();
641 | Typr.U.P.curveTo(p, c1x, c1y, c2x, c2y, x, y);
642 | }
643 |
644 | }
645 | else if(v=="o27")
646 | {
647 | if (stack.length % 2) {
648 | y += stack.shift();
649 | }
650 |
651 | while (stack.length > 0) {
652 | c1x = x + stack.shift();
653 | c1y = y;
654 | c2x = c1x + stack.shift();
655 | c2y = c1y + stack.shift();
656 | x = c2x + stack.shift();
657 | y = c2y;
658 | Typr.U.P.curveTo(p, c1x, c1y, c2x, c2y, x, y);
659 | }
660 | }
661 | else if(v=="o10" || v=="o29") // callsubr || callgsubr
662 | {
663 | var obj = (v=="o10" ? font.Private : font);
664 | if(stack.length==0) { console.log("error: empty stack"); }
665 | else {
666 | var ind = stack.pop();
667 | var subr = obj.Subrs[ ind + obj.Bias ];
668 | state.x=x; state.y=y; state.nStems=nStems; state.haveWidth=haveWidth; state.width=width; state.open=open;
669 | Typr.U._drawCFF(subr, state,font,p);
670 | x=state.x; y=state.y; nStems=state.nStems; haveWidth=state.haveWidth; width=state.width; open=state.open;
671 | }
672 | }
673 | else if(v=="o30" || v=="o31") // vhcurveto || hvcurveto
674 | {
675 | var count, count1 = stack.length;
676 | var index = 0;
677 | var alternate = v == "o31";
678 |
679 | count = count1 & ~2;
680 | index += count1 - count;
681 |
682 | while ( index < count )
683 | {
684 | if(alternate)
685 | {
686 | c1x = x + stack.shift();
687 | c1y = y;
688 | c2x = c1x + stack.shift();
689 | c2y = c1y + stack.shift();
690 | y = c2y + stack.shift();
691 | if(count-index == 5) { x = c2x + stack.shift(); index++; }
692 | else x = c2x;
693 | alternate = false;
694 | }
695 | else
696 | {
697 | c1x = x;
698 | c1y = y + stack.shift();
699 | c2x = c1x + stack.shift();
700 | c2y = c1y + stack.shift();
701 | x = c2x + stack.shift();
702 | if(count-index == 5) { y = c2y + stack.shift(); index++; }
703 | else y = c2y;
704 | alternate = true;
705 | }
706 | Typr.U.P.curveTo(p, c1x, c1y, c2x, c2y, x, y);
707 | index += 4;
708 | }
709 | }
710 |
711 | else if((v+"").charAt(0)=="o") { console.log("Unknown operation: "+v, cmds); throw v; }
712 | else stack.push(v);
713 | }
714 | //console.log(cmds);
715 | state.x=x; state.y=y; state.nStems=nStems; state.haveWidth=haveWidth; state.width=width; state.open=open;
716 | }
--------------------------------------------------------------------------------
/src/utils/colorPresets.json:
--------------------------------------------------------------------------------
1 | [{
2 | "name": "Deluxe Paint",
3 | "palette": [[0,0,0],[48,138,69],[245,245,245],[113,113,113],[243,0,0],[146,0,0],[243,211,211],[243,162,81],[243,243,211],[227,211,0],[211,243,81],[211,243,211],[0,243,0],[0,146,0],[211,243,243],[0,227,227],[170,170,170],[69,223,69],[227,227,227],[113,113,113],[227,0,0],[130,0,0],[243,178,178],[243,146,65],[243,243,178],[195,195,0],[195,243,65],[178,243,178],[0,227,0],[0,130,0],[178,243,243],[0,195,195],[101,101,101],[69,223,207],[223,223,223],[101,101,101],[227,0,0],[113,0,0],[243,146,146],[243,130,32],[243,243,146],[178,162,0],[178,243,32],[146,243,146],[0,227,0],[0,113,0],[146,243,243],[0,178,178],[223,223,223],[48,138,207],[195,195,195],[81,81,81],[211,0,0],[113,0,0],[243,113,113],[243,113,0],[243,243,113],[146,146,0],[162,243,0],[130,243,113],[0,211,0],[0,113,0],[113,243,243],[0,146,146],[207,48,69],[138,138,223],[178,178,178],[65,65,65],[195,0,0],[97,0,0],[243,81,81],[227,97,0],[243,243,81],[130,130,0],[146,227,0],[97,243,81],[0,195,0],[0,97,0],[81,243,243],[0,130,130],[223,138,69],[69,48,207],[170,170,170],[48,48,48],[178,0,0],[81,0,0],[243,65,65],[195,97,0],[243,243,65],[113,97,0],[130,195,0],[65,243,65],[0,178,0],[0,81,0],[65,243,243],[0,113,113],[207,223,69],[207,48,207],[146,146,146],[32,32,32],[178,0,0],[65,0,0],[243,32,32],[178,81,0],[243,243,32],[81,81,0],[113,178,0],[32,243,32],[0,178,0],[0,65,0],[32,243,243],[0,81,81],[138,138,48],[223,138,207],[130,130,130],[32,32,32],[162,0,0],[65,0,0],[243,0,0],[146,65,0],[243,243,0],[65,65,0],[97,146,0],[0,243,0],[0,162,0],[0,65,0],[0,243,243],[0,65,65],[81,178,243],[211,211,243],[0,0,243],[0,0,146],[243,211,243],[146,0,227],[243,211,243],[227,0,227],[243,227,211],[195,146,130],[130,65,48],[81,16,16],[243,81,81],[195,32,32],[32,195,48],[81,32,195],[65,178,243],[178,178,243],[0,0,227],[0,0,130],[227,178,243],[130,0,195],[243,178,243],[195,0,195],[243,211,211],[178,130,113],[130,48,48],[65,16,0],[243,178,130],[195,65,32],[32,195,81],[130,32,195],[32,162,243],[146,146,243],[0,0,227],[0,0,113],[211,146,243],[113,0,178],[243,146,243],[178,0,178],[243,211,195],[178,113,97],[113,48,32],[65,0,0],[243,243,130],[195,113,32],[32,195,130],[178,32,195],[0,146,243],[113,130,243],[0,0,211],[0,0,113],[211,113,243],[97,0,146],[243,113,243],[146,0,146],[227,195,178],[162,113,97],[113,48,32],[48,0,0],[130,243,130],[195,146,32],[32,195,178],[195,32,162],[0,130,227],[81,97,243],[0,0,195],[0,0,97],[195,81,243],[81,0,130],[243,81,243],[130,0,130],[227,178,162],[162,97,81],[113,32,32],[48,0,0],[130,243,243],[195,195,32],[32,162,195],[195,32,130],[0,113,195],[65,65,243],[0,0,178],[0,0,81],[178,65,243],[65,0,113],[243,65,243],[97,0,113],[211,178,146],[162,97,81],[97,32,16],[32,0,0],[130,130,243],[146,195,32],[32,113,195],[195,32,81],[0,97,178],[32,32,243],[0,0,178],[0,0,65],[178,32,243],[48,0,81],[243,32,243],[81,0,81],[211,162,146],[146,81,65],[97,16,16],[32,0,0],[178,130,243],[113,195,32],[32,81,195],[195,32,32],[0,81,146],[0,0,243],[0,0,162],[0,0,65],[162,0,243],[32,0,65],[243,0,243],[65,0,65],[195,146,130],[146,81,65],[81,16,16],[32,0,0],[243,130,243],[65,195,32],[32,32,195],[255,255,255]]
4 | }, {
5 | "name": "AtariST (Reduced To 256)",
6 | "palette": [[0,0,0],[0,0,36],[0,0,72],[0,0,109],[0,0,145],[0,0,182],[0,0,218],[0,0,255],[72,0,0],[72,0,36],[72,0,72],[72,0,109],[72,0,145],[72,0,182],[72,0,218],[72,0,255],[0,36,0],[0,36,36],[0,36,72],[0,36,109],[0,36,145],[0,36,182],[0,36,218],[0,36,255],[72,36,0],[72,36,36],[72,36,72],[72,36,109],[72,36,145],[72,36,182],[72,36,218],[72,36,255],[0,72,0],[0,72,36],[0,72,72],[0,72,109],[0,72,145],[0,72,182],[0,72,218],[0,72,255],[72,72,0],[72,72,36],[72,72,72],[72,72,109],[72,72,145],[72,72,182],[72,72,218],[72,72,255],[0,109,0],[0,109,36],[0,109,72],[0,109,109],[0,109,145],[0,109,182],[0,109,218],[0,109,255],[72,109,0],[72,109,36],[72,109,72],[72,109,109],[72,109,145],[72,109,182],[72,109,218],[72,109,255],[0,145,0],[0,145,36],[0,145,72],[0,145,109],[0,145,145],[0,145,182],[0,145,218],[0,145,255],[72,145,0],[72,145,36],[72,145,72],[72,145,109],[72,145,145],[72,145,182],[72,145,218],[72,145,255],[0,182,0],[0,182,36],[0,182,72],[0,182,109],[0,182,145],[0,182,182],[0,182,218],[0,182,255],[72,182,0],[72,182,36],[72,182,72],[72,182,109],[72,182,145],[72,182,182],[72,182,218],[72,182,255],[0,218,0],[0,218,36],[0,218,72],[0,218,109],[0,218,145],[0,218,182],[0,218,218],[0,218,255],[72,218,0],[72,218,36],[72,218,72],[72,218,109],[72,218,145],[72,218,182],[72,218,218],[72,218,255],[0,255,0],[0,255,36],[0,255,72],[0,255,109],[0,255,145],[0,255,182],[0,255,218],[0,255,255],[72,255,0],[72,255,36],[72,255,72],[72,255,109],[72,255,145],[72,255,182],[72,255,218],[72,255,255],[145,0,0],[145,0,36],[145,0,72],[145,0,109],[145,0,145],[145,0,182],[145,0,218],[145,0,255],[255,0,0],[255,0,36],[255,0,72],[255,0,109],[255,0,145],[255,0,182],[255,0,218],[255,0,255],[145,36,0],[145,36,36],[145,36,72],[145,36,109],[145,36,145],[145,36,182],[145,36,218],[145,36,255],[255,36,0],[255,36,36],[255,36,72],[255,36,109],[255,36,145],[255,36,182],[255,36,218],[255,36,255],[145,72,0],[145,72,36],[145,72,72],[145,72,109],[145,72,145],[145,72,182],[145,72,218],[145,72,255],[255,72,0],[255,72,36],[255,72,72],[255,72,109],[255,72,145],[255,72,182],[255,72,218],[255,72,255],[145,109,0],[145,109,36],[145,109,72],[145,109,109],[145,109,145],[145,109,182],[145,109,218],[145,109,255],[255,109,0],[255,109,36],[255,109,72],[255,109,109],[255,109,145],[255,109,182],[255,109,218],[255,109,255],[145,145,0],[145,145,36],[145,145,72],[145,145,109],[145,145,145],[145,145,182],[145,145,218],[145,145,255],[255,145,0],[255,145,36],[255,145,72],[255,145,109],[255,145,145],[255,145,182],[255,145,218],[255,145,255],[145,182,0],[145,182,36],[145,182,72],[145,182,109],[145,182,145],[145,182,182],[145,182,218],[145,182,255],[255,182,0],[255,182,36],[255,182,72],[255,182,109],[255,182,145],[255,182,182],[255,182,218],[255,182,255],[145,218,0],[145,218,36],[145,218,72],[145,218,109],[145,218,145],[145,218,182],[145,218,218],[145,218,255],[255,218,0],[255,218,36],[255,218,72],[255,218,109],[255,218,145],[255,218,182],[255,218,218],[255,218,255],[145,255,0],[145,255,36],[145,255,72],[145,255,109],[145,255,145],[145,255,182],[145,255,218],[145,255,255],[255,255,0],[255,255,36],[255,255,72],[255,255,109],[255,255,145],[255,255,182],[255,255,218],[255,255,255]]
7 | }, {
8 | "name": "Eclipse icon",
9 | "palette": [[0,0,0],[128,0,0],[0,128,0],[128,128,0],[0,0,128],[128,0,128],[0,128,128],[192,192,192],[192,220,192],[166,202,240],[95,63,63],[127,63,63],[159,63,63],[191,63,63],[223,63,63],[255,63,63],[63,95,63],[95,95,63],[127,95,63],[159,95,63],[191,95,63],[223,95,63],[255,95,63],[63,127,63],[95,127,63],[127,127,63],[159,127,63],[191,127,63],[223,127,63],[255,127,63],[63,159,63],[95,159,63],[127,159,63],[159,159,63],[191,159,63],[223,159,63],[255,159,63],[63,191,63],[95,191,63],[127,191,63],[159,191,63],[191,191,63],[223,191,63],[255,191,63],[63,223,63],[95,223,63],[127,223,63],[159,223,63],[191,223,63],[223,223,63],[255,223,63],[63,255,63],[95,255,63],[127,255,63],[159,255,63],[191,255,63],[223,255,63],[255,255,63],[63,63,95],[95,63,95],[127,63,95],[159,63,95],[191,63,95],[223,63,95],[255,63,95],[63,95,95],[95,95,95],[127,95,95],[159,95,95],[191,95,95],[223,95,95],[255,95,95],[63,127,95],[95,127,95],[127,127,95],[159,127,95],[191,127,95],[223,127,95],[255,127,95],[63,159,95],[95,159,95],[127,159,95],[159,159,95],[191,159,95],[223,159,95],[255,159,95],[63,191,95],[95,191,95],[127,191,95],[159,191,95],[191,191,95],[223,191,95],[255,191,95],[63,223,95],[95,223,95],[127,223,95],[159,223,95],[191,223,95],[223,223,95],[255,223,95],[63,255,95],[95,255,95],[127,255,95],[159,255,95],[191,255,95],[223,255,95],[255,255,95],[63,63,127],[95,63,127],[127,63,127],[159,63,127],[191,63,127],[223,63,127],[255,63,127],[63,95,127],[95,95,127],[127,95,127],[159,95,127],[191,95,127],[223,95,127],[255,95,127],[63,127,127],[95,127,127],[127,127,127],[159,127,127],[191,127,127],[223,127,127],[255,127,127],[63,159,127],[95,159,127],[127,159,127],[159,159,127],[191,159,127],[223,159,127],[255,159,127],[63,191,127],[95,191,127],[127,191,127],[159,191,127],[191,191,127],[223,191,127],[255,191,127],[63,223,127],[95,223,127],[127,223,127],[159,223,127],[191,223,127],[223,223,127],[255,223,127],[63,255,127],[95,255,127],[127,255,127],[159,255,127],[191,255,127],[223,255,127],[255,255,127],[63,63,159],[95,63,159],[127,63,159],[159,63,159],[191,63,159],[223,63,159],[255,63,159],[63,95,159],[95,95,159],[127,95,159],[159,95,159],[191,95,159],[223,95,159],[255,95,159],[63,127,159],[95,127,159],[127,127,159],[159,127,159],[191,127,159],[223,127,159],[255,127,159],[63,159,159],[95,159,159],[127,159,159],[159,159,159],[191,159,159],[223,159,159],[255,159,159],[63,191,159],[95,191,159],[127,191,159],[159,191,159],[191,191,159],[223,191,159],[255,191,159],[63,223,159],[95,223,159],[127,223,159],[159,223,159],[191,223,159],[223,223,159],[255,223,159],[63,255,159],[95,255,159],[127,255,159],[159,255,159],[191,255,159],[223,255,159],[255,255,159],[63,63,191],[95,63,191],[127,63,191],[159,63,191],[191,63,191],[223,63,191],[255,63,191],[63,95,191],[95,95,191],[127,95,191],[159,95,191],[191,95,191],[223,95,191],[255,95,191],[63,127,191],[95,127,191],[127,127,191],[159,127,191],[191,127,191],[223,127,191],[255,127,191],[63,159,191],[95,159,191],[127,159,191],[159,159,191],[191,159,191],[223,159,191],[255,159,191],[63,191,191],[95,191,191],[127,191,191],[159,191,191],[191,191,191],[223,191,191],[255,191,191],[63,223,191],[95,223,191],[127,223,191],[159,223,191],[191,223,191],[223,223,191],[255,251,240],[160,160,164],[128,128,128],[255,0,0],[0,255,0],[255,255,0],[0,0,255],[255,0,255],[0,255,255],[255,255,255]]
10 | }, {
11 | "name": "Fornax Void Official Palette No.1",
12 | "palette": [[122,37,255],[117,42,255],[112,47,255],[108,51,255],[103,56,255],[99,60,255],[94,65,255],[89,70,255],[85,74,255],[80,79,255],[76,83,255],[71,88,255],[66,93,255],[62,97,255],[57,102,255],[53,106,255],[47,222,235],[55,214,242],[63,206,249],[70,198,255],[78,190,255],[86,182,255],[93,174,255],[101,166,255],[109,158,255],[116,150,255],[124,142,255],[132,134,255],[139,126,255],[147,118,255],[155,110,255],[162,102,255],[0,204,204],[7,195,208],[13,186,211],[20,177,215],[26,168,218],[32,160,221],[39,151,225],[45,142,228],[52,133,232],[58,124,235],[64,116,238],[71,107,242],[77,98,245],[84,89,249],[90,80,252],[96,72,255],[240,240,240],[224,233,233],[208,226,226],[192,220,220],[176,213,213],[160,206,206],[144,200,200],[128,193,193],[112,186,186],[96,180,180],[80,173,173],[64,166,166],[48,160,160],[32,153,153],[16,146,146],[0,140,140],[255,255,255],[242,242,255],[230,230,255],[218,218,255],[206,206,255],[194,194,255],[181,181,255],[169,169,255],[157,157,255],[145,145,255],[133,133,255],[120,120,255],[108,108,255],[96,96,255],[84,84,255],[72,72,255],[243,142,255],[231,136,255],[219,130,255],[208,124,255],[196,118,255],[185,112,255],[173,106,255],[161,100,255],[150,94,255],[138,88,255],[127,82,255],[115,76,255],[103,70,255],[92,64,255],[80,58,255],[69,53,255],[255,216,255],[255,194,255],[255,172,255],[255,150,255],[255,128,255],[255,96,255],[255,64,255],[255,0,255],[224,0,224],[192,0,192],[160,0,160],[128,0,128],[96,0,96],[64,0,64],[48,0,48],[32,0,32],[216,216,255],[196,196,247],[176,176,240],[157,157,232],[137,137,225],[117,117,217],[98,98,210],[78,78,202],[58,58,195],[39,39,187],[19,19,180],[0,0,173],[0,0,145],[0,0,118],[0,0,91],[0,0,64],[255,43,255],[238,40,246],[221,38,238],[204,36,229],[187,34,221],[170,32,212],[153,30,204],[136,28,195],[119,25,187],[102,23,178],[85,21,170],[68,19,161],[51,17,153],[34,15,144],[17,13,136],[0,11,128],[0,0,0],[5,5,17],[9,9,34],[13,13,51],[18,18,68],[22,22,85],[26,26,102],[30,30,119],[35,35,136],[39,39,153],[43,43,170],[47,47,187],[52,52,204],[56,56,221],[60,60,238],[64,64,255],[0,255,255],[0,240,240],[0,225,225],[0,210,210],[0,195,195],[0,180,180],[0,165,165],[0,150,150],[0,136,136],[0,121,121],[0,106,106],[0,91,91],[0,76,76],[0,61,61],[0,46,46],[0,32,32],[255,160,255],[238,157,246],[221,155,238],[204,153,229],[187,151,221],[170,149,212],[153,147,204],[136,145,195],[119,142,187],[102,140,178],[85,138,170],[68,136,161],[51,134,153],[34,132,144],[17,130,136],[0,128,128],[0,0,0],[16,9,17],[31,18,34],[46,27,51],[61,36,68],[76,45,85],[91,54,102],[106,63,119],[122,72,136],[137,81,153],[152,90,170],[167,99,187],[182,108,204],[197,117,221],[212,126,238],[227,134,255],[255,192,255],[242,172,255],[229,153,255],[217,134,255],[204,115,255],[192,96,255],[176,48,255],[160,0,255],[128,0,232],[96,0,208],[80,0,192],[64,0,128],[48,0,96],[40,0,80],[32,0,64],[16,0,48],[166,0,255],[178,0,223],[189,0,191],[200,0,159],[211,0,127],[222,0,95],[233,0,63],[244,0,31],[255,0,0],[218,0,10],[182,0,19],[145,0,28],[109,0,37],[72,0,46],[36,0,55],[0,0,64],[227,227,255],[211,211,240],[196,196,225],[181,181,210],[166,166,195],[151,151,180],[136,136,165],[121,121,150],[105,105,136],[90,90,121],[75,75,106],[60,60,91],[45,45,76],[30,30,61],[15,15,46],[255,255,255]]
13 | }, {
14 | "name": "DOOM",
15 | "palette":[[0,0,0],[31,23,11],[23,15,7],[75,75,75],[255,255,255],[27,27,27],[19,19,19],[11,11,11],[7,7,7],[47,55,31],[35,43,15],[23,31,7],[15,23,0],[79,59,43],[71,51,35],[63,43,27],[255,183,183],[247,171,171],[243,163,163],[235,151,151],[231,143,143],[223,135,135],[219,123,123],[211,115,115],[203,107,107],[199,99,99],[191,91,91],[187,87,87],[179,79,79],[175,71,71],[167,63,63],[163,59,59],[155,51,51],[151,47,47],[143,43,43],[139,35,35],[131,31,31],[127,27,27],[119,23,23],[115,19,19],[107,15,15],[103,11,11],[95,7,7],[91,7,7],[83,7,7],[79,0,0],[71,0,0],[67,0,0],[255,235,223],[255,227,211],[255,219,199],[255,211,187],[255,207,179],[255,199,167],[255,191,155],[255,187,147],[255,179,131],[247,171,123],[239,163,115],[231,155,107],[223,147,99],[215,139,91],[207,131,83],[203,127,79],[191,123,75],[179,115,71],[171,111,67],[163,107,63],[155,99,59],[143,95,55],[135,87,51],[127,83,47],[119,79,43],[107,71,39],[95,67,35],[83,63,31],[75,55,27],[63,47,23],[51,43,19],[43,35,15],[239,239,239],[231,231,231],[223,223,223],[219,219,219],[211,211,211],[203,203,203],[199,199,199],[191,191,191],[183,183,183],[179,179,179],[171,171,171],[167,167,167],[159,159,159],[151,151,151],[147,147,147],[139,139,139],[131,131,131],[127,127,127],[119,119,119],[111,111,111],[107,107,107],[99,99,99],[91,91,91],[87,87,87],[79,79,79],[71,71,71],[67,67,67],[59,59,59],[55,55,55],[47,47,47],[39,39,39],[35,35,35],[119,255,111],[111,239,103],[103,223,95],[95,207,87],[91,191,79],[83,175,71],[75,159,63],[67,147,55],[63,131,47],[55,115,43],[47,99,35],[39,83,27],[31,67,23],[23,51,15],[19,35,11],[11,23,7],[191,167,143],[183,159,135],[175,151,127],[167,143,119],[159,135,111],[155,127,107],[147,123,99],[139,115,91],[131,107,87],[123,99,79],[119,95,75],[111,87,67],[103,83,63],[95,75,55],[87,67,51],[83,63,47],[159,131,99],[143,119,83],[131,107,75],[119,95,63],[103,83,51],[91,71,43],[79,59,35],[67,51,27],[123,127,99],[111,115,87],[103,107,79],[91,99,71],[83,87,59],[71,79,51],[63,71,43],[55,63,39],[255,255,115],[235,219,87],[215,187,67],[195,155,47],[175,123,31],[155,91,19],[135,67,7],[115,43,0],[255,255,255],[255,219,219],[255,187,187],[255,155,155],[255,123,123],[255,95,95],[255,63,63],[255,31,31],[255,0,0],[239,0,0],[227,0,0],[215,0,0],[203,0,0],[191,0,0],[179,0,0],[167,0,0],[155,0,0],[139,0,0],[127,0,0],[115,0,0],[103,0,0],[91,0,0],[79,0,0],[67,0,0],[231,231,255],[199,199,255],[171,171,255],[143,143,255],[115,115,255],[83,83,255],[55,55,255],[27,27,255],[0,0,255],[0,0,227],[0,0,203],[0,0,179],[0,0,155],[0,0,131],[0,0,107],[0,0,83],[255,255,255],[255,235,219],[255,215,187],[255,199,155],[255,179,123],[255,163,91],[255,143,59],[255,127,27],[243,115,23],[235,111,15],[223,103,15],[215,95,11],[203,87,7],[195,79,0],[183,71,0],[175,67,0],[255,255,255],[255,255,215],[255,255,179],[255,255,143],[255,255,107],[255,255,71],[255,255,35],[255,255,0],[167,63,0],[159,55,0],[147,47,0],[135,35,0],[79,59,39],[67,47,27],[55,35,19],[47,27,11],[0,0,83],[0,0,71],[0,0,59],[0,0,47],[0,0,35],[0,0,23],[0,0,11],[0,0,0],[255,159,67],[255,231,75],[255,123,255],[255,0,255],[207,0,207],[159,0,155],[111,0,107],[255,255,255]]
16 | }, {
17 | "name": "Riso Blue, Yellow, FluoroPink (Preview)",
18 | "palette": [[0,75,181],[0,70,182],[7,64,179],[13,59,173],[30,54,171],[47,40,150],[255,68,14],[255,124,0],[255,154,0],[255,182,0],[255,209,0],[223,205,0],[136,162,0],[82,131,22],[42,100,26],[0,63,31],[42,120,200],[58,119,204],[59,100,196],[68,92,192],[84,82,186],[95,51,163],[255,65,51],[255,127,49],[255,156,40],[255,183,40],[255,216,15],[204,204,36],[131,165,53],[77,132,56],[33,99,60],[0,65,63],[87,146,210],[98,141,211],[102,126,206],[108,114,199],[120,98,190],[143,61,169],[255,66,79],[255,130,84],[255,158,84],[255,187,82],[255,218,78],[195,207,92],[121,165,94],[75,133,95],[29,107,89],[0,66,87],[128,172,214],[140,165,217],[146,146,213],[152,132,208],[169,119,199],[188,66,179],[255,69,126],[255,135,113],[255,159,124],[255,190,118],[252,215,127],[185,203,122],[114,165,125],[73,137,124],[17,105,117],[0,63,106],[185,200,219],[194,191,220],[208,172,214],[220,155,213],[237,131,203],[255,63,177],[255,66,142],[255,137,154],[255,160,158],[255,187,166],[244,212,171],[184,203,173],[116,167,173],[61,136,168],[14,106,160],[0,63,139],[255,65,170],[0,63,156],[49,112,175],[89,136,178],[135,159,182],[203,186,179],[216,187,124],[147,158,125],[96,130,119],[56,102,123],[0,63,117],[0,64,94],[39,100,90],[76,121,87],[121,141,78],[186,173,65],[255,128,194],[16,61,152],[65,100,166],[101,124,174],[152,149,175],[218,169,176],[225,169,123],[158,142,125],[104,116,120],[63,95,122],[15,57,114],[9,61,92],[57,93,89],[100,114,88],[134,131,82],[198,151,68],[255,162,209],[27,53,148],[76,93,169],[115,113,170],[165,133,176],[229,144,168],[232,142,115],[165,124,120],[118,105,120],[73,86,121],[24,52,111],[24,54,86],[69,87,92],[105,101,86],[144,115,80],[215,135,72],[253,189,212],[37,49,141],[86,77,158],[122,97,167],[172,114,172],[247,124,166],[245,112,115],[178,100,115],[131,87,115],[80,71,115],[37,46,106],[34,48,84],[73,73,87],[115,90,88],[153,98,84],[220,113,73],[235,211,211],[54,35,127],[99,51,150],[138,61,156],[186,74,165],[255,71,154],[255,62,102],[193,60,107],[143,55,104],[100,51,107],[50,36,96],[46,40,80],[82,61,86],[126,63,84],[165,67,78],[230,65,70],[255,221,0],[0,75,181],[0,75,181],[0,75,181],[0,75,181],[0,75,181],[255,53,23],[193,51,26],[139,49,31],[96,48,35],[52,40,40],[53,40,63],[87,51,61],[123,62,55],[167,62,53],[231,66,44],[254,226,31],[0,75,181],[0,75,181],[0,75,181],[0,75,181],[0,75,181],[243,113,0],[184,91,17],[133,81,25],[89,70,33],[38,50,40],[35,50,66],[77,74,62],[111,85,57],[156,93,53],[224,112,44],[248,229,91],[0,75,181],[0,75,181],[0,75,181],[0,75,181],[0,75,181],[239,135,0],[169,116,7],[119,98,20],[77,79,31],[31,55,39],[26,56,63],[64,81,61],[103,100,57],[141,108,46],[209,132,36],[246,231,124],[0,75,181],[0,75,181],[0,75,181],[0,75,181],[0,75,181],[229,158,0],[159,130,0],[114,108,18],[67,87,28],[23,57,38],[18,57,64],[55,87,62],[91,107,55],[132,124,47],[199,150,30],[232,228,181],[0,75,181],[0,75,181],[0,75,181],[0,75,181],[0,75,181],[212,179,0],[148,146,0],[101,121,9],[56,96,27],[7,60,39],[0,63,63],[45,93,61],[83,119,55],[119,136,45],[189,168,25],[0,75,181],[0,75,181],[0,75,181],[0,75,181],[0,75,181],[0,75,181],[0,75,181],[0,75,181],[0,75,181],[0,75,181],[0,75,181],[0,75,181],[0,75,181],[0,75,181],[0,75,181],[255,255,255]]
19 | }, {
20 | "name": "Riso Blue, Yellow, FluoroPink (Blue Plate)",
21 | "palette": [[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[198,198,198],[145,145,145],[94,94,94],[48,48,48],[0,0,0],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[198,198,198],[145,145,145],[94,94,94],[48,48,48],[0,0,0],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[198,198,198],[145,145,145],[94,94,94],[48,48,48],[0,0,0],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[198,198,198],[145,145,145],[94,94,94],[48,48,48],[0,0,0],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[198,198,198],[145,145,145],[94,94,94],[48,48,48],[0,0,0],[255,255,255],[0,0,0],[48,48,48],[94,94,94],[145,145,145],[198,198,198],[198,198,198],[145,145,145],[94,94,94],[48,48,48],[0,0,0],[0,0,0],[48,48,48],[94,94,94],[145,145,145],[198,198,198],[255,255,255],[0,0,0],[48,48,48],[94,94,94],[145,145,145],[198,198,198],[198,198,198],[145,145,145],[94,94,94],[48,48,48],[0,0,0],[0,0,0],[48,48,48],[94,94,94],[145,145,145],[198,198,198],[255,255,255],[0,0,0],[48,48,48],[94,94,94],[145,145,145],[198,198,198],[198,198,198],[145,145,145],[94,94,94],[48,48,48],[0,0,0],[0,0,0],[48,48,48],[94,94,94],[145,145,145],[198,198,198],[255,255,255],[0,0,0],[48,48,48],[94,94,94],[145,145,145],[198,198,198],[198,198,198],[145,145,145],[94,94,94],[48,48,48],[0,0,0],[0,0,0],[48,48,48],[94,94,94],[145,145,145],[198,198,198],[255,255,255],[0,0,0],[48,48,48],[94,94,94],[145,145,145],[198,198,198],[198,198,198],[145,145,145],[94,94,94],[48,48,48],[0,0,0],[0,0,0],[48,48,48],[94,94,94],[145,145,145],[198,198,198],[255,255,255],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[198,198,198],[145,145,145],[94,94,94],[48,48,48],[0,0,0],[0,0,0],[48,48,48],[94,94,94],[145,145,145],[198,198,198],[255,255,255],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[198,198,198],[145,145,145],[94,94,94],[48,48,48],[0,0,0],[0,0,0],[48,48,48],[94,94,94],[145,145,145],[198,198,198],[255,255,255],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[198,198,198],[145,145,145],[94,94,94],[48,48,48],[0,0,0],[0,0,0],[48,48,48],[94,94,94],[145,145,145],[198,198,198],[255,255,255],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[198,198,198],[145,145,145],[94,94,94],[48,48,48],[0,0,0],[0,0,0],[48,48,48],[94,94,94],[145,145,145],[198,198,198],[255,255,255],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[198,198,198],[145,145,145],[94,94,94],[48,48,48],[0,0,0],[0,0,0],[48,48,48],[94,94,94],[145,145,145],[198,198,198],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[255,255,255]]
22 | }, {
23 | "name": "Riso Blue, Yellow, FluoroPink (FluoroPink Plate)",
24 | "palette": [[255,255,255],[198,198,198],[145,145,145],[94,94,94],[48,48,48],[0,0,0],[0,0,0],[48,48,48],[94,94,94],[145,145,145],[198,198,198],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[198,198,198],[145,145,145],[94,94,94],[48,48,48],[0,0,0],[0,0,0],[48,48,48],[94,94,94],[145,145,145],[198,198,198],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[198,198,198],[145,145,145],[94,94,94],[48,48,48],[0,0,0],[0,0,0],[48,48,48],[94,94,94],[145,145,145],[198,198,198],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[198,198,198],[145,145,145],[94,94,94],[48,48,48],[0,0,0],[0,0,0],[48,48,48],[94,94,94],[145,145,145],[198,198,198],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[198,198,198],[145,145,145],[94,94,94],[48,48,48],[0,0,0],[0,0,0],[48,48,48],[94,94,94],[145,145,145],[198,198,198],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[0,0,0],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[48,48,48],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[145,145,145],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[198,198,198],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255]]
25 | }, {
26 | "name": "Riso Blue, Yellow, FluoroPink (Yellow Plate)",
27 | "palette": [[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[255,255,255],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[255,255,255],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[255,255,255],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[255,255,255],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[255,255,255],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[198,198,198],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[145,145,145],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[94,94,94],[0,0,0],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[94,94,94],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[145,145,145],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[198,198,198],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[48,48,48],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255]]
28 | }, {
29 | "name": "Riso FluoroPink & Teal (Preview)",
30 | "palette": [[0,131,138],[0,44,83],[12,46,86],[22,48,89],[34,50,93],[48,52,98],[64,55,103],[82,59,108],[100,62,114],[121,66,120],[137,69,125],[157,72,131],[176,76,137],[194,79,143],[209,82,148],[222,84,152],[13,137,144],[0,48,86],[12,50,89],[22,52,92],[34,54,96],[48,57,101],[64,61,106],[82,64,112],[101,68,118],[122,72,124],[139,75,129],[158,79,136],[178,83,142],[196,87,148],[211,90,152],[224,92,157],[25,143,149],[0,52,88],[12,54,92],[22,57,95],[34,59,99],[48,62,104],[65,66,109],[83,70,115],[101,74,121],[122,78,128],[139,82,134],[159,86,140],[179,90,146],[197,94,153],[212,97,157],[225,100,162],[38,149,155],[0,57,91],[12,59,95],[23,62,98],[34,64,102],[49,68,107],[65,72,113],[83,76,119],[102,80,125],[123,85,132],[140,89,138],[160,94,144],[179,98,151],[198,103,157],[213,106,162],[225,109,167],[54,157,163],[0,62,95],[12,65,99],[23,68,102],[35,71,106],[49,74,112],[66,79,117],[84,84,124],[103,88,130],[124,93,137],[141,98,143],[161,103,150],[181,108,157],[199,113,164],[215,117,169],[227,120,174],[72,166,171],[0,68,98],[12,71,103],[23,75,106],[35,78,111],[50,82,116],[66,87,122],[84,92,128],[104,97,136],[125,103,143],[142,108,149],[162,113,156],[183,119,163],[201,124,171],[217,128,176],[229,132,181],[92,176,180],[0,75,103],[12,78,107],[23,82,111],[35,85,115],[50,90,121],[67,95,127],[86,101,134],[105,106,142],[126,113,149],[144,119,156],[165,124,163],[185,131,171],[204,136,178],[219,141,183],[232,145,189],[113,186,190],[0,82,107],[12,86,112],[23,90,116],[36,93,120],[51,99,127],[67,104,133],[86,110,140],[106,117,148],[127,124,155],[145,130,162],[166,136,170],[187,143,178],[205,149,186],[221,154,191],[234,159,196],[136,197,200],[0,90,112],[12,94,117],[24,98,121],[36,102,126],[51,108,132],[68,114,139],[87,121,146],[107,128,154],[129,135,162],[147,142,170],[168,149,178],[189,156,186],[208,163,194],[224,169,200],[237,174,205],[155,207,209],[0,97,116],[12,101,121],[24,105,126],[36,110,131],[52,116,137],[69,122,144],[88,130,152],[108,137,160],[130,145,169],[148,153,176],[169,160,185],[190,168,193],[210,175,202],[226,181,207],[239,187,213],[177,217,219],[0,104,121],[13,109,126],[24,114,131],[37,119,136],[52,125,143],[69,132,150],[89,140,158],[109,148,167],[131,157,176],[150,165,184],[171,173,192],[192,182,201],[211,189,210],[228,196,216],[241,201,222],[199,228,229],[0,111,126],[13,117,131],[24,122,136],[37,127,141],[53,134,148],[70,141,156],[90,150,164],[110,158,173],[133,168,182],[151,176,190],[173,185,199],[194,194,208],[214,203,217],[230,209,224],[244,215,230],[219,238,239],[0,119,130],[13,124,136],[25,130,141],[37,135,146],[53,142,154],[71,150,162],[91,159,170],[111,168,180],[134,178,189],[153,188,198],[174,197,207],[196,207,216],[216,216,226],[232,223,232],[246,229,239],[236,246,246],[0,124,134],[13,130,139],[25,136,144],[38,141,150],[54,149,158],[71,158,166],[91,167,174],[112,177,184],[135,187,194],[154,196,202],[176,206,212],[197,216,222],[217,226,232],[234,233,238],[248,240,245],[250,253,253],[0,129,137],[13,135,143],[25,141,148],[38,147,154],[54,155,162],[72,164,170],[92,174,179],[113,184,189],[135,195,198],[154,205,207],[176,214,217],[198,225,227],[218,235,237],[235,243,244],[249,250,251],[226,85,153],[228,93,158],[229,101,163],[230,110,168],[232,121,175],[234,133,182],[237,146,190],[239,160,198],[242,175,207],[244,188,215],[246,203,224],[249,217,232],[251,231,241],[253,242,247],[254,252,253],[255,255,255]]
31 | }, {
32 | "name": "Riso FluoroPink & Teal (Pink plate)",
33 | "palette": [[255,255,255],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[255,255,255],[21,21,21],[21,21,21],[21,21,21],[21,21,21],[21,21,21],[21,21,21],[21,21,21],[21,21,21],[21,21,21],[21,21,21],[21,21,21],[21,21,21],[21,21,21],[21,21,21],[21,21,21],[255,255,255],[36,36,36],[36,36,36],[36,36,36],[36,36,36],[36,36,36],[36,36,36],[36,36,36],[36,36,36],[36,36,36],[36,36,36],[36,36,36],[36,36,36],[36,36,36],[36,36,36],[36,36,36],[255,255,255],[50,50,50],[50,50,50],[50,50,50],[50,50,50],[50,50,50],[50,50,50],[50,50,50],[50,50,50],[50,50,50],[50,50,50],[50,50,50],[50,50,50],[50,50,50],[50,50,50],[50,50,50],[255,255,255],[66,66,66],[66,66,66],[66,66,66],[66,66,66],[66,66,66],[66,66,66],[66,66,66],[66,66,66],[66,66,66],[66,66,66],[66,66,66],[66,66,66],[66,66,66],[66,66,66],[66,66,66],[255,255,255],[82,82,82],[82,82,82],[82,82,82],[82,82,82],[82,82,82],[82,82,82],[82,82,82],[82,82,82],[82,82,82],[82,82,82],[82,82,82],[82,82,82],[82,82,82],[82,82,82],[82,82,82],[255,255,255],[99,99,99],[99,99,99],[99,99,99],[99,99,99],[99,99,99],[99,99,99],[99,99,99],[99,99,99],[99,99,99],[99,99,99],[99,99,99],[99,99,99],[99,99,99],[99,99,99],[99,99,99],[255,255,255],[116,116,116],[116,116,116],[116,116,116],[116,116,116],[116,116,116],[116,116,116],[116,116,116],[116,116,116],[116,116,116],[116,116,116],[116,116,116],[116,116,116],[116,116,116],[116,116,116],[116,116,116],[255,255,255],[134,134,134],[134,134,134],[134,134,134],[134,134,134],[134,134,134],[134,134,134],[134,134,134],[134,134,134],[134,134,134],[134,134,134],[134,134,134],[134,134,134],[134,134,134],[134,134,134],[134,134,134],[255,255,255],[150,150,150],[150,150,150],[150,150,150],[150,150,150],[150,150,150],[150,150,150],[150,150,150],[150,150,150],[150,150,150],[150,150,150],[150,150,150],[150,150,150],[150,150,150],[150,150,150],[150,150,150],[255,255,255],[168,168,168],[168,168,168],[168,168,168],[168,168,168],[168,168,168],[168,168,168],[168,168,168],[168,168,168],[168,168,168],[168,168,168],[168,168,168],[168,168,168],[168,168,168],[168,168,168],[168,168,168],[255,255,255],[187,187,187],[187,187,187],[187,187,187],[187,187,187],[187,187,187],[187,187,187],[187,187,187],[187,187,187],[187,187,187],[187,187,187],[187,187,187],[187,187,187],[187,187,187],[187,187,187],[187,187,187],[255,255,255],[207,207,207],[207,207,207],[207,207,207],[207,207,207],[207,207,207],[207,207,207],[207,207,207],[207,207,207],[207,207,207],[207,207,207],[207,207,207],[207,207,207],[207,207,207],[207,207,207],[207,207,207],[255,255,255],[226,226,226],[226,226,226],[226,226,226],[226,226,226],[226,226,226],[226,226,226],[226,226,226],[226,226,226],[226,226,226],[226,226,226],[226,226,226],[226,226,226],[226,226,226],[226,226,226],[226,226,226],[255,255,255],[246,246,246],[246,246,246],[246,246,246],[246,246,246],[246,246,246],[246,246,246],[246,246,246],[246,246,246],[246,246,246],[246,246,246],[246,246,246],[246,246,246],[246,246,246],[246,246,246],[246,246,246],[0,0,0],[21,21,21],[36,36,36],[50,50,50],[66,66,66],[82,82,82],[99,99,99],[116,116,116],[134,134,134],[150,150,150],[168,168,168],[187,187,187],[207,207,207],[226,226,226],[246,246,246],[255,255,255]]
34 | }, {
35 | "name": "Riso FluoroPink & Teal (Teal Plate)",
36 | "palette": [[0,0,0],[0,0,0],[21,21,21],[36,36,36],[50,50,50],[66,66,66],[82,82,82],[99,99,99],[116,116,116],[134,134,134],[150,150,150],[168,168,168],[187,187,187],[207,207,207],[226,226,226],[246,246,246],[21,21,21],[0,0,0],[21,21,21],[36,36,36],[50,50,50],[66,66,66],[82,82,82],[99,99,99],[116,116,116],[134,134,134],[150,150,150],[168,168,168],[187,187,187],[207,207,207],[226,226,226],[246,246,246],[36,36,36],[0,0,0],[21,21,21],[36,36,36],[50,50,50],[66,66,66],[82,82,82],[99,99,99],[116,116,116],[134,134,134],[150,150,150],[168,168,168],[187,187,187],[207,207,207],[226,226,226],[246,246,246],[50,50,50],[0,0,0],[21,21,21],[36,36,36],[50,50,50],[66,66,66],[82,82,82],[99,99,99],[116,116,116],[134,134,134],[150,150,150],[168,168,168],[187,187,187],[207,207,207],[226,226,226],[246,246,246],[66,66,66],[0,0,0],[21,21,21],[36,36,36],[50,50,50],[66,66,66],[82,82,82],[99,99,99],[116,116,116],[134,134,134],[150,150,150],[168,168,168],[187,187,187],[207,207,207],[226,226,226],[246,246,246],[82,82,82],[0,0,0],[21,21,21],[36,36,36],[50,50,50],[66,66,66],[82,82,82],[99,99,99],[116,116,116],[134,134,134],[150,150,150],[168,168,168],[187,187,187],[207,207,207],[226,226,226],[246,246,246],[99,99,99],[0,0,0],[21,21,21],[36,36,36],[50,50,50],[66,66,66],[82,82,82],[99,99,99],[116,116,116],[134,134,134],[150,150,150],[168,168,168],[187,187,187],[207,207,207],[226,226,226],[246,246,246],[116,116,116],[0,0,0],[21,21,21],[36,36,36],[50,50,50],[66,66,66],[82,82,82],[99,99,99],[116,116,116],[134,134,134],[150,150,150],[168,168,168],[187,187,187],[207,207,207],[226,226,226],[246,246,246],[134,134,134],[0,0,0],[21,21,21],[36,36,36],[50,50,50],[66,66,66],[82,82,82],[99,99,99],[116,116,116],[134,134,134],[150,150,150],[168,168,168],[187,187,187],[207,207,207],[226,226,226],[246,246,246],[150,150,150],[0,0,0],[21,21,21],[36,36,36],[50,50,50],[66,66,66],[82,82,82],[99,99,99],[116,116,116],[134,134,134],[150,150,150],[168,168,168],[187,187,187],[207,207,207],[226,226,226],[246,246,246],[168,168,168],[0,0,0],[21,21,21],[36,36,36],[50,50,50],[66,66,66],[82,82,82],[99,99,99],[116,116,116],[134,134,134],[150,150,150],[168,168,168],[187,187,187],[207,207,207],[226,226,226],[246,246,246],[187,187,187],[0,0,0],[21,21,21],[36,36,36],[50,50,50],[66,66,66],[82,82,82],[99,99,99],[116,116,116],[134,134,134],[150,150,150],[168,168,168],[187,187,187],[207,207,207],[226,226,226],[246,246,246],[207,207,207],[0,0,0],[21,21,21],[36,36,36],[50,50,50],[66,66,66],[82,82,82],[99,99,99],[116,116,116],[134,134,134],[150,150,150],[168,168,168],[187,187,187],[207,207,207],[226,226,226],[246,246,246],[226,226,226],[0,0,0],[21,21,21],[36,36,36],[50,50,50],[66,66,66],[82,82,82],[99,99,99],[116,116,116],[134,134,134],[150,150,150],[168,168,168],[187,187,187],[207,207,207],[226,226,226],[246,246,246],[246,246,246],[0,0,0],[21,21,21],[36,36,36],[50,50,50],[66,66,66],[82,82,82],[99,99,99],[116,116,116],[134,134,134],[150,150,150],[168,168,168],[187,187,187],[207,207,207],[226,226,226],[246,246,246],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255]]
37 | }, {
38 | "name": "Liero Level Palette",
39 | "palette": [[255,0,128],[100,150,200],[150,100,200],[200,100,150],[200,150,100],[150,200,100],[100,200,150],[50,100,150],[100,50,150],[150,50,100],[150,100,50],[255,128,64],[128,128,255],[255,255,255],[255,255,255],[255,255,255],[244,244,252],[248,248,188],[216,220,136],[188,176,104],[160,132,72],[236,216,160],[196,168,124],[156,120,88],[108,76,44],[172,120,72],[124,84,48],[172,120,72],[124,84,48],[140,96,56],[156,108,64],[120,72,52],[132,92,40],[136,124,0],[149,136,0],[124,112,0],[116,100,0],[172,96,28],[160,88,24],[152,84,20],[144,80,16],[120,64,8],[136,72,12],[128,68,8],[165,0,0],[189,0,0],[217,0,0],[255,255,255],[76,76,76],[85,84,84],[92,92,92],[100,100,100],[109,108,108],[116,116,116],[125,124,124],[132,132,132],[140,140,140],[148,148,148],[156,157,156],[255,255,255],[163,0,0],[187,0,0],[215,0,0],[255,255,255],[237,216,160],[197,168,124],[157,120,88],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[96,48,0],[84,40,0],[92,44,0],[89,40,0],[255,255,255],[72,36,0],[60,28,0],[68,32,0],[64,28,0],[255,255,255],[108,80,0],[108,56,0],[164,0,0],[188,0,0],[216,0,0],[255,255,255],[252,200,200],[244,164,164],[248,92,92],[244,76,76],[244,60,60],[245,76,76],[244,92,92],[245,164,164],[253,252,252],[221,220,220],[189,188,188],[157,156,156],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[81,80,192],[104,105,248],[137,136,244],[255,255,255],[80,81,192],[104,104,249],[136,137,244],[255,255,255],[60,60,144],[80,80,192],[104,104,248],[136,136,244],[180,180,244],[255,255,255],[105,104,248],[181,180,244],[44,133,44],[60,172,61],[104,189,104],[255,255,255],[44,132,45],[61,173,60],[104,188,105],[255,255,255],[32,100,32],[45,132,44],[61,172,60],[104,188,104],[164,212,164],[255,255,255],[60,173,60],[165,212,164],[0,0,0],[72,72,72],[84,84,84],[108,108,108],[124,124,124],[144,144,144],[156,156,156],[168,168,168],[180,180,180],[188,188,188],[196,196,196],[216,216,216],[220,220,220],[252,252,252],[244,188,188],[244,124,124],[248,60,60],[252,84,84],[172,0,0],[200,0,0],[252,0,0],[248,24,4],[252,36,0],[248,52,8],[248,80,16],[252,72,0],[248,108,20],[152,60,0],[252,108,0],[88,40,0],[248,136,24],[160,80,0],[168,84,0],[168,84,0],[200,100,0],[164,148,128],[100,56,0],[180,100,0],[252,144,0],[248,164,32],[112,76,0],[208,140,0],[252,180,0],[248,192,36],[236,180,0],[124,96,0],[136,116,0],[252,216,0],[40,36,8],[248,220,40],[148,136,0],[80,76,20],[160,152,40],[200,192,48],[244,232,60],[120,116,28],[240,240,212],[252,252,244],[240,240,180],[244,244,148],[244,244,112],[244,244,80],[252,252,0],[148,176,0],[116,144,0],[88,112,0],[60,80,0],[168,240,0],[84,232,0],[40,112,40],[60,172,60],[52,152,52],[44,132,44],[84,216,84],[0,144,0],[0,224,0],[84,252,252],[104,104,136],[144,144,192],[240,240,248],[220,220,244],[208,208,244],[200,200,244],[188,188,248],[168,168,248],[84,84,252],[72,68,228],[88,60,204],[108,52,180],[124,44,156],[144,40,136],[160,32,112],[196,20,68],[216,12,44],[232,4,20],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255]]
40 | }]
41 |
42 |
--------------------------------------------------------------------------------