made a page to generate crafting trees (TODO: docs + testing)
This commit is contained in:
@@ -5,7 +5,8 @@ const PAGES = {
|
||||
TOYS: 2,
|
||||
LICENSE: 3,
|
||||
LOADING: 4,
|
||||
LIBS: 5
|
||||
LIBS: 5,
|
||||
CRAFTING: 6
|
||||
}
|
||||
const CONSOLE_COLORS = {
|
||||
red: "color: #FF0000;",
|
||||
@@ -189,6 +190,7 @@ document.addEventListener("DOMContentLoaded", async function () {
|
||||
case (PAGES.LICENSE): loadingScreenStars(); await loadingScreenLicense(); break
|
||||
case (PAGES.TOYS): loadingScreenStars(); break
|
||||
case (PAGES.LIBS): loadingScreenStars(); break
|
||||
case (PAGES.CRAFTING): loadingScreenCrafting(); break
|
||||
}
|
||||
|
||||
if (navBarPresent) {
|
||||
|
||||
@@ -64,6 +64,9 @@ canvas {
|
||||
margin: calc(3px * var(--pxDensity)) calc(3px * var(--pxDensity)) 0% 0%;
|
||||
width: round(auto, var(--pxDensity));
|
||||
/*height: calc(6px * var(--pxDensity));*/
|
||||
border: none;
|
||||
color: #ffffff;
|
||||
font-size: inherit;
|
||||
}
|
||||
.switch {
|
||||
position: relative;
|
||||
@@ -110,3 +113,40 @@ canvas {
|
||||
image-rendering: pixelated;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
button {
|
||||
display: inline-block;
|
||||
background-color: var(--navBarBtn_Inner);
|
||||
box-shadow: calc(1px * var(--pxDensity)) 0px var(--navBarBtn_Border),
|
||||
calc(-1px * var(--pxDensity)) 0px var(--navBarBtn_Border),
|
||||
0px calc(1px * var(--pxDensity)) var(--navBarBtn_Border),
|
||||
0px calc(-1px * var(--pxDensity)) var(--navBarBtn_Border);
|
||||
|
||||
padding: calc(1px * var(--pxDensity));
|
||||
margin: calc(3px * var(--pxDensity)) calc(3px * var(--pxDensity)) 0% 0%;
|
||||
width: round(auto, var(--pxDensity));
|
||||
/*height: calc(6px * var(--pxDensity));*/
|
||||
border: none;
|
||||
color: #ffffff;
|
||||
font-size: inherit;
|
||||
}
|
||||
button:hover {
|
||||
filter: brightness(1.35) drop-shadow(0px calc(1px * var(--pxDensity)) rgba(0, 0, 0, 0.5));
|
||||
cursor: pointer;
|
||||
}
|
||||
button:active {
|
||||
filter: brightness(0.75);
|
||||
transform: translateY(calc(1px * var(--pxDensity)));
|
||||
}
|
||||
button:disabled, button[disabled] {
|
||||
filter: brightness(0.75) drop-shadow(0px calc(1px * var(--pxDensity)) rgba(0, 0, 0, 0.5));
|
||||
cursor: not-allowed;
|
||||
}
|
||||
button:disabled:hover, button[disabled]:hover {
|
||||
filter: brightness(0.75) drop-shadow(0px calc(1px * var(--pxDensity)) rgba(0, 0, 0, 0.5));
|
||||
cursor: not-allowed;
|
||||
}
|
||||
button:disabled:active, button[disabled]:active {
|
||||
filter: brightness(0.75) drop-shadow(0px calc(1px * var(--pxDensity)) rgba(0, 0, 0, 0.5));
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
}
|
||||
+3
-21
@@ -20,27 +20,9 @@ li {
|
||||
padding: 0%;
|
||||
border: none;
|
||||
filter: drop-shadow(0px calc(1px * var(--pxDensity)) rgba(0, 0, 0, 0.5));
|
||||
}
|
||||
button:hover {
|
||||
filter: brightness(1.35) drop-shadow(0px calc(1px * var(--pxDensity)) rgba(0, 0, 0, 0.5));
|
||||
cursor: pointer;
|
||||
}
|
||||
button:active {
|
||||
filter: brightness(0.75);
|
||||
transform: translateY(calc(1px * var(--pxDensity)));
|
||||
}
|
||||
.button:disabled, button[disabled] {
|
||||
filter: brightness(0.75) drop-shadow(0px calc(1px * var(--pxDensity)) rgba(0, 0, 0, 0.5));
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.button:disabled:hover, button[disabled]:hover {
|
||||
filter: brightness(0.75) drop-shadow(0px calc(1px * var(--pxDensity)) rgba(0, 0, 0, 0.5));
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.button:disabled:active, button[disabled]:active {
|
||||
filter: brightness(0.75) drop-shadow(0px calc(1px * var(--pxDensity)) rgba(0, 0, 0, 0.5));
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
margin: 0%;
|
||||
box-shadow: none;
|
||||
width: auto;
|
||||
}
|
||||
.navBtnImg {
|
||||
width: calc(12px * var(--pxDensity));
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, user-scalable=no">
|
||||
|
||||
<link rel="stylesheet" href="/global/navBar.css">
|
||||
<link rel="stylesheet" href="/global/globalStyle.css">
|
||||
<link rel="stylesheet" href="/global/loadingScreen.css">
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<link rel="stylesheet" href="tree.css">
|
||||
|
||||
<link rel="icon" type="image/png" href="/assets/favicon_32x32.png">
|
||||
<title>Byte Dice - Crafting</title>
|
||||
|
||||
<meta name="robots" content="index, follow">
|
||||
<link rel="canonical" href="https://bytedice.net/toys">
|
||||
|
||||
<meta name="description" content="A crafting-tree-like generation tool">
|
||||
<meta name="keywords" content="Byte Dice, pixel art, procedural generation, game art, digital art, ByteDice showcase">
|
||||
<meta name="author" content="Byte Dice">
|
||||
|
||||
<meta property="og:title" content="Byte Dice">
|
||||
<meta property="og:description" content="A crafting-tree-like generation tool">
|
||||
<meta property="og:url" content="https://bytedice.net/toys/crafting">
|
||||
<meta property="og:type" content="website">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="mainDiv">
|
||||
<img src="/assets/backgrounds/starNoise_512x512.png" draggable="false" id="starNoise">
|
||||
<canvas id="starfallCanvas"></canvas>
|
||||
|
||||
<div id="treeStaticContainer">
|
||||
<div id="treeScaleContainer">
|
||||
<div id="trees"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tomlInputContainer" id="tomlInputContainer">
|
||||
<div class="tomlInputGrid">
|
||||
<label><a href="./docs">Tutorial / Docs</a></label>
|
||||
<textarea id="tomlInput" name="tomlInput"></textarea>
|
||||
<button id="generateButton">Generate Tree</button>
|
||||
</div>
|
||||
<button id="collapseButton"><</button>
|
||||
</div>
|
||||
|
||||
<div id="navBarContainer" data-alt="byte"></div>
|
||||
</div>
|
||||
|
||||
<div id="loadingScreen"></div>
|
||||
|
||||
<!-- global -->
|
||||
<script src="/global/globalScript.js"></script>
|
||||
<script src="/global/pxDensity.js"></script>
|
||||
<script src="/global/loadingScreen.js"></script>
|
||||
<script src="/global/navBar.js"></script>
|
||||
<script src="/global/screenTransition.js"></script>
|
||||
|
||||
<!-- local -->
|
||||
<script src="script.js"></script>
|
||||
<script type="module" src="tree_generator.js"></script>
|
||||
<script src="/stars.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,81 @@
|
||||
CURRENT_PAGE = PAGES.CRAFTING
|
||||
|
||||
let tomlInputContainer = document.getElementById("tomlInputContainer")
|
||||
let collapseButton = document.getElementById("collapseButton")
|
||||
let treeStatic = document.getElementById("treeStaticContainer")
|
||||
let treeScale = document.getElementById("treeScaleContainer")
|
||||
|
||||
|
||||
let mouseX = 0
|
||||
let mouseY = 0
|
||||
let dragX = 0
|
||||
let dragY = 0
|
||||
let dragOffsetX = 0
|
||||
let dragOffsetY = 0
|
||||
let isDragging = false
|
||||
let scale = 1
|
||||
|
||||
|
||||
let isCollapsed = false
|
||||
|
||||
|
||||
document.addEventListener("mousemove", function(event) {
|
||||
mouseX = event.clientX;
|
||||
mouseY = event.clientY;
|
||||
})
|
||||
|
||||
|
||||
function collapseInput() {
|
||||
const COLLAPSE = "collapse 0.5s cubic-bezier(0, 0, 0, 1.46) forwards"
|
||||
tomlInputContainer.style.animation = COLLAPSE
|
||||
isCollapsed = true
|
||||
collapseButton.textContent = ">"
|
||||
}
|
||||
|
||||
|
||||
function unCollapseInput() {
|
||||
const UN_COLLAPSE = "un-collapse 0.5s cubic-bezier(0, 0, 0, 1.46) forwards"
|
||||
tomlInputContainer.style.animation = UN_COLLAPSE
|
||||
isCollapsed = false
|
||||
collapseButton.textContent = "<"
|
||||
}
|
||||
|
||||
|
||||
collapseButton.onclick = function() {
|
||||
if (!isCollapsed) { collapseInput(); }
|
||||
else { unCollapseInput(); }
|
||||
}
|
||||
|
||||
|
||||
function loadingScreenCrafting() {
|
||||
unCollapseInput();
|
||||
}
|
||||
|
||||
|
||||
function drag_trees(mouse_offset) {
|
||||
dragX = (mouseX - dragOffsetX) / scale
|
||||
dragY = (mouseY - dragOffsetY) / scale
|
||||
|
||||
trees.style.transform = `translate(${dragX}px, ${dragY}px)`
|
||||
}
|
||||
function on_start_drag() {
|
||||
dragOffsetX = mouseX - dragX * scale
|
||||
dragOffsetY = mouseY - dragY * scale
|
||||
isDragging = true
|
||||
}
|
||||
function dragLoop() {
|
||||
if (isDragging) { drag_trees() }
|
||||
|
||||
requestAnimationFrame(dragLoop)
|
||||
}
|
||||
|
||||
|
||||
treeStatic.onmousedown = on_start_drag
|
||||
document.addEventListener("mouseup", function() { isDragging = false })
|
||||
treeStatic.addEventListener("wheel", function(event) {
|
||||
scale += (-event.deltaY / 500)
|
||||
scale = Math.max(0.2, scale)
|
||||
treeScale.style.transform = `scale(${scale})`
|
||||
})
|
||||
|
||||
document.addEventListener("DOMContentLoaded", dragLoop)
|
||||
@@ -0,0 +1,84 @@
|
||||
.tomlInputContainer textarea {
|
||||
font-family: "Roboto", sans-serif;
|
||||
background-color: var(--navBarBtn_Inner);
|
||||
box-shadow: calc(1px * var(--pxDensity)) 0px var(--navBarBtn_Border),
|
||||
calc(-1px * var(--pxDensity)) 0px var(--navBarBtn_Border),
|
||||
0px calc(1px * var(--pxDensity)) var(--navBarBtn_Border),
|
||||
0px calc(-1px * var(--pxDensity)) var(--navBarBtn_Border);
|
||||
|
||||
padding: calc(1px * var(--pxDensity));
|
||||
border: none;
|
||||
font-size: min(5vmin, 1.2vmax, 0.9rem);
|
||||
margin: calc(3px * var(--pxDensity)) 0% 0% 0%;
|
||||
box-sizing: border-box;
|
||||
width: calc(60px * var(--pxDensity));
|
||||
/*height: calc(100px * var(--pxDensity));*/
|
||||
height: 65vh;
|
||||
color: inherit;
|
||||
display: inline-block;
|
||||
text-align: left;
|
||||
resize: none
|
||||
}
|
||||
.tomlInputContainer textarea:hover {
|
||||
filter: brightness(1.35);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
.tomlInputContainer label {
|
||||
background-color: var(--navBarBtn_Inner);
|
||||
box-shadow: calc(1px * var(--pxDensity)) 0px var(--navBarBtn_Border),
|
||||
calc(-1px * var(--pxDensity)) 0px var(--navBarBtn_Border),
|
||||
0px calc(1px * var(--pxDensity)) var(--navBarBtn_Border),
|
||||
0px calc(-1px * var(--pxDensity)) var(--navBarBtn_Border);
|
||||
|
||||
padding: calc(1px * var(--pxDensity));
|
||||
box-sizing: border-box;
|
||||
width: round(auto, var(--pxDensity));
|
||||
height: calc(6px * var(--pxDensity));
|
||||
font-weight: 800;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
.tomlInputGrid {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
|
||||
.tomlInputContainer {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
margin: 0% auto 0% auto;
|
||||
width: max-content;
|
||||
max-height: 70vh;
|
||||
padding: calc(2px * var(--pxDensity));
|
||||
max-width: min(600px, 100vw, 100vw);
|
||||
font-size: min(1.5rem, calc(4px * var(--pxDensity)));
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
#generateButton {
|
||||
width: 100%;
|
||||
height: calc(6px * var(--pxDensity));
|
||||
}
|
||||
|
||||
|
||||
#collapseButton {
|
||||
margin: 0% calc(3px * var(--pxDensity));
|
||||
height: calc(6px * var(--pxDensity));
|
||||
width: calc(6px * var(--pxDensity));
|
||||
aspect-ratio: 1 / 1;
|
||||
}
|
||||
|
||||
|
||||
@keyframes collapse {
|
||||
0% { transform: translateX(0%); }
|
||||
100% { transform: translateX(calc(-63px * var(--pxDensity))); }
|
||||
}
|
||||
|
||||
@keyframes un-collapse {
|
||||
0% { transform: translateX(calc(-63px * var(--pxDensity))); }
|
||||
100% { transform: translateX(0%); }
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
#trees {
|
||||
position: absolute;
|
||||
left: 0%;
|
||||
top: 0%;
|
||||
width: max-content;
|
||||
height: max-content;
|
||||
padding: calc(16px * var(--pxDensity)) calc(2px * var(--pxDensity));
|
||||
overflow: visible;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: calc(5px * var(--pxDensity));
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.tree {
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
width: min-content;
|
||||
height: min-content;
|
||||
padding: calc(3px * var(--pxDensity));
|
||||
background-color: rgba(0.1, 0.1, 0.1, 0.1);
|
||||
user-select: none;
|
||||
}
|
||||
.item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
overflow: visible;
|
||||
margin-bottom: calc(3px * var(--pxDensity));
|
||||
user-select: none;
|
||||
}
|
||||
.siblings {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: calc(3px * var(--pxDensity));
|
||||
align-items: flex-end;
|
||||
background-color: rgba(0.1, 0.1, 0.1, 0.1);
|
||||
padding: calc(2px * var(--pxDensity));
|
||||
margin-bottom: calc(3px * var(--pxDensity));
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.item p { /* from .encased */
|
||||
display: inline-block;
|
||||
background-color: var(--navBarBtn_Inner);
|
||||
box-shadow: calc(1px * var(--pxDensity)) 0px var(--navBarBtn_Border),
|
||||
calc(-1px * var(--pxDensity)) 0px var(--navBarBtn_Border),
|
||||
0px calc(1px * var(--pxDensity)) var(--navBarBtn_Border),
|
||||
0px calc(-1px * var(--pxDensity)) var(--navBarBtn_Border);
|
||||
|
||||
padding: calc(1px * var(--pxDensity));
|
||||
width: round(auto, var(--pxDensity));
|
||||
height: calc(3px * var(--pxDensity));
|
||||
border: none;
|
||||
color: #ffffff;
|
||||
font-size: min(5vmin, 1.2vmax, 0.9rem);
|
||||
min-width: calc(12px * var(--pxDensity));
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
user-select: none;
|
||||
}
|
||||
.item .blue {
|
||||
background-color: var(--navBar_Inner);
|
||||
box-shadow: calc(1px * var(--pxDensity)) 0px var(--navBar_Border),
|
||||
calc(-1px * var(--pxDensity)) 0px var(--navBar_Border),
|
||||
0px calc(1px * var(--pxDensity)) var(--navBar_Border),
|
||||
0px calc(-1px * var(--pxDensity)) var(--navBar_Border);
|
||||
}
|
||||
|
||||
|
||||
#treeStaticContainer {
|
||||
position: fixed;
|
||||
top: 0%;
|
||||
left: 0%;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: inline-block;
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
#treeScaleContainer {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
import { parse } from "https://esm.sh/smol-toml"
|
||||
|
||||
let tomlInput = document.getElementById("tomlInput")
|
||||
let genButton = document.getElementById("generateButton")
|
||||
let trees = document.getElementById("trees")
|
||||
|
||||
let recipes = {}
|
||||
let startItems = []
|
||||
let products = []
|
||||
|
||||
|
||||
genButton.onclick = getDataFromInput
|
||||
|
||||
|
||||
function getDataFromInput() {
|
||||
let input = tomlInput.value
|
||||
try {
|
||||
let json = parse(input)
|
||||
|
||||
startItems = json.io.inputs
|
||||
products = json.io.products
|
||||
recipes = json.recipes
|
||||
} catch (e) { alert(e) }
|
||||
|
||||
clearTrees()
|
||||
|
||||
for (let product of products) {
|
||||
console.log("generating: \"" + product + "\"")
|
||||
genTreeForProduct(product)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function genTreeForProduct(product) {
|
||||
let treeData = RecursivelyGetRecipes(product)
|
||||
|
||||
let treeNode = document.createElement("div")
|
||||
treeNode.className = "tree"
|
||||
|
||||
makeTreeHTML(treeData, treeNode, true)
|
||||
|
||||
trees.appendChild(treeNode)
|
||||
}
|
||||
|
||||
|
||||
function RecursivelyGetRecipes(product) {
|
||||
let recipe = recipes[product]
|
||||
|
||||
if (recipe == undefined) {
|
||||
alert("ERROR: Recipe not found for \"" + product + "\"")
|
||||
return [product]
|
||||
}
|
||||
|
||||
let children = []
|
||||
|
||||
for (let item of recipe) {
|
||||
if (startItems.includes(item)) { children.push(item) }
|
||||
else { children.push(...RecursivelyGetRecipes(item)) }
|
||||
}
|
||||
|
||||
return [product, children]
|
||||
}
|
||||
|
||||
|
||||
function prettyTreeString(tree, indent=0) {
|
||||
let string = ""
|
||||
|
||||
for (let item of tree) {
|
||||
if (typeof item == "string")
|
||||
{ string += "| ".repeat(indent) + item + "\n" }
|
||||
else { string += prettyTreeString(item, indent + 1) }
|
||||
}
|
||||
|
||||
return string
|
||||
}
|
||||
|
||||
|
||||
function clearTrees() {
|
||||
let children = trees.children
|
||||
for (let c of children) { c.remove() }
|
||||
}
|
||||
|
||||
|
||||
function makeTreeHTML(tree, parentNode, blue = false) {
|
||||
let previouslyAdded = undefined
|
||||
|
||||
let stringCount = tree.filter((x) => typeof(x) == "string").length
|
||||
let arrCount = tree.length - stringCount
|
||||
|
||||
// add .siblings container if theres more than 1 .item
|
||||
if (stringCount > 1) {
|
||||
let s = document.createElement("div")
|
||||
s.className = "siblings"
|
||||
parentNode.prepend(s)
|
||||
parentNode = s
|
||||
}
|
||||
if (arrCount == 0) { blue = true }
|
||||
|
||||
for (let i = 0; i < tree.length; i++) {
|
||||
if (typeof(tree[i]) == "string") {
|
||||
if (tree.length - 1 == i || tree[i + 1] == "string") { blue = true }
|
||||
let n = makeItemNode(tree[i], blue)
|
||||
parentNode.prepend(n)
|
||||
previouslyAdded = n
|
||||
}
|
||||
else { makeTreeHTML(tree[i], previouslyAdded, false) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function makeItemNode(name, blue = false) {
|
||||
let node = document.createElement("div")
|
||||
node.className = "item"
|
||||
let p = document.createElement("p")
|
||||
if (blue) { p.className = "blue" }
|
||||
p.textContent = name
|
||||
node.appendChild(p)
|
||||
|
||||
return node
|
||||
}
|
||||
@@ -50,6 +50,15 @@
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toyLi">
|
||||
<button onclick="slideTransition('/toys/crafting', event)" class="toyContainer borderedRect">
|
||||
<img class="toyImg" src="/assets/byte_dice_fancy_64x64.png">
|
||||
<div class="toyTextContainer">
|
||||
<h1>Crafting Tree Generator</h1>
|
||||
<p class="desc">A crafting-tree-like generation tool that generates descending trees from a TOML file</p>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="navBarContainer" data-alt="byte"></div>
|
||||
|
||||
+2
-2
@@ -36,7 +36,7 @@ h1 {
|
||||
margin: 0%;
|
||||
}
|
||||
button:hover {
|
||||
filter: brightness(1.15) drop-shadow(0px calc(1px * var(--pxDensity)) rgba(0, 0, 0, 0.5));
|
||||
filter: brightness(1.15) drop-shadow(0px calc(2px * var(--pxDensity)) rgba(0, 0, 0, 0.5));
|
||||
cursor: pointer;
|
||||
}
|
||||
button:active {
|
||||
@@ -44,7 +44,7 @@ button:active {
|
||||
transform: translateY(calc(1px * var(--pxDensity)));
|
||||
}
|
||||
.toyUl {
|
||||
padding: calc(3px * var(--pxDensity));
|
||||
padding: 0% calc(3px * var(--pxDensity));
|
||||
display: inline-flex;
|
||||
width: fit-content;
|
||||
justify-content: center;
|
||||
|
||||
Reference in New Issue
Block a user