diff --git a/library/tutorials/Icons_ Symbols_ and Emojis/0.json b/library/tutorials/Icons_ Symbols_ and Emojis/0.json
new file mode 100644
index 0000000000..81bc4103b4
--- /dev/null
+++ b/library/tutorials/Icons_ Symbols_ and Emojis/0.json
@@ -0,0 +1,436 @@
+{
+ "_meta": {
+ "version": 17,
+ "info": {
+ "name": "Icons, Symbols, and Emojis",
+ "image": "/assets/1923406359_3510",
+ "rules": "",
+ "bgg": "",
+ "year": "",
+ "mode": "Tutorial",
+ "time": "0",
+ "attribution": "",
+ "lastUpdate": 1737418482866,
+ "showName": false,
+ "skill": "",
+ "description": "",
+ "similarImage": "",
+ "similarName": "",
+ "similarDesigner": "",
+ "similarAwards": "",
+ "ruleText": "",
+ "helpText": "",
+ "variantImage": "",
+ "variant": "CSS",
+ "language": "en-US",
+ "players": "1"
+ }
+ },
+ "header": {
+ "id": "header",
+ "x": 300,
+ "y": -2,
+ "height": 60,
+ "z": 74,
+ "movable": false,
+ "movableInEdit": false,
+ "css": "font-size: 60px;text-align:center",
+ "text": "Icons, Symbols, and Emojis: CSS",
+ "width": 1000
+ },
+ "mainText": {
+ "id": "mainText",
+ "x": 100,
+ "y": 100,
+ "width": 1405,
+ "height": 150,
+ "layer": -3,
+ "z": 124,
+ "css": "font-size: 25px; ",
+ "movable": false,
+ "html": "The items below are expressed in VTT as either a `text` property or an `image` property. See the Fonts and Symbols wiki page for additional information about which items can be text, which images, and which can be either. In each group, the top left item has limited css applied. The top right item uses a varierty of different drop-shadow techniques. The lower left image demonstrates borderRadius (a special VTT property) and box-shadow. The bottom right image is clickable and uses a transition to show the difference between filter attributes (from left to right): blur, brightness, contrast, saturation."
+ },
+ "button1Text": {
+ "id": "button1Text",
+ "x": 60,
+ "y": 587,
+ "width": 300,
+ "z": 185,
+ "movable": false,
+ "text": "The paint buckets are from game-icons.net and are expressed in the image property. Open the JSON Editor and select one. Put the cursor on the image property and a button appears at the top of the row of buttons allowing you to choose another image.\n\nThe top right paint bucket has this `filter` css: `drop-shadow(0 0 5px gold)`. The first value is the horizontal offset in pixels. It can be negative. The second value is the vertical offset in pixels and it can also be negative. The third value is the amount of blur (in pixels) for the shadow. The last value is the shadow color. "
+ },
+ "button2Text": {
+ "id": "button2Text",
+ "x": 410,
+ "y": 587,
+ "width": 300,
+ "z": 121,
+ "movable": false,
+ "text": "The buses are part of the material symbols font and are expressed in the text property. To see some font options, put the cursor on the classes property in a widget above. Then put the cursor on the text value and you will get a button to change to one of the many symbols available. Some css appears on all of these widgets for basic formatting: font-size (self-explanatory); display, justify-content, align-items (used to center the image inside the widget); color (self-explanatory).\n\nThe bottom left bus has this `box-shadow` css: `5px 5px 10px 2px #4c556a`. The values are for the horizontal and vertical spread and color."
+ },
+ "button3Text": {
+ "id": "button3Text",
+ "x": 760,
+ "y": 587,
+ "width": 300,
+ "z": 9732,
+ "movable": false,
+ "text": "The pumpkins are part of the (monocolor) emoji font that is expressed through the classes and text properties like the buses. They have the same css as the buses to size, center, and color the pumpkins.\n\nThe bottom left pumpkin combines box-shadow and drop-shadow."
+ },
+ "background": {
+ "id": "background",
+ "width": 1600,
+ "height": 1000,
+ "layer": -4,
+ "z": 94,
+ "movable": false,
+ "movableInEdit": false,
+ "css": {
+ "background-color": "#96a7cf"
+ }
+ },
+ "example2": {
+ "id": "example2",
+ "x": 210,
+ "y": 292,
+ "z": 10098,
+ "css": {
+ "filter": "drop-shadow(0 0 5px gold)"
+ },
+ "image": "/i/game-icons.net/delapouite/paint-bucket.svg",
+ "movable": false
+ },
+ "example1": {
+ "id": "example1",
+ "x": 100,
+ "y": 292,
+ "z": 10097,
+ "image": "/i/game-icons.net/delapouite/paint-bucket.svg",
+ "movable": false
+ },
+ "example3": {
+ "id": "example3",
+ "x": 100,
+ "y": 416,
+ "z": 10100,
+ "css": {
+ "box-shadow": "0 0 10px 2px #4c556a"
+ },
+ "image": "/i/game-icons.net/delapouite/paint-bucket.svg",
+ "movable": false
+ },
+ "example4": {
+ "id": "example4",
+ "x": 210,
+ "y": 416,
+ "z": 10099,
+ "css": {
+ "filter": "blur(${PROPERTY blur}px)",
+ "transition": "linear 0.5s"
+ },
+ "image": "/i/game-icons.net/delapouite/paint-bucket.svg",
+ "movable": false,
+ "clickRoutine": [
+ {
+ "func": "IF",
+ "operand1": "${PROPERTY blur}",
+ "operand2": 5,
+ "thenRoutine": [
+ {
+ "func": "SET",
+ "collection": "thisButton",
+ "property": "blur",
+ "value": 0
+ }
+ ],
+ "elseRoutine": [
+ {
+ "func": "SET",
+ "collection": "thisButton",
+ "property": "blur",
+ "value": 5
+ }
+ ]
+ }
+ ],
+ "blur": 5
+ },
+ "example5": {
+ "id": "example5",
+ "x": 570,
+ "y": 292,
+ "z": 10098,
+ "css": {
+ "font-size": "90px",
+ "display": "flex",
+ "justify-content": "center",
+ "align-items": "center",
+ "color": "#2d5da8",
+ "filter": "drop-shadow(-7px 0 6px #2d5da8bb)"
+ },
+ "movable": false,
+ "classes": "material-symbols",
+ "text": "directions_bus"
+ },
+ "example6": {
+ "id": "example6",
+ "x": 460,
+ "y": 292,
+ "z": 10097,
+ "movable": false,
+ "classes": "material-symbols",
+ "text": "directions_bus",
+ "css": {
+ "font-size": "90px",
+ "display": "flex",
+ "justify-content": "center",
+ "align-items": "center",
+ "color": "#2d5da8"
+ }
+ },
+ "example7": {
+ "id": "example7",
+ "x": 460,
+ "y": 416,
+ "z": 10100,
+ "css": {
+ "font-size": "90px",
+ "display": "flex",
+ "justify-content": "center",
+ "align-items": "center",
+ "color": "#2d5da8",
+ "box-shadow": "5px 5px 10px 2px #4c556a"
+ },
+ "borderRadius": 8,
+ "movable": false,
+ "classes": "material-symbols",
+ "text": "directions_bus"
+ },
+ "example8": {
+ "id": "example8",
+ "x": 570,
+ "y": 416,
+ "z": 10099,
+ "css": {
+ "font-size": "90px",
+ "display": "flex",
+ "justify-content": "center",
+ "align-items": "center",
+ "color": "#2d5da8",
+ "filter": "brightness(${PROPERTY brightness})",
+ "transition": "linear 0.5s"
+ },
+ "movable": false,
+ "clickRoutine": [
+ {
+ "func": "IF",
+ "operand1": "${PROPERTY brightness}",
+ "operand2": 0.5,
+ "thenRoutine": [
+ {
+ "func": "SET",
+ "collection": "thisButton",
+ "property": "brightness",
+ "value": 1.5
+ }
+ ],
+ "elseRoutine": [
+ {
+ "func": "SET",
+ "collection": "thisButton",
+ "property": "brightness",
+ "value": 0.5
+ }
+ ]
+ }
+ ],
+ "classes": "material-symbols",
+ "text": "directions_bus",
+ "brightness": 0.5
+ },
+ "example9": {
+ "id": "example9",
+ "x": 919,
+ "y": 292,
+ "z": 10098,
+ "css": {
+ "font-size": "90px",
+ "display": "flex",
+ "justify-content": "center",
+ "align-items": "center",
+ "color": "#e4651c",
+ "filter": "drop-shadow(2px 2px 2px #000000)"
+ },
+ "movable": false,
+ "text": "🎃",
+ "classes": "emoji-monochrome"
+ },
+ "example10": {
+ "id": "example10",
+ "x": 809,
+ "y": 292,
+ "z": 10097,
+ "movable": false,
+ "classes": "emoji-monochrome",
+ "text": "🎃",
+ "css": {
+ "font-size": "90px",
+ "display": "flex",
+ "justify-content": "center",
+ "align-items": "center",
+ "color": "#e4651c"
+ }
+ },
+ "example11": {
+ "id": "example11",
+ "x": 809,
+ "y": 416,
+ "z": 10100,
+ "css": {
+ "font-size": "90px",
+ "display": "flex",
+ "justify-content": "center",
+ "align-items": "center",
+ "color": "#e4651c",
+ "box-shadow": "3px 3px 3px 9px #606060",
+ "filter": "drop-shadow(10px 5px 9px #0000)"
+ },
+ "borderRadius": 20,
+ "movable": false,
+ "text": "🎃",
+ "classes": "emoji-monochrome"
+ },
+ "example12": {
+ "id": "example12",
+ "x": 919,
+ "y": 416,
+ "z": 10099,
+ "css": {
+ "font-size": "90px",
+ "display": "flex",
+ "justify-content": "center",
+ "align-items": "center",
+ "color": "#e4651c",
+ "filter": "contrast(${PROPERTY contrast})",
+ "transition": "linear 0.5s"
+ },
+ "movable": false,
+ "clickRoutine": [
+ {
+ "func": "IF",
+ "operand1": "${PROPERTY contrast}",
+ "operand2": 0.5,
+ "thenRoutine": [
+ {
+ "func": "SET",
+ "collection": "thisButton",
+ "property": "contrast",
+ "value": 2
+ }
+ ],
+ "elseRoutine": [
+ {
+ "func": "SET",
+ "collection": "thisButton",
+ "property": "contrast",
+ "value": 0.5
+ }
+ ]
+ }
+ ],
+ "classes": "emoji-monochrome",
+ "text": "🎃",
+ "contrast": 0.5
+ },
+ "button4Text": {
+ "id": "button4Text",
+ "x": 1110,
+ "y": 587,
+ "width": 300,
+ "z": 9732,
+ "movable": false,
+ "text": "The octopuses are part of the colored emoji font that is expressed through the image property. Recoloring images like the octopuses and paint buckets requires either using `svgReplaces` or css filter properties, both of which are demonstrated in the other variants of this tutorial."
+ },
+ "example13": {
+ "id": "example13",
+ "x": 1269,
+ "y": 292,
+ "z": 10098,
+ "css": {
+ "font-size": "90px",
+ "display": "flex",
+ "justify-content": "center",
+ "align-items": "center",
+ "color": "#e4651c",
+ "filter": "drop-shadow(0 0 20px #ffffff)"
+ },
+ "movable": false,
+ "image": "/i/noto-emoji/emoji_u1f419.svg"
+ },
+ "example14": {
+ "id": "example14",
+ "x": 1159,
+ "y": 292,
+ "z": 10097,
+ "movable": false,
+ "image": "/i/noto-emoji/emoji_u1f419.svg"
+ },
+ "example15": {
+ "id": "example15",
+ "x": 1159,
+ "y": 416,
+ "z": 10100,
+ "css": {
+ "font-size": "90px",
+ "display": "flex",
+ "justify-content": "center",
+ "align-items": "center",
+ "color": "#e4651c",
+ "box-shadow": "3px 3px 7px 7px #4c556a"
+ },
+ "borderRadius": 100,
+ "movable": false,
+ "image": "/i/noto-emoji/emoji_u1f419.svg"
+ },
+ "example16": {
+ "id": "example16",
+ "x": 1269,
+ "y": 416,
+ "z": 10099,
+ "css": {
+ "font-size": "90px",
+ "display": "flex",
+ "justify-content": "center",
+ "align-items": "center",
+ "color": "#e4651c",
+ "filter": "saturate(${PROPERTY saturate})",
+ "transition": "linear 0.5s"
+ },
+ "movable": false,
+ "clickRoutine": [
+ {
+ "func": "IF",
+ "operand1": "${PROPERTY saturate}",
+ "operand2": 0.5,
+ "thenRoutine": [
+ {
+ "func": "SET",
+ "collection": "thisButton",
+ "property": "saturate",
+ "value": 2
+ }
+ ],
+ "elseRoutine": [
+ {
+ "func": "SET",
+ "collection": "thisButton",
+ "property": "saturate",
+ "value": 0.5
+ }
+ ]
+ }
+ ],
+ "image": "/i/noto-emoji/emoji_u1f419.svg",
+ "saturate": 0.5
+ }
+}
\ No newline at end of file
diff --git a/library/tutorials/Icons_ Symbols_ and Emojis/1.json b/library/tutorials/Icons_ Symbols_ and Emojis/1.json
new file mode 100644
index 0000000000..9a5dc06a0c
--- /dev/null
+++ b/library/tutorials/Icons_ Symbols_ and Emojis/1.json
@@ -0,0 +1,1723 @@
+{
+ "_meta": {
+ "version": 17,
+ "info": {
+ "name": "Icons, Symbols, and Emojis",
+ "image": "/assets/1923406359_3510",
+ "rules": "",
+ "bgg": "",
+ "year": "",
+ "mode": "Tutorial",
+ "time": "0",
+ "attribution": "",
+ "lastUpdate": 1737418482870,
+ "showName": false,
+ "skill": "",
+ "description": "",
+ "similarImage": "",
+ "similarName": "",
+ "similarDesigner": "",
+ "similarAwards": "",
+ "ruleText": "",
+ "helpText": "",
+ "variantImage": "",
+ "variant": "CSS Demo",
+ "language": "en-US",
+ "players": "1"
+ }
+ },
+ "header": {
+ "id": "header",
+ "x": 200,
+ "y": -2,
+ "height": 60,
+ "z": 74,
+ "movable": false,
+ "movableInEdit": false,
+ "css": "font-size: 60px;text-align:center",
+ "text": "Icons, Symbols, and Emojis: CSS Demo",
+ "width": 1200
+ },
+ "mainText": {
+ "id": "mainText",
+ "x": 100,
+ "y": 100,
+ "width": 1405,
+ "height": 150,
+ "layer": -3,
+ "z": 124,
+ "css": "font-size: 25px; ",
+ "movable": false,
+ "html": "In this tutorial, you can see the effects of selected css changes on icons, symbols, and emojis. Choose the css you want to manipulate using the black and white rectangle in the bottom right. Then adjust sliders to see the kinds of effects you can create. When combining different color-changing effects (such as sepia and grayscale) the order in which the css properties are listed influences the appearance; that is not simulated here. To reset a specific value to its default, click on the slider button. To reset all the defaults for that property, click on an icon."
+ },
+ "background": {
+ "id": "background",
+ "width": 1600,
+ "height": 1000,
+ "layer": -4,
+ "z": 94,
+ "movable": false,
+ "movableInEdit": false,
+ "css": {
+ "background-color": "#96a7cf"
+ }
+ },
+ "demo1": {
+ "id": "demo1",
+ "x": 53,
+ "y": 271,
+ "width": 200,
+ "height": 200,
+ "z": 10097,
+ "movable": false,
+ "css": {
+ "font-size": "190px",
+ "display": "flex",
+ "justify-content": "center",
+ "align-items": "center",
+ "box-shadow": "${PROPERTY box-shadowX}px ${PROPERTY box-shadowY}px ${PROPERTY box-shadowBlur}px ${PROPERTY box-shadowSpread}px ${PROPERTY box-shadowColor}",
+ "color": "${PROPERTY color}",
+ "background": "${PROPERTY background}",
+ "filter": "drop-shadow(${PROPERTY filter-drop-shadowX}px ${PROPERTY filter-drop-shadowY}px ${PROPERTY filter-drop-shadowBlur}px ${PROPERTY filter-drop-shadowColor}) brightness(${PROPERTY filter-brightness}) contrast(${PROPERTY filter-contrast}) blur(${PROPERTY filter-blur}px) grayscale(${PROPERTY filter-grayscale}) hue-rotate(${PROPERTY filter-hue-rotate}deg) invert(${PROPERTY filter-invert}) saturate(${PROPERTY filter-saturate}) sepia(${PROPERTY filter-sepia})"
+ },
+ "image": "/i/game-icons.net/delapouite/paint-bucket.svg",
+ "demo": true,
+ "box-shadowColor": "#000000",
+ "clickRoutine": [
+ "var props = ${PROPERTY props OF chooseButton}",
+ "var defaults = ${PROPERTY propsDefault OF chooseButton}",
+ "var single = ${PROPERTY single OF chooseButton}",
+ {
+ "func": "FOREACH",
+ "in": "${props}",
+ "loopRoutine": [
+ {
+ "func": "IF",
+ "condition": "${single}",
+ "thenRoutine": [
+ "var key = ${single}"
+ ]
+ },
+ {
+ "func": "SELECT",
+ "property": "demo",
+ "value": true
+ },
+ {
+ "func": "SET",
+ "property": "${value}",
+ "value": "${defaults.$key}"
+ },
+ "var currentProp = ${defaults.$key}",
+ "var currentPropLC = toLowerCase ${currentProp}",
+ "var colorCheck = ${currentPropLC} includes 'color'",
+ {
+ "func": "IF",
+ "condition": "${colorCheck}",
+ "thenRoutine": [
+ "// Color",
+ {
+ "func": "SET",
+ "collection": [
+ "slideButton0"
+ ],
+ "property": "y",
+ "value": 180
+ },
+ {
+ "func": "FOREACH",
+ "loopRoutine": [
+ {
+ "func": "GET",
+ "property": "defaultColor"
+ },
+ {
+ "func": "SET",
+ "property": "${value}",
+ "value": "${defaultColor}"
+ }
+ ]
+ }
+ ],
+ "elseRoutine": [
+ {
+ "func": "IF",
+ "operand1": "${key}",
+ "operand2": 5,
+ "thenRoutine": [
+ "// Percent values",
+ {
+ "func": "IF",
+ "condition": "${PROPERTY equalsOne OF chooseButton}",
+ "thenRoutine": [
+ {
+ "func": "SET",
+ "collection": [
+ "slideButton${key}"
+ ],
+ "property": "x",
+ "value": 150
+ }
+ ],
+ "elseRoutine": [
+ {
+ "func": "SET",
+ "collection": [
+ "slideButton${key}"
+ ],
+ "property": "x",
+ "value": 100
+ }
+ ]
+ },
+ {
+ "func": "CALL",
+ "widget": "slideButton${key}",
+ "routine": "updatePosRoutine",
+ "arguments": {
+ "newValue": "${currentProp}"
+ }
+ }
+ ],
+ "elseRoutine": [
+ "// Degree values",
+ {
+ "func": "IF",
+ "operand1": "${key}",
+ "operand2": 6,
+ "thenRoutine": [
+ {
+ "func": "SET",
+ "collection": [
+ "slideButton${key}"
+ ],
+ "property": "x",
+ "value": 0
+ },
+ {
+ "func": "CALL",
+ "widget": "slideButton${key}",
+ "routine": "updatePosRoutine",
+ "arguments": {
+ "newValue": "${currentProp}"
+ }
+ }
+ ],
+ "elseRoutine": [
+ "// Number values",
+ {
+ "func": "SET",
+ "collection": [
+ "slideButton${key}"
+ ],
+ "property": "x",
+ "value": 100
+ },
+ {
+ "func": "CALL",
+ "widget": "slideButton${key}",
+ "routine": "updatePosRoutine",
+ "arguments": {
+ "newValue": "${currentProp}"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "func": "SET",
+ "collection": [
+ "slideButton0"
+ ],
+ "property": "x",
+ "value": 45
+ },
+ {
+ "func": "SET",
+ "collection": [
+ "slideButton0"
+ ],
+ "property": "text",
+ "value": "hue"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "filter-contrast": 1,
+ "filter-drop-shadowX": 0,
+ "filter-drop-shadowY": 0,
+ "filter-drop-shadowColor": "",
+ "filter-drop-shadowBlur": 0,
+ "filter-brightness": 1,
+ "box-shadowX": 0,
+ "box-shadowY": 0,
+ "box-shadowBlur": 0,
+ "box-shadowSpread": 0,
+ "filter-blur": 0,
+ "defaultColor": "#000000",
+ "color": "#000000",
+ "background": "",
+ "filter-grayscale": 0,
+ "filter-invert": 0,
+ "filter-sepia": 0,
+ "filter-saturate": 1,
+ "filter-hue-rotate": 0
+ },
+ "demo2": {
+ "id": "demo2",
+ "x": 469,
+ "y": 271,
+ "width": 200,
+ "height": 200,
+ "z": 10098,
+ "movable": false,
+ "classes": "material-symbols",
+ "text": "directions_bus",
+ "demo": true,
+ "movableInEdit": true,
+ "inheritFrom": {
+ "demo1": [
+ "css",
+ "clickRoutine"
+ ]
+ },
+ "activeFace": 0,
+ "box-shadowColor": "#000000",
+ "filter-contrast": 1,
+ "filter-drop-shadowX": 0,
+ "filter-drop-shadowY": 0,
+ "filter-drop-shadowBlur": 0,
+ "filter-drop-shadowColor": "",
+ "filter-brightness": 1,
+ "box-shadowX": 0,
+ "box-shadowY": 0,
+ "box-shadowBlur": 0,
+ "box-shadowSpread": 0,
+ "filter-blur": 0,
+ "defaultColor": "#2d5da8",
+ "color": "#2d5da8",
+ "background": "",
+ "filter-grayscale": 0,
+ "filter-invert": 0,
+ "filter-sepia": 0,
+ "filter-saturate": 1,
+ "filter-hue-rotate": 0
+ },
+ "demo3": {
+ "id": "demo3",
+ "x": 885,
+ "y": 271,
+ "width": 200,
+ "height": 200,
+ "z": 10098,
+ "movable": false,
+ "classes": "emoji-monochrome",
+ "text": "🎃",
+ "demo": true,
+ "box-shadowColor": "#000000",
+ "inheritFrom": {
+ "demo1": [
+ "css",
+ "clickRoutine"
+ ]
+ },
+ "filter-contrast": 1,
+ "filter-drop-shadowX": 0,
+ "filter-drop-shadowY": 0,
+ "filter-drop-shadowBlur": 0,
+ "filter-drop-shadowColor": "",
+ "filter-brightness": 1,
+ "box-shadowX": 0,
+ "box-shadowY": 0,
+ "box-shadowBlur": 0,
+ "box-shadowSpread": 0,
+ "filter-blur": 0,
+ "defaultColor": "#e4651c",
+ "color": "#e4651c",
+ "background": "",
+ "filter-grayscale": 0,
+ "filter-invert": 0,
+ "filter-sepia": 0,
+ "filter-saturate": 1,
+ "filter-hue-rotate": 0
+ },
+ "demo4": {
+ "id": "demo4",
+ "x": 1301,
+ "y": 271,
+ "width": 200,
+ "height": 200,
+ "z": 10097,
+ "movable": false,
+ "image": "/i/noto-emoji/emoji_u1f419.svg",
+ "demo": true,
+ "box-shadowColor": "#000000",
+ "movableInEdit": true,
+ "inheritFrom": {
+ "demo1": [
+ "css",
+ "clickRoutine"
+ ]
+ },
+ "filter-contrast": 1,
+ "filter-drop-shadowX": 0,
+ "filter-drop-shadowY": 0,
+ "filter-drop-shadowBlur": 0,
+ "filter-drop-shadowColor": "",
+ "filter-brightness": 1,
+ "box-shadowX": 0,
+ "box-shadowY": 0,
+ "box-shadowBlur": 0,
+ "box-shadowSpread": 0,
+ "filter-blur": 0,
+ "defaultColor": "#000000",
+ "color": "#000000",
+ "background": "",
+ "filter-grayscale": 0,
+ "filter-invert": 0,
+ "filter-sepia": 0,
+ "filter-saturate": 1,
+ "filter-hue-rotate": 0
+ },
+ "chooseButton": {
+ "type": "button",
+ "id": "chooseButton",
+ "x": 1760,
+ "y": 217,
+ "z": 829,
+ "text": "CSS",
+ "clickRoutine": [
+ {
+ "func": "SELECT",
+ "property": "choose",
+ "value": true,
+ "collection": "allChoose"
+ },
+ {
+ "func": "MOVE",
+ "collection": "allChoose",
+ "to": "chooseHolder"
+ },
+ {
+ "func": "SORT",
+ "collection": "allChoose",
+ "key": "text"
+ },
+ {
+ "func": "INPUT",
+ "fields": [
+ {
+ "type": "title",
+ "text": "Choose CSS Property"
+ },
+ {
+ "type": "subtitle",
+ "text": "You can change elements of one property at a time. Click to choose, then press OK."
+ },
+ {
+ "type": "choose",
+ "source": "allChoose",
+ "max": 1,
+ "variable": "choice",
+ "scale": 1.3
+ }
+ ]
+ },
+ {
+ "func": "SELECT",
+ "property": "slider",
+ "value": true
+ },
+ {
+ "func": "SET",
+ "property": "display",
+ "value": false
+ },
+ {
+ "func": "SELECT",
+ "property": "id",
+ "value": "${choice}"
+ },
+ {
+ "func": "GET",
+ "property": "props"
+ },
+ {
+ "func": "GET",
+ "property": "propsDefault"
+ },
+ {
+ "func": "GET",
+ "property": "single"
+ },
+ {
+ "func": "GET",
+ "property": "propsLabel"
+ },
+ {
+ "func": "GET",
+ "property": "text",
+ "variable": "thisCSS"
+ },
+ {
+ "func": "SET",
+ "collection": "thisButton",
+ "property": "choice",
+ "value": "${thisCSS}"
+ },
+ {
+ "func": "SET",
+ "collection": "thisButton",
+ "property": "propsDefault",
+ "value": "${propsDefault}"
+ },
+ {
+ "func": "SET",
+ "collection": "thisButton",
+ "property": "single",
+ "value": "${single}"
+ },
+ {
+ "func": "SET",
+ "collection": "thisButton",
+ "property": "propsLabel",
+ "value": "${propsLabel}"
+ },
+ "var defaultsArray = []",
+ {
+ "func": "FOREACH",
+ "in": "${props}",
+ "loopRoutine": [
+ {
+ "func": "SELECT",
+ "property": "id",
+ "value": "slideHolder${key}"
+ },
+ {
+ "func": "IF",
+ "operand1": "${value}",
+ "relation": "!=",
+ "operand2": " ",
+ "thenRoutine": [
+ {
+ "func": "SET",
+ "property": "display",
+ "value": true
+ },
+ {
+ "func": "SELECT",
+ "property": "id",
+ "value": "slideButton${key}"
+ },
+ "var currentProp = ${thisCSS} + ${value}",
+ {
+ "func": "SET",
+ "property": "currentProp",
+ "value": "${currentProp}"
+ },
+ "var defaultsArray = push ${currentProp}",
+ "var thisLabel = ${PROPERTY propsLabel}",
+ "var thisLabel = ${thisLabel.$key}",
+ {
+ "func": "SET",
+ "collection": [
+ "slideLabel${key}"
+ ],
+ "property": "text",
+ "value": "${thisLabel}"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "func": "SET",
+ "collection": "thisButton",
+ "property": "props",
+ "value": "${defaultsArray}"
+ },
+ {
+ "func": "CALL",
+ "routine": "updateSliderRoutine"
+ },
+ {
+ "func": "MOVE",
+ "collection": "allChoose",
+ "to": "offHolder"
+ },
+ {
+ "func": "SELECT",
+ "source": "allChoose",
+ "property": "id",
+ "value": "${choice}"
+ },
+ {
+ "func": "MOVE",
+ "to": "chooseHolder"
+ },
+ "var isBright = ${PROPERTY choice} == 'filter-brightness'",
+ "var isContrast = ${PROPERTY choice} == 'filter-contrast'",
+ "var isSaturate = ${PROPERTY choice} == 'filter-saturate'",
+ "var equalsOne = ${isBright} || ${isContrast} || ${isSaturate}",
+ {
+ "func": "IF",
+ "condition": "${equalsOne}",
+ "thenRoutine": [
+ {
+ "func": "SET",
+ "collection": "thisButton",
+ "property": "equalsOne",
+ "value": true
+ }
+ ],
+ "elseRoutine": [
+ {
+ "func": "SET",
+ "collection": "thisButton",
+ "property": "equalsOne",
+ "value": false
+ }
+ ]
+ }
+ ],
+ "props": [
+ "box-shadowColor",
+ "box-shadowX",
+ "box-shadowY",
+ "box-shadowBlur",
+ "box-shadowSpread"
+ ],
+ "updateSliderRoutine": [
+ "var props = ${PROPERTY props}",
+ "var single = ${PROPERTY single}",
+ {
+ "func": "FOREACH",
+ "in": "${props}",
+ "loopRoutine": [
+ {
+ "func": "GET",
+ "collection": [
+ "demo1"
+ ],
+ "property": "${value}",
+ "variable": "newValue"
+ },
+ {
+ "func": "IF",
+ "condition": "${single}",
+ "thenRoutine": [
+ "var key = ${single}"
+ ]
+ },
+ "var currentProp = ${value}",
+ "var currentPropLC = toLowerCase ${currentProp}",
+ "var colorCheck = ${currentPropLC} includes 'color'",
+ {
+ "func": "IF",
+ "condition": "${colorCheck}",
+ "thenRoutine": [
+ "// Color",
+ {
+ "func": "FOREACH",
+ "loopRoutine": [
+ {
+ "func": "SET",
+ "collection": [
+ "slideLabel0"
+ ],
+ "property": "text",
+ "value": "${newValue}"
+ }
+ ]
+ },
+ {
+ "func": "SET",
+ "collection": [
+ "slideButton0"
+ ],
+ "property": "y",
+ "value": 180
+ }
+ ],
+ "elseRoutine": [
+ {
+ "func": "IF",
+ "operand1": "${key}",
+ "operand2": 5,
+ "thenRoutine": [
+ "// Percent values",
+ {
+ "func": "SET",
+ "collection": [
+ "slideButton${key}"
+ ],
+ "property": "text",
+ "value": "${newValue}"
+ },
+ "var newX = (${newValue} + 2) / 0.02",
+ {
+ "func": "SET",
+ "collection": [
+ "slideButton${key}"
+ ],
+ "property": "x",
+ "value": "${newX}"
+ }
+ ],
+ "elseRoutine": [
+ "// Degree values",
+ {
+ "func": "IF",
+ "operand1": "${key}",
+ "operand2": 6,
+ "thenRoutine": [
+ {
+ "func": "SET",
+ "collection": [
+ "slideButton${key}"
+ ],
+ "property": "text",
+ "value": "${newValue}"
+ },
+ "var newX = ${newValue} / 1.8",
+ {
+ "func": "SET",
+ "collection": [
+ "slideButton${key}"
+ ],
+ "property": "x",
+ "value": "${newX}"
+ }
+ ],
+ "elseRoutine": [
+ "// Number values",
+ {
+ "func": "SET",
+ "collection": [
+ "slideButton${key}"
+ ],
+ "property": "text",
+ "value": "${newValue}"
+ },
+ "var newX = (${newValue} + 20) / 0.2",
+ {
+ "func": "SET",
+ "collection": [
+ "slideButton${key}"
+ ],
+ "property": "x",
+ "value": "${newX}"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "equalsOne": false,
+ "choice": "box-shadow",
+ "propsDefault": [
+ "",
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ "propsLabel": [
+ "",
+ "X Offset (px)",
+ "Y Offset (px)",
+ "Blur (px)",
+ "Spread (px)"
+ ]
+ },
+ "chooseHolder": {
+ "type": "holder",
+ "id": "chooseHolder",
+ "x": 1284,
+ "y": 920,
+ "z": 126,
+ "dropTarget": {},
+ "width": 208,
+ "height": 48,
+ "scale": 2,
+ "classes": "transparent"
+ },
+ "slideHolder0": {
+ "type": "button",
+ "id": "slideHolder0",
+ "x": 328,
+ "y": 539,
+ "height": 360,
+ "layer": -2,
+ "z": 39,
+ "css": "border-radius:4px;background-image: linear-gradient(to bottom, hsl(0, 100%, 50%), hsl(47.5, 100%, 50%), hsl(95, 100%, 50%), hsl(142.5, 100%, 50%), hsl(190, 100%, 50%), hsl(237.5, 100%, 50%), hsl(285, 100%, 50%), hsl(332.5, 100%, 50%), hsl(360, 100%, 50%))",
+ "slider": true,
+ "clickRoutine": []
+ },
+ "slideButton0": {
+ "type": "button",
+ "id": "slideButton0",
+ "parent": "slideHolder0",
+ "fixedParent": true,
+ "z": 1372,
+ "movable": true,
+ "css": "border-color:transparent;background-color:transparent;border-radius:0",
+ "dragLimit": {
+ "minX": 45,
+ "maxX": 45,
+ "maxY": 311,
+ "minY": -41
+ },
+ "image": "/assets/1502865726_277",
+ "currentProp": "box-shadowColor",
+ "updateColorRoutine": [
+ {
+ "func": "SELECT",
+ "property": "demo",
+ "value": true
+ },
+ {
+ "func": "SET",
+ "collection": "DEFAULT",
+ "property": "${PROPERTY currentProp}",
+ "value": "${newValue}"
+ },
+ {
+ "func": "SET",
+ "collection": [
+ "slideLabel0"
+ ],
+ "property": "text",
+ "value": "${newValue}"
+ }
+ ],
+ "yChangeRoutine": [
+ "var newValue = ${PROPERTY y} + 41",
+ "var newValue = ${newValue} * 1.01989",
+ "var newValue = ${newValue} toFixed 0",
+ "var newValue = ${newValue} parseFloat",
+ "var newValue = 'hsla(' + ${newValue}",
+ "var newValue = ${newValue} + ','",
+ "var newValue = ${newValue} + '70'",
+ "var newValue = ${newValue} + '\\u0025,'",
+ "var newValue = ${newValue} + '50'",
+ "var newValue = ${newValue} + '\\u0025,'",
+ "var newValue = ${newValue} + '1'",
+ "var newValue = ${newValue} + ')'",
+ "var newValue = ${newValue} colorToHex",
+ {
+ "func": "CALL",
+ "routine": "updateColorRoutine"
+ }
+ ],
+ "slideLabel0": "#123456",
+ "x": 45,
+ "text": "hue",
+ "y": 180
+ },
+ "slideHolder4": {
+ "type": "holder",
+ "id": "slideHolder4",
+ "x": 618,
+ "y": 779,
+ "display": true,
+ "inheritFrom": {
+ "slideHolder1": "*"
+ }
+ },
+ "slideButton4": {
+ "type": "button",
+ "id": "slideButton4",
+ "parent": "slideHolder4",
+ "y": 0,
+ "z": 1335,
+ "display": true,
+ "inheritFrom": {
+ "slideButton1": "*"
+ },
+ "currentProp": "box-shadowSpread",
+ "x": 100,
+ "text": 0
+ },
+ "slideHolder3": {
+ "type": "holder",
+ "id": "slideHolder3",
+ "x": 618,
+ "y": 689,
+ "display": true,
+ "inheritFrom": {
+ "slideHolder1": "*"
+ }
+ },
+ "slideButton3": {
+ "type": "button",
+ "id": "slideButton3",
+ "parent": "slideHolder3",
+ "y": 0,
+ "z": 1336,
+ "display": true,
+ "inheritFrom": {
+ "slideButton1": "*"
+ },
+ "currentProp": "box-shadowBlur",
+ "x": 100,
+ "text": 0
+ },
+ "slideHolder2": {
+ "type": "holder",
+ "id": "slideHolder2",
+ "x": 618,
+ "y": 599,
+ "display": true,
+ "inheritFrom": {
+ "slideHolder1": "*"
+ }
+ },
+ "slideButton2": {
+ "type": "button",
+ "id": "slideButton2",
+ "parent": "slideHolder2",
+ "y": 0,
+ "z": 1341,
+ "display": true,
+ "inheritFrom": {
+ "slideButton1": "*"
+ },
+ "currentProp": "box-shadowY",
+ "x": 100,
+ "text": 0
+ },
+ "slideHolder1": {
+ "type": "holder",
+ "id": "slideHolder1",
+ "x": 618,
+ "y": 509,
+ "width": 280,
+ "height": 80,
+ "borderRadius": 50,
+ "z": 125,
+ "css": {
+ "background": "#ffffff40"
+ },
+ "slider": true
+ },
+ "slideButton1": {
+ "type": "button",
+ "id": "slideButton1",
+ "parent": "slideHolder1",
+ "fixedParent": true,
+ "z": 1340,
+ "movable": true,
+ "dragLimit": {
+ "minX": 0,
+ "maxX": 200,
+ "maxY": 0,
+ "minY": 0
+ },
+ "currentProp": "box-shadowX",
+ "updatePosRoutine": [
+ {
+ "func": "SELECT",
+ "property": "demo",
+ "value": true
+ },
+ {
+ "func": "SET",
+ "collection": "DEFAULT",
+ "property": "${PROPERTY currentProp}",
+ "value": "${newValue}"
+ },
+ {
+ "func": "SET",
+ "collection": "thisButton",
+ "property": "text",
+ "value": "${newValue}"
+ }
+ ],
+ "xChangeRoutine": [
+ {
+ "func": "IF",
+ "operand1": "${PROPERTY dragging}",
+ "operand2": null,
+ "thenRoutine": [],
+ "elseRoutine": [
+ "var newValue = ${PROPERTY x} * 0.2 - 20",
+ "var newValue = ${newValue} toFixed 0",
+ "var newValue = ${newValue} parseFloat",
+ {
+ "func": "CALL",
+ "routine": "updatePosRoutine"
+ }
+ ]
+ }
+ ],
+ "text": 0,
+ "clickRoutine": [
+ {
+ "func": "SET",
+ "collection": "thisButton",
+ "property": "x",
+ "value": 100
+ },
+ {
+ "func": "CALL",
+ "routine": "updatePosRoutine",
+ "arguments": {
+ "newValue": 0
+ }
+ }
+ ],
+ "x": 100
+ },
+ "forceColor1": {
+ "id": "forceColor1",
+ "y": 5,
+ "x": -70,
+ "parent": "slideHolder0",
+ "fixedParent": true,
+ "z": 10107,
+ "width": 40,
+ "height": 40,
+ "css": {
+ "background": "${PROPERTY background}"
+ },
+ "background": "#ffffff",
+ "clickRoutine": [
+ {
+ "func": "CALL",
+ "widget": "slideButton0",
+ "routine": "updateColorRoutine",
+ "arguments": {
+ "newValue": "${PROPERTY background}"
+ }
+ }
+ ],
+ "movable": false
+ },
+ "forceColor2": {
+ "inheritFrom": {
+ "forceColor1": "*"
+ },
+ "id": "forceColor2",
+ "x": -71,
+ "y": 108,
+ "background": "#000000",
+ "z": 10108
+ },
+ "forceColor3": {
+ "inheritFrom": {
+ "forceColor1": "*"
+ },
+ "id": "forceColor3",
+ "x": -70,
+ "y": 210,
+ "background": "#606060"
+ },
+ "forceColor4": {
+ "inheritFrom": {
+ "forceColor1": "*"
+ },
+ "id": "forceColor4",
+ "x": -72,
+ "y": 313,
+ "background": "transparent",
+ "css": {
+ "background": "${PROPERTY background}",
+ "border": "1px solid #000000"
+ }
+ },
+ "choose6": {
+ "id": "choose6",
+ "x": 4,
+ "y": 4,
+ "text": "filter-brightness",
+ "props": [
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ ""
+ ],
+ "propsDefault": [
+ "",
+ "",
+ "",
+ "",
+ "",
+ 1
+ ],
+ "single": 5,
+ "inheritFrom": {
+ "choose1": "!parent"
+ },
+ "z": 12605,
+ "propsLabel": [
+ "",
+ "",
+ "",
+ "",
+ "",
+ "Brightness (%)"
+ ],
+ "parent": "offHolder"
+ },
+ "slideHolder5": {
+ "inheritFrom": {
+ "slideHolder1": "*"
+ },
+ "type": "holder",
+ "id": "slideHolder5",
+ "display": false
+ },
+ "slideButton5": {
+ "inheritFrom": {
+ "slideButton1": "*"
+ },
+ "type": "button",
+ "id": "slideButton5",
+ "parent": "slideHolder5",
+ "z": 1323,
+ "x": 100,
+ "y": 0,
+ "currentProp": "filter-sepia",
+ "xChangeRoutine": [
+ {
+ "func": "IF",
+ "operand1": "${PROPERTY dragging}",
+ "operand2": null,
+ "thenRoutine": [],
+ "elseRoutine": [
+ "var newValue = ${PROPERTY x} * 0.02 - 2",
+ "var newValue = ${newValue} toFixed 1",
+ "var newValue = ${newValue} parseFloat",
+ {
+ "func": "CALL",
+ "routine": "updatePosRoutine"
+ }
+ ]
+ }
+ ],
+ "updatePosRoutine": [
+ {
+ "func": "SELECT",
+ "property": "demo",
+ "value": true
+ },
+ {
+ "func": "SET",
+ "collection": "DEFAULT",
+ "property": "${PROPERTY currentProp}",
+ "value": "${newValue}"
+ },
+ {
+ "func": "SET",
+ "collection": "thisButton",
+ "property": "text",
+ "value": "${newValue}"
+ }
+ ],
+ "clickRoutine": [
+ {
+ "func": "IF",
+ "condition": "${PROPERTY equalsOne OF chooseButton}",
+ "thenRoutine": [
+ {
+ "func": "SET",
+ "collection": "thisButton",
+ "property": "x",
+ "value": 150
+ },
+ {
+ "func": "CALL",
+ "routine": "updatePosRoutine",
+ "arguments": {
+ "newValue": 1
+ }
+ }
+ ],
+ "elseRoutine": [
+ {
+ "func": "SET",
+ "collection": "thisButton",
+ "property": "x",
+ "value": 100
+ },
+ {
+ "func": "CALL",
+ "routine": "updatePosRoutine",
+ "arguments": {
+ "newValue": 0
+ }
+ }
+ ]
+ }
+ ],
+ "text": 0
+ },
+ "choose7": {
+ "id": "choose7",
+ "x": 4,
+ "y": 4,
+ "text": "filter-contrast",
+ "props": [
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ ""
+ ],
+ "propsDefault": [
+ "",
+ "",
+ "",
+ "",
+ "",
+ 1
+ ],
+ "single": 5,
+ "inheritFrom": {
+ "choose1": "!parent"
+ },
+ "z": 12606,
+ "propsLabel": [
+ "",
+ "",
+ "",
+ "",
+ "",
+ "Contrast (%)"
+ ],
+ "parent": "offHolder"
+ },
+ "slideLabel0": {
+ "type": "label",
+ "id": "slideLabel0",
+ "parent": "slideHolder0",
+ "fixedParent": true,
+ "x": -48,
+ "y": -52,
+ "width": 180,
+ "height": 35,
+ "borderRadius": 4,
+ "css": {
+ "color": "black",
+ "font-size": "30px",
+ "border": "1px solid black"
+ },
+ "editable": true,
+ "textChangeRoutine": [
+ {
+ "func": "CALL",
+ "widget": "slideButton0",
+ "routine": "updateColorRoutine",
+ "arguments": {
+ "newValue": "${PROPERTY text}"
+ }
+ }
+ ],
+ "text": "#000000"
+ },
+ "choose8": {
+ "inheritFrom": {
+ "choose1": "!parent"
+ },
+ "id": "choose8",
+ "x": 4,
+ "y": 4,
+ "text": "filter-grayscale",
+ "props": [
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ ""
+ ],
+ "propsDefault": [
+ "",
+ "",
+ "",
+ "",
+ "",
+ 0
+ ],
+ "single": 5,
+ "z": 12608,
+ "propsLabel": [
+ "",
+ "",
+ "",
+ "",
+ "",
+ "Grayscale (%)"
+ ],
+ "parent": "offHolder"
+ },
+ "slideLabel1": {
+ "id": "slideLabel1",
+ "x": 330,
+ "css": {
+ "color": "black",
+ "font-size": "30px"
+ },
+ "width": 500,
+ "height": 35,
+ "movable": false,
+ "parent": "slideHolder1",
+ "y": 20,
+ "fixedParent": true,
+ "text": "X Offset (px)"
+ },
+ "slideLabel2": {
+ "inheritFrom": {
+ "slideLabel1": "*"
+ },
+ "id": "slideLabel2",
+ "x": 330,
+ "y": 20,
+ "parent": "slideHolder2",
+ "text": "Y Offset (px)"
+ },
+ "slideLabel3": {
+ "inheritFrom": {
+ "slideLabel1": "*"
+ },
+ "id": "slideLabel3",
+ "x": 330,
+ "y": 20,
+ "parent": "slideHolder3",
+ "text": "Blur (px)"
+ },
+ "slideLabel4": {
+ "inheritFrom": {
+ "slideLabel1": "*"
+ },
+ "id": "slideLabel4",
+ "x": 330,
+ "y": 20,
+ "parent": "slideHolder4",
+ "text": "Spread (px)",
+ "activeFace": 0
+ },
+ "slideLabel5": {
+ "inheritFrom": {
+ "slideLabel1": "*"
+ },
+ "id": "slideLabel5",
+ "x": 330,
+ "y": 20,
+ "parent": "slideHolder5",
+ "text": "Sepia (%)"
+ },
+ "choose10": {
+ "inheritFrom": {
+ "choose1": "!parent"
+ },
+ "id": "choose10",
+ "x": 4,
+ "y": 4,
+ "z": 12611,
+ "text": "filter-saturate",
+ "props": [
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ ""
+ ],
+ "propsDefault": [
+ "",
+ "",
+ "",
+ "",
+ "",
+ 1
+ ],
+ "propsLabel": [
+ "",
+ "",
+ "",
+ "",
+ "",
+ "Saturate (%)"
+ ],
+ "single": 5,
+ "parent": "offHolder"
+ },
+ "choose2": {
+ "id": "choose2",
+ "x": 4,
+ "y": 4,
+ "text": "color",
+ "props": [
+ ""
+ ],
+ "propsDefault": [
+ "color"
+ ],
+ "inheritFrom": {
+ "choose1": "!parent"
+ },
+ "z": 12603,
+ "parent": "offHolder"
+ },
+ "choose4": {
+ "id": "choose4",
+ "x": 4,
+ "y": 4,
+ "text": "filter-drop-shadow",
+ "props": [
+ "Color",
+ "X",
+ "Y",
+ "Blur"
+ ],
+ "propsDefault": [
+ "",
+ 0,
+ 0,
+ 0
+ ],
+ "inheritFrom": {
+ "choose1": "!parent"
+ },
+ "z": 12607,
+ "propsLabel": [
+ "",
+ "X Offset (px)",
+ "Y Offset (px)",
+ "Blur (px)"
+ ],
+ "parent": "offHolder"
+ },
+ "choose5": {
+ "id": "choose5",
+ "x": 4,
+ "y": 4,
+ "text": "filter-blur",
+ "props": [
+ " ",
+ ""
+ ],
+ "propsDefault": [
+ "",
+ 0
+ ],
+ "single": 1,
+ "inheritFrom": {
+ "choose1": "!parent"
+ },
+ "z": 12604,
+ "propsLabel": [
+ "",
+ "",
+ "",
+ "",
+ "",
+ "Blur (px)"
+ ],
+ "parent": "offHolder"
+ },
+ "choose9": {
+ "inheritFrom": {
+ "choose1": "!parent"
+ },
+ "id": "choose9",
+ "x": 4,
+ "y": 4,
+ "z": 12610,
+ "text": "filter-invert",
+ "props": [
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ ""
+ ],
+ "propsDefault": [
+ "",
+ "",
+ "",
+ "",
+ "",
+ 0
+ ],
+ "propsLabel": [
+ "",
+ "",
+ "",
+ "",
+ "",
+ "Invert (%)"
+ ],
+ "single": 5,
+ "parent": "offHolder"
+ },
+ "offHolder": {
+ "type": "holder",
+ "id": "offHolder",
+ "x": 1738,
+ "y": 354,
+ "z": 135
+ },
+ "choose11": {
+ "inheritFrom": {
+ "choose1": "!parent"
+ },
+ "id": "choose11",
+ "x": 4,
+ "y": 4,
+ "z": 12612,
+ "text": "filter-sepia",
+ "props": [
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ ""
+ ],
+ "propsDefault": [
+ "",
+ "",
+ "",
+ "",
+ "",
+ 0
+ ],
+ "propsLabel": [
+ "",
+ "",
+ "",
+ "",
+ "",
+ "Sepia (%)"
+ ],
+ "single": 5,
+ "parent": "offHolder"
+ },
+ "choose3": {
+ "id": "choose3",
+ "x": 4,
+ "y": 4,
+ "props": [
+ ""
+ ],
+ "text": "background",
+ "propsDefault": [
+ ""
+ ],
+ "inheritFrom": {
+ "choose1": "!parent"
+ },
+ "z": 12601,
+ "parent": "offHolder"
+ },
+ "choose1": {
+ "id": "choose1",
+ "y": 4,
+ "text": "box-shadow",
+ "css": {
+ "display": "flex",
+ "justify-content": "center",
+ "align-items": "center",
+ "background": "black",
+ "color": "white"
+ },
+ "width": 200,
+ "height": 40,
+ "borderRadius": 10,
+ "z": 12613,
+ "props": [
+ "Color",
+ "X",
+ "Y",
+ "Blur",
+ "Spread"
+ ],
+ "propsDefault": [
+ "",
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ "clickRoutine": [
+ {
+ "func": "CLICK",
+ "collection": [
+ "chooseButton"
+ ]
+ }
+ ],
+ "choose": true,
+ "propsLabel": [
+ "",
+ "X Offset (px)",
+ "Y Offset (px)",
+ "Blur (px)",
+ "Spread (px)"
+ ],
+ "x": 4,
+ "parent": "chooseHolder"
+ },
+ "r865": {
+ "id": "r865",
+ "y": 114,
+ "x": -302,
+ "parent": "slideHolder0",
+ "fixedParent": true,
+ "css": {
+ "color": "black",
+ "text-align": "left"
+ },
+ "width": 200,
+ "text": "Use the hue slider to approximate a color. To use an exact hex color, enter it into the box above the slider. You can also click the squares for white, black, gray, and transparent.",
+ "z": 12038,
+ "movable": false
+ },
+ "changeIconLabel": {
+ "id": "changeIconLabel",
+ "x": 1257,
+ "y": 505,
+ "text": "To change to a different icon, open one in the JSON Editor. Place the cursor either over the text or image property and click the blue and white button that appears in the upper right corner to 'pick an asset'.",
+ "width": 300,
+ "movable": false
+ },
+ "choose12": {
+ "inheritFrom": {
+ "choose1": "!parent"
+ },
+ "id": "choose12",
+ "x": 4,
+ "y": 4,
+ "z": 12609,
+ "text": "filter-hue-rotate",
+ "props": [
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ ""
+ ],
+ "propsDefault": [
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ 0
+ ],
+ "propsLabel": [
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "Hue-Rotate (deg)"
+ ],
+ "single": 6,
+ "parent": "offHolder"
+ },
+ "slideHolder6": {
+ "inheritFrom": {
+ "slideHolder1": "*"
+ },
+ "type": "holder",
+ "id": "slideHolder6",
+ "display": false
+ },
+ "slideButton6": {
+ "inheritFrom": {
+ "slideButton1": "*"
+ },
+ "type": "button",
+ "id": "slideButton6",
+ "parent": "slideHolder6",
+ "z": 1374,
+ "text": 0,
+ "y": 0,
+ "dragLimit": {
+ "minX": 0,
+ "maxX": 200,
+ "maxY": 0,
+ "minY": 0
+ },
+ "currentProp": "filter-hue-rotate",
+ "clickRoutine": [
+ {
+ "func": "SET",
+ "collection": "thisButton",
+ "property": "x",
+ "value": 0
+ },
+ {
+ "func": "CALL",
+ "routine": "updatePosRoutine",
+ "arguments": {
+ "newValue": 0
+ }
+ }
+ ],
+ "updatePosRoutine": [
+ {
+ "func": "SELECT",
+ "property": "demo",
+ "value": true
+ },
+ {
+ "func": "SET",
+ "collection": "DEFAULT",
+ "property": "${PROPERTY currentProp}",
+ "value": "${newValue}"
+ },
+ {
+ "func": "SET",
+ "collection": "thisButton",
+ "property": "text",
+ "value": "${newValue}"
+ }
+ ],
+ "xChangeRoutine": [
+ {
+ "func": "IF",
+ "operand1": "${PROPERTY dragging}",
+ "operand2": null,
+ "thenRoutine": [],
+ "elseRoutine": [
+ "var newValue = ${PROPERTY x} * 1.8",
+ "var newValue = ${newValue} toFixed 0",
+ "var newValue = ${newValue} parseFloat",
+ {
+ "func": "CALL",
+ "routine": "updatePosRoutine"
+ }
+ ]
+ }
+ ],
+ "x": 0
+ },
+ "slideLabel6": {
+ "inheritFrom": {
+ "slideLabel5": "*"
+ },
+ "id": "slideLabel6",
+ "parent": "slideHolder6",
+ "text": "Hue-Rotate (deg)"
+ }
+}
\ No newline at end of file
diff --git a/library/tutorials/Icons_ Symbols_ and Emojis/2.json b/library/tutorials/Icons_ Symbols_ and Emojis/2.json
new file mode 100644
index 0000000000..1831b86886
--- /dev/null
+++ b/library/tutorials/Icons_ Symbols_ and Emojis/2.json
@@ -0,0 +1,217 @@
+{
+ "_meta": {
+ "version": 17,
+ "info": {
+ "name": "Icons, Symbols, and Emojis",
+ "image": "/assets/1923406359_3510",
+ "rules": "",
+ "bgg": "",
+ "year": "",
+ "mode": "Tutorial",
+ "time": "0",
+ "attribution": "",
+ "lastUpdate": 1737418482872,
+ "showName": false,
+ "skill": "",
+ "description": "",
+ "similarImage": "",
+ "similarName": "",
+ "similarDesigner": "",
+ "similarAwards": "",
+ "ruleText": "",
+ "helpText": "",
+ "variantImage": "",
+ "variant": "svgReplaces",
+ "language": "en-US",
+ "players": "1"
+ }
+ },
+ "header": {
+ "id": "header",
+ "x": 200,
+ "y": -2,
+ "height": 60,
+ "z": 74,
+ "movable": false,
+ "movableInEdit": false,
+ "css": "font-size: 60px;text-align:center",
+ "text": "Icons, Symbols, and Emojis: svgReplaces",
+ "width": 1200
+ },
+ "mainText": {
+ "id": "mainText",
+ "x": 100,
+ "y": 100,
+ "width": 1405,
+ "height": 150,
+ "layer": -3,
+ "z": 124,
+ "css": "font-size: 25px; ",
+ "movable": false,
+ "html": "The icons in VTT represented through images (not text) are SVG files. SVGs are described with text-like code and can be adjusted dynamically through the VTT `svgReplaces` property. For more background about SVGs see this website. In a typical case, you are simply replacing a color with another color, but the property can be used in more powerful ways. These same techniques work on any SVG images and not just the ones available by default on VTT."
+ },
+ "button1Text": {
+ "id": "button1Text",
+ "x": 60,
+ "y": 587,
+ "width": 300,
+ "z": 185,
+ "movable": false,
+ "text": "The boat on the left is from the game-icons.net collection. They all have the default fill color as #000, so that is what you replace. Look at the boat in the JSON Editor. The `svgReplaces` property is saying take any instances where `#000` appears in the SVG and change it to whatever is set in the property `newColor`. You can name the property whatever you want. Then in that property, identify the color that should replace the black #000. \n\nThe meeple on the right is part of a custom set of VTT icons. They use `currentColor` (which defaults to black) and so that is what needs to be replaced."
+ },
+ "button2Text": {
+ "id": "button2Text",
+ "x": 410,
+ "y": 587,
+ "width": 300,
+ "z": 121,
+ "movable": false,
+ "html": "Many SVGs have more than one color. The emoji above on the left has 4. You can see the colors by opening the svg in a text editor. To do that, first download the svg by going to https://virtualtabletop.io/i/noto-emoji/emoji_u23ef.svg and save the file to your computer. Then open it in a text editor. You will see the available colors are #F77E00, #FF9800, #FFBD52, and #FAFAFA.\n\nThe emoji on the right has `svgReplaces` for the three orangish colors. Note that the replacement is case sensitive, so #f77e00 would not work."
+ },
+ "button3Text": {
+ "id": "button3Text",
+ "x": 760,
+ "y": 587,
+ "width": 300,
+ "z": 9732,
+ "movable": false,
+ "text": "The rainbows above are just another example of color replacement in an emoji with multiple colors.."
+ },
+ "background": {
+ "id": "background",
+ "width": 1600,
+ "height": 1000,
+ "layer": -4,
+ "z": 94,
+ "movable": false,
+ "movableInEdit": false,
+ "css": {
+ "background-color": "#96a7cf"
+ }
+ },
+ "example1": {
+ "id": "example1",
+ "x": 100,
+ "y": 288,
+ "z": 10097,
+ "image": "/i/game-icons.net/delapouite/fishing-boat.svg",
+ "movable": false,
+ "svgReplaces": {
+ "#000": "newColor"
+ },
+ "newColor": "gold"
+ },
+ "button4Text": {
+ "id": "button4Text",
+ "x": 1110,
+ "y": 587,
+ "width": 300,
+ "z": 9732,
+ "movable": false,
+ "text": "These examples take a simple SVG that has a fill but no stroke, and adds the stroke for a different effect. This technique will work on many SVGs. But you really should understand the structure of the SVG you intend to modify before trying something like this.\n\nThe example on the top uses a simple color svgReplaces to modify the color. Then on the bottom images, in the case of the bricks, the stroke (the area around each brick) is set to a thick, dark red stroke that is slightly opaque. The fire is similar with a thick, gold stroke added around the orange fire."
+ },
+ "example2": {
+ "id": "example2",
+ "x": 213,
+ "y": 288,
+ "z": 10097,
+ "image": "i/icons/meeple_3d.svg",
+ "movable": false,
+ "svgReplaces": {
+ "currentColor": "canBeAnything"
+ },
+ "canBeAnything": "red"
+ },
+ "example3": {
+ "id": "example3",
+ "x": 432,
+ "y": 288,
+ "z": 10097,
+ "image": "/i/noto-emoji/emoji_u23ef.svg",
+ "movable": false
+ },
+ "example4": {
+ "id": "example4",
+ "x": 563,
+ "y": 288,
+ "z": 10097,
+ "image": "/i/noto-emoji/emoji_u23ef.svg",
+ "movable": false,
+ "svgReplaces": {
+ "#FF9800": "mainColor",
+ "#FFBD52": "glintColor",
+ "#F77E00": "highlightColor"
+ },
+ "mainColor": "#5624d6",
+ "glintColor": "#b29aee",
+ "highlightColor": "#31147a"
+ },
+ "example6": {
+ "id": "example6",
+ "x": 924,
+ "y": 288,
+ "movable": false,
+ "image": "/i/noto-emoji/emoji_u1f308.svg",
+ "svgReplaces": {
+ "#8177FA": "color1",
+ "#00C0E9": "color2",
+ "#97CC37": "color3",
+ "#F9D81E": "color4",
+ "#FF8E00": "color5",
+ "#FF5117": "color6"
+ },
+ "color1": "indigo",
+ "color2": "blue",
+ "color3": "green",
+ "color4": "yellow",
+ "color5": "orange",
+ "color6": "red"
+ },
+ "example5": {
+ "id": "example5",
+ "x": 788,
+ "y": 288,
+ "movable": false,
+ "image": "/i/noto-emoji/emoji_u1f308.svg"
+ },
+ "example8": {
+ "id": "example8",
+ "x": 1117,
+ "y": 425,
+ "image": "/i/game-icons.net/delapouite/brick-wall.svg",
+ "svgReplaces": {
+ "#000": "customCSS"
+ },
+ "customCSS": "red\" stroke-width=\"15\" stroke-opacity=\"0.8\" stroke=\"darkred"
+ },
+ "example7": {
+ "id": "example7",
+ "x": 1117,
+ "y": 288,
+ "image": "/i/game-icons.net/delapouite/brick-wall.svg",
+ "svgReplaces": {
+ "#000": "brickColor"
+ },
+ "brickColor": "red"
+ },
+ "example9": {
+ "id": "example9",
+ "x": 1299,
+ "y": 425,
+ "image": "/i/game-icons.net/carl-olsen/flame.svg",
+ "svgReplaces": {
+ "#000": "customCSS"
+ },
+ "customCSS": "orange\" stroke-width=\"25\" stroke=\"gold"
+ },
+ "example10": {
+ "id": "example10",
+ "x": 1299,
+ "y": 288,
+ "image": "/i/game-icons.net/carl-olsen/flame.svg",
+ "svgReplaces": {
+ "#000": "newColor"
+ },
+ "newColor": "orange"
+ }
+}
\ No newline at end of file
diff --git a/library/tutorials/Icons_ Symbols_ and Emojis/assets/1502865726_277 b/library/tutorials/Icons_ Symbols_ and Emojis/assets/1502865726_277
new file mode 100644
index 0000000000..5c090514c4
--- /dev/null
+++ b/library/tutorials/Icons_ Symbols_ and Emojis/assets/1502865726_277
@@ -0,0 +1,6 @@
+
diff --git a/library/tutorials/Icons_ Symbols_ and Emojis/assets/1923406359_3510 b/library/tutorials/Icons_ Symbols_ and Emojis/assets/1923406359_3510
new file mode 100644
index 0000000000..ce0f6d9df3
--- /dev/null
+++ b/library/tutorials/Icons_ Symbols_ and Emojis/assets/1923406359_3510
@@ -0,0 +1,24 @@
+
\ No newline at end of file