1 Commits

Author SHA1 Message Date
d0717402c0 changes to dice-box-threejs
All checks were successful
CI / deploy (push) Successful in 5m20s
2025-02-16 12:45:26 +01:00
18 changed files with 113 additions and 283 deletions

View File

@@ -66,11 +66,11 @@ jobs:
- name: Deploy unstable - name: Deploy unstable
if: github.ref_name != 'main' if: github.ref_name != 'main'
run: "ssh -i ./.key dice-tower@${{secrets.SSH_HOST}} 'docker compose -f compose.unstable.yml pull && docker compose -f compose.unstable.yml up -d' " run: "ssh -i ./.key dice-tower@${{secrets.SSH_HOST}} 'docker compose -f compose.unstable.yml up -d' "
- name: Deploy - name: Deploy
if: github.ref_name == 'main' if: github.ref_name == 'main'
run: "ssh -i ./.key dice-tower@${{secrets.SSH_HOST}} 'docker compose -f compose.yml pull && docker compose -f compose.yml up -d' " run: "ssh -i ./.key dice-tower@${{secrets.SSH_HOST}} 'docker compose -f compose.yml up -d' "
- name: Deploy local - name: Deploy local
if: github.ref_name == 'main' if: github.ref_name == 'main'

View File

@@ -16,7 +16,6 @@
<p align="center"> <p align="center">
<img src=".github/media/preview.gif" /> <img src=".github/media/preview.gif" />
</p> </p>
--- ---
## Key Features ## Key Features
@@ -28,7 +27,6 @@
* Watch roll results (also available as Browser Source in OBS) * Watch roll results (also available as Browser Source in OBS)
--- ---
## Start Container ## Start Container
You can start dice-tower with docker compose You can start dice-tower with docker compose

View File

@@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>de.arindy</groupId> <groupId>de.arindy</groupId>
<artifactId>dice-tower</artifactId> <artifactId>dice-tower</artifactId>
<version>1.2.3</version> <version>1.2.0-SNAPSHOT</version>
<properties> <properties>
<compiler-plugin.version>3.13.0</compiler-plugin.version> <compiler-plugin.version>3.13.0</compiler-plugin.version>

View File

@@ -23,12 +23,11 @@ class ChatOverlayResource {
@QueryParam("subsAllowed") subsAllowed: Boolean = false, @QueryParam("subsAllowed") subsAllowed: Boolean = false,
@QueryParam("cmd") cmd: String? = "roll", @QueryParam("cmd") cmd: String? = "roll",
@QueryParam("theme") theme: String? = "default", @QueryParam("theme") theme: String? = "default",
@QueryParam("faceColor") faceColor: String? = "#ff0202", @QueryParam("themeColor") themeColor: String? = "default",
@QueryParam("numberColor") numberColor: String? = "#ffffff",
@QueryParam("clearAfter") clearAfter: Long? = -1, @QueryParam("clearAfter") clearAfter: Long? = -1,
@QueryParam("timeout") timeout: Long? = -1 @QueryParam("timeout") timeout: Long? = -1
): TemplateInstance { ): TemplateInstance {
return Templates.chatoverlay(channel, scale ?: 7, maxDice ?: 20, modsAllowed, vipAllowed, subsAllowed, cmd ?: "roll", theme ?: "default", faceColor ?: "#ff0202", numberColor ?: "#ffffff", clearAfter ?: 10, timeout ?: 60) return Templates.chatoverlay(channel, scale ?: 7, maxDice ?: 20, modsAllowed, vipAllowed, subsAllowed, cmd ?: "roll", theme ?: "default", themeColor ?: "ff0202", clearAfter ?: 10, timeout ?: 60)
} }
@GET @GET

View File

@@ -53,10 +53,10 @@ final class DiceResource(@Context val sse: Sse) {
.mediaType(MediaType.APPLICATION_JSON_TYPE).data(data).build() .mediaType(MediaType.APPLICATION_JSON_TYPE).data(data).build()
) )
if (data.roll.all { it.trim().isNotEmpty() }) { if (data.roll.all { it.trim().isNotEmpty() }) {
results(data.room!!, Result(data.name, data.user!!, data.faceColor, null)) results(data.room!!, Result(data.name, data.user!!, data.themeColor, null))
} }
Thread.sleep(1000) Thread.sleep(1000)
results(data.room!!, Result(data.name, data.user!!, data.faceColor, results.toTypedArray())) results(data.room!!, Result(data.name, data.user!!, data.themeColor, results.toTypedArray()))
} }
@POST @POST
@@ -110,7 +110,7 @@ final class DiceResource(@Context val sse: Sse) {
} }
@RegisterForReflection @RegisterForReflection
data class Result(val name: String, val user: String, val faceColor: String, val results: Array<Results>?) { data class Result(val name: String, val user: String, val themeColor: String, val results: Array<Results>?) {
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
if (javaClass != other?.javaClass) return false if (javaClass != other?.javaClass) return false
@@ -119,7 +119,7 @@ final class DiceResource(@Context val sse: Sse) {
if (name != other.name) return false if (name != other.name) return false
if (user != other.user) return false if (user != other.user) return false
if (faceColor != other.faceColor) return false if (themeColor != other.themeColor) return false
if (results != null) { if (results != null) {
if (other.results == null) return false if (other.results == null) return false
if (!results.contentEquals(other.results)) return false if (!results.contentEquals(other.results)) return false
@@ -131,7 +131,7 @@ final class DiceResource(@Context val sse: Sse) {
override fun hashCode(): Int { override fun hashCode(): Int {
var result = name.hashCode() var result = name.hashCode()
result = 31 * result + user.hashCode() result = 31 * result + user.hashCode()
result = 31 * result + faceColor.hashCode() result = 31 * result + themeColor.hashCode()
result = 31 * result + (results?.contentHashCode() ?: 0) result = 31 * result + (results?.contentHashCode() ?: 0)
return result return result
} }

View File

@@ -1,14 +1,11 @@
package de.arindy.dicetower package de.arindy.dicetower
import io.quarkus.runtime.annotations.RegisterForReflection
@RegisterForReflection
data class RollPayload( data class RollPayload(
val name: String, val name: String,
var command: String, var command: String,
var predetermined: Boolean? = false, var predetermined: Boolean? = false,
val faceColor: String = "white", val themeColor: String = "white",
val numberColor: String = "white", val themeForegroundColor: String = "white",
val theme: String = "default", val theme: String = "default",
var room: String?, var room: String?,
var user: String?, var user: String?,

View File

@@ -27,8 +27,7 @@ object Templates {
subsAllowed: Boolean, subsAllowed: Boolean,
cmd: String?, cmd: String?,
theme: String?, theme: String?,
faceColor: String?, themeColor: String?,
numberColor: String?,
clearAfter: Long?, clearAfter: Long?,
timeout: Long? timeout: Long?
): TemplateInstance ): TemplateInstance

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

View File

@@ -14,17 +14,6 @@ function url() {
return window.location.protocol + '//' + window.location.hostname + (window.location.port?.length > 0 ? ':' + window.location.port : ''); return window.location.protocol + '//' + window.location.hostname + (window.location.port?.length > 0 ? ':' + window.location.port : '');
} }
function register() {
let httpRequest = new XMLHttpRequest();
httpRequest.open('POST', url() + '/dice/' + document.getElementById('room').value + '/register')
httpRequest.setRequestHeader('Content-Type', 'application/json')
httpRequest.send(JSON.stringify({
name: document.getElementById('name').value,
overlay: document.getElementById('overlayId').value,
id: document.getElementById('room').value + ':' + localStorage.getItem('userId')
}))
}
function start(event = undefined) { function start(event = undefined) {
if ((!event || event.keyCode === 13) && document.getElementById('name').value.length > 0 && document.getElementById('room').value.length > 0) { if ((!event || event.keyCode === 13) && document.getElementById('name').value.length > 0 && document.getElementById('room').value.length > 0) {
document.getElementById('overlayId').value = url() + '/overlay/' + document.getElementById('room').value + ':' + localStorage.getItem('userId') + '?scale=10&clearAfter=30'; document.getElementById('overlayId').value = url() + '/overlay/' + document.getElementById('room').value + ':' + localStorage.getItem('userId') + '?scale=10&clearAfter=30';
@@ -59,11 +48,11 @@ function start(event = undefined) {
if (localStorage.getItem(document.getElementById('name').value + "-theme")) { if (localStorage.getItem(document.getElementById('name').value + "-theme")) {
document.getElementById('theme').value = localStorage.getItem(document.getElementById('name').value + "-theme") document.getElementById('theme').value = localStorage.getItem(document.getElementById('name').value + "-theme")
} }
if (localStorage.getItem(document.getElementById('name').value + "-faceColor")) { if (localStorage.getItem(document.getElementById('name').value + "-themeColor")) {
document.getElementById('faceColor').setColor(localStorage.getItem(document.getElementById('name').value + "-faceColor")); document.getElementById('themeColor').setColor(localStorage.getItem(document.getElementById('name').value + "-themeColor"));
} }
if (localStorage.getItem(document.getElementById('name').value + "-numberColor")) { if (localStorage.getItem(document.getElementById('name').value + "-themeForegroundColor")) {
document.getElementById('numberColor').setColor(localStorage.getItem(document.getElementById('name').value + "-numberColor")); document.getElementById('themeForegroundColor').setColor(localStorage.getItem(document.getElementById('name').value + "-themeForegroundColor"));
} }
if (!localStorage.getItem(document.getElementById('name').value + '-started')) { if (!localStorage.getItem(document.getElementById('name').value + '-started')) {
@@ -72,7 +61,14 @@ function start(event = undefined) {
localStorage.setItem(document.getElementById('name').value + '-started', "true") localStorage.setItem(document.getElementById('name').value + '-started', "true")
register(); let httpRequest = new XMLHttpRequest();
httpRequest.open('POST', url() + '/dice/' + document.getElementById('room').value + '/register')
httpRequest.setRequestHeader('Content-Type', 'application/json')
httpRequest.send(JSON.stringify({
name: document.getElementById('name').value,
overlay: document.getElementById('overlayId').value,
id: document.getElementById('room').value + ':' + localStorage.getItem('userId')
}))
if (document.getElementById('gm').checked) { if (document.getElementById('gm').checked) {
document.getElementById('resultSwitch').checked = true; document.getElementById('resultSwitch').checked = true;
document.getElementById('resultFrame').src = document.getElementById('resultsId').value; document.getElementById('resultFrame').src = document.getElementById('resultsId').value;
@@ -102,21 +98,18 @@ function start(event = undefined) {
newOverlay.appendChild(newInput); newOverlay.appendChild(newInput);
overlays.appendChild(newOverlay); overlays.appendChild(newOverlay);
if (!document.getElementById(data.id + '-diceFrame')) { let dice = document.createElement('iframe');
let dice = document.createElement('iframe'); dice.id = data.id + '-diceFrame'
dice.id = data.id + '-diceFrame' dice.style.width = "50%";
dice.style.width = "50%"; dice.style.height = "100%";
dice.style.height = "100%"; dice.style.overflow = "hidden";
dice.style.overflow = "hidden"; dice.style.border = "0";
dice.style.border = "0"; dice.style.zIndex = "4";
dice.style.zIndex = "4"; dice.style.position = "absolute";
dice.style.position = "absolute"; dice.style.top = "0";
dice.style.top = "0"; dice.style.left = "50%";
dice.style.left = "50%"; dice.src = data.overlay;
dice.src = data.overlay; document.getElementById('results-dice').appendChild(dice)
document.getElementById('results-dice').appendChild(dice)
}
} }
configurePopover(); configurePopover();
@@ -132,15 +125,14 @@ function rollEasy(dice) {
function roll(event) { function roll(event) {
if ((!event || event.keyCode === 13) && document.getElementById('command').value?.length > 0) { if ((!event || event.keyCode === 13) && document.getElementById('command').value?.length > 0) {
register()
let httpRequest = new XMLHttpRequest(); let httpRequest = new XMLHttpRequest();
httpRequest.open('POST', url() + '/dice/' + document.getElementById('room').value + ':' + localStorage.getItem(`userId`)) httpRequest.open('POST', url() + '/dice/' + document.getElementById('room').value + ':' + localStorage.getItem(`userId`))
httpRequest.setRequestHeader('Content-Type', 'application/json') httpRequest.setRequestHeader('Content-Type', 'application/json')
httpRequest.send(JSON.stringify({ httpRequest.send(JSON.stringify({
name: document.getElementById('name').value, name: document.getElementById('name').value,
command: document.getElementById('command').value, command: document.getElementById('command').value,
faceColor: document.getElementById('faceColor').value, themeColor: document.getElementById('themeColor').value,
numberColor: document.getElementById('numberColor').value, themeForegroundColor: document.getElementById('themeForegroundColor').value,
theme: document.getElementById('theme').value theme: document.getElementById('theme').value
})) }))
} }
@@ -148,8 +140,8 @@ function roll(event) {
function saveDice() { function saveDice() {
localStorage.setItem(document.getElementById('name').value + "-theme", document.getElementById('theme').value) localStorage.setItem(document.getElementById('name').value + "-theme", document.getElementById('theme').value)
localStorage.setItem(document.getElementById('name').value + "-faceColor", document.getElementById('faceColor').value) localStorage.setItem(document.getElementById('name').value + "-themeColor", document.getElementById('themeColor').value)
localStorage.setItem(document.getElementById('name').value + "-numberColor", document.getElementById('numberColor').value) localStorage.setItem(document.getElementById('name').value + "-themeForegroundColor", document.getElementById('themeForegroundColor').value)
} }
function configurePopover() { function configurePopover() {
@@ -198,7 +190,6 @@ document.addEventListener("DOMContentLoaded", async () => {
document.querySelector('meta[property="twitter:url"]').setAttribute("content", url()); document.querySelector('meta[property="twitter:url"]').setAttribute("content", url());
document.querySelector('meta[property="og:image"]').setAttribute("content", url() + '/rich.png'); document.querySelector('meta[property="og:image"]').setAttribute("content", url() + '/rich.png');
document.querySelector('meta[name="twitter:image"]').setAttribute("content", url() + '/rich.png'); document.querySelector('meta[name="twitter:image"]').setAttribute("content", url() + '/rich.png');
document.querySelector('meta[property="twitter:domain"]').setAttribute("content", window.location.hostname);
if (localStorage.getItem('last-name') && localStorage.getItem('last-room')) { if (localStorage.getItem('last-name') && localStorage.getItem('last-room')) {
document.getElementById('name').value = localStorage.getItem('last-name'); document.getElementById('name').value = localStorage.getItem('last-name');
@@ -215,7 +206,11 @@ document.addEventListener("DOMContentLoaded", async () => {
}) })
document.getElementById('resultDiceSwitch').addEventListener('change', function () { document.getElementById('resultDiceSwitch').addEventListener('change', function () {
document.getElementById('results-dice').hidden = !this.checked; if (!this.checked) {
document.getElementById('results-dice').hidden = true
} else {
document.getElementById('results-dice').hidden = false
}
}) })
document.getElementById('chatOverlayLink').href = url() + '/chatoverlay' document.getElementById('chatOverlayLink').href = url() + '/chatoverlay'
@@ -223,3 +218,6 @@ document.addEventListener("DOMContentLoaded", async () => {
configurePopover(); configurePopover();
}) })
if (!localStorage.getItem("userId")) {
localStorage.setItem("userId", self.crypto.randomUUID());
}

View File

@@ -115,8 +115,8 @@ document.addEventListener("DOMContentLoaded", async () => {
diceBox.clearDice(); diceBox.clearDice();
await diceBox.updateConfig({ await diceBox.updateConfig({
theme_customColorset: { theme_customColorset: {
background: document.getElementById('faceColor').value, background: document.getElementById('themeColor').value,
foreground: document.getElementById('numberColor').value, foreground: document.getElementById('themeForegroundColor').value,
texture: document.getElementById('theme').value texture: document.getElementById('theme').value
} }
}); });

View File

@@ -1,18 +0,0 @@
{
"name": "Dice-Tower",
"icons": [
{
"src": "192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": "/",
"display_override": ["window-controls-overlay", "minimal-ui"],
"display": "standalone"
}

View File

@@ -32,22 +32,6 @@ button:active {
background: #222222; background: #222222;
} }
#install {
padding: 10px;
border: #666666 3px solid;
border-radius: 10px;
background: #666666;
color: #fff
}
#install:hover {
background: #444444;
}
#install:active {
background: #222222;
}
input { input {
margin: 10px; margin: 10px;
} }

View File

@@ -12,20 +12,15 @@
<div popover id="results" class="tooltip"> <div popover id="results" class="tooltip">
</div> </div>
<script type="module"> <script type="module">
import DiceBox from "/vendor/dice-box/dice-box-threejs.es.js"; import DiceBox from "/vendor/dice-box/dice-box.es.js";
const diceBox = new DiceBox("#dice-box", { const diceBox = new DiceBox("#dice-box", {
assetPath: "/vendor/dice-box/", assetPath: "/vendor/assets/",
light_intensity: 2, theme: '{theme}',
gravity_multiplier: 600, themeColor: '{themeColor}',
baseScale: {scale} * 10, scale: {scale}
strength: Math.floor(Math.random() * 4),
theme_customColorset: {
texture: '{theme}',
background: '{faceColor}',
foreground: '{numberColor}'
}
}); });
diceBox.initialize(); diceBox.init()
ComfyJS.Init('{channel}'); ComfyJS.Init('{channel}');
//maxDice //maxDice
@@ -38,16 +33,16 @@
toggleWait(true); toggleWait(true);
diceBox.onRollComplete = (rollResult) => { diceBox.onRollComplete = (rollResult) => {
rollResult.sets.forEach(result => { rollResult.forEach(result => {
let values = [] let values = []
result.rolls.forEach(roll => { result.rolls.forEach(roll => {
values.push(roll.value); values.push(roll.value);
}) })
document.getElementById('results').innerHTML = '<strong>' + user + '</strong> rolls <strong>' + message + '</strong>:<br/> [' + values.map(value => value === 1 ? '<strong style="text-shadow: 2px 2px 10px red">' + value + '</strong>' : value === result.sides ? '<strong style="text-shadow: 2px 2px 10px green">' + value + '</strong>' : value).join(' + ') + '] = <strong>' + result.total + '</strong> ' document.getElementById('results').innerHTML = '<strong>' + user + '</strong> rolls <strong>' + message + '</strong>:<br/> [' + values.map(value => value === 1 ? '<strong style="text-shadow: 2px 2px 10px red">' + value + '</strong>' : value === result.sides ? '<strong style="text-shadow: 2px 2px 10px green">' + value + '</strong>' : value).join(' + ') + (result.modifier > 0 ? ' <a style="text-decoration: underline">+' + result.modifier + '</a>' : result.modifier < 0 ? ' <a style="text-decoration: underline">' + result.modifier + '</a>' : '') + '] = <strong>' + result.value + '</strong> '
}) })
document.getElementById('results').showPopover() document.getElementById('results').showPopover()
setTimeout(() => { setTimeout(() => {
diceBox.clearDice(); diceBox.clear();
document.getElementById('results').hidePopover() document.getElementById('results').hidePopover()
}, {clearAfter} * 1000) }, {clearAfter} * 1000)
} }

View File

@@ -23,16 +23,18 @@
<div class="w3-panel w3-theme-l4 w3-card w3-display-container" <div class="w3-panel w3-theme-l4 w3-card w3-display-container"
style="padding: 25px; text-align: center; margin-bottom: auto;"> style="padding: 25px; text-align: center; margin-bottom: auto;">
<label for="theme">Theme </label> <label for="theme">Theme </label>
<select name="theme" id="theme" style="margin: 0 25px"></select> <select name="theme" id="theme" style="margin: 25px">
<option value="default">Default</option>
<div style="display: flex; flex-direction: row; justify-content: space-between; align-items: baseline"> <option value="blueGreenMetal">Blue-Green Metal</option>
<div style="flex-grow: 1; padding: 0 10px"> <option value="diceOfRolling">Dice of Rolling</option>
<color-picker id="faceColor" name="Face" value="black"></color-picker> <option value="gemstone">Gemstone</option>
</div> <option value="gemstoneMarble">Marble Gemstone</option>
<div style="flex-grow: 1; padding: 10px 0"> <option value="rock">Rock</option>
<color-picker id="numberColor" name="Numbers" value="white"></color-picker> <option value="rust">Rust</option>
</div> <option value="smooth">Smooth</option>
</div> <option value="wooden">Wooden</option>
</select>
<color-picker id="themeColor"></color-picker>
<div> <div>
<label for="channel">Channel </label> <label for="channel">Channel </label>
<input type="text" id="channel" style="width: 400px; margin-top: 20px" value="arindy"/> <input type="text" id="channel" style="width: 400px; margin-top: 20px" value="arindy"/>
@@ -55,7 +57,7 @@
</div> </div>
<div> <div>
<label for="scale">Dice-Scale </label> <label for="scale">Dice-Scale </label>
<input type="number" id="scale" style="width: 50px; margin-top: 20px" value="15"/> <input type="number" id="scale" style="width: 50px; margin-top: 20px" value="9"/>
<label for="maxDice">Max number of dice </label> <label for="maxDice">Max number of dice </label>
<input type="number" id="maxDice" style="width: 50px; margin-top: 20px" value="20"/> <input type="number" id="maxDice" style="width: 50px; margin-top: 20px" value="20"/>
</div> </div>
@@ -65,10 +67,7 @@
<label for="timeout">Command-timeout (in seconds)</label> <label for="timeout">Command-timeout (in seconds)</label>
<input type="number" id="timeout" style="width: 50px; margin-top: 20px" value="60"/> <input type="number" id="timeout" style="width: 50px; margin-top: 20px" value="60"/>
</div> </div>
<div id="dice-box" style="height: 400px"></div>
<div id="dice-box" style="width: 850px; height: 400px">
<div id="app"></div>
</div>
<button style="margin: 10px" id="preview">Preview <i class="fa-solid fa-magnifying-glass"></i></button> <button style="margin: 10px" id="preview">Preview <i class="fa-solid fa-magnifying-glass"></i></button>
<button style="margin: 10px" id="generate">Generate overlay-link <i class="fa-solid fa-link"></i></button> <button style="margin: 10px" id="generate">Generate overlay-link <i class="fa-solid fa-link"></i></button>
<div> <div>
@@ -105,139 +104,30 @@
} }
</script> </script>
<script type="module"> <script type="module">
import DiceBox from "/vendor/dice-box/dice-box-threejs.es.js"; import DiceBox from "/vendor/dice-box/dice-box.es.js";
let diceBox
const Themes = {
cloudy: {
name: "Clouds (Transparent)"
},
cloudy_2: {
name: "Clouds"
},
fire: {
name: "Fire"
},
marble: {
name: "Marble"
},
water: {
name: "Water"
},
ice: {
name: "Ice"
},
paper: {
name: "Paper"
},
speckles: {
name: "Speckles"
},
glitter: {
name: "Glitter"
},
glitter_2: {
name: "Glitter (Transparent)"
},
stars: {
name: "Stars"
},
stainedglass: {
name: "Stained Glass"
},
wood: {
name: "Wood"
},
metal: {
name: "Stainless Steel"
},
skulls: {
name: "Skulls"
},
leopard: {
name: "Leopard"
},
tiger: {
name: "Tiger"
},
cheetah: {
name: "Cheetah"
},
dragon: {
name: "Dragon"
},
lizard: {
name: "Lizard"
},
bird: {
name: "Bird"
},
astral: {
name: "Astral Sea"
},
bronze01: {
name: "Bronze 1"
},
bronze02: {
name: "Bronze 2"
},
bronze03: {
name: "Bronze 3"
},
bronze03a: {
name: "Bronze 3a"
},
bronze03b: {
name: "Bronze 3b"
},
bronze04: {
name: "Bronze 4"
},
none: {
name: "none"
}
}
function url() { function url() {
return window.location.protocol + '//' + window.location.hostname + (window.location.port?.length > 0 ? ':' + window.location.port : ''); return window.location.protocol + '//' + window.location.hostname + (window.location.port?.length > 0 ? ':' + window.location.port : '');
} }
document.addEventListener("DOMContentLoaded", async () => { document.addEventListener("DOMContentLoaded", async () => {
const themeSelector = document.getElementById('theme');
for (const theme in Themes) {
let option = document.createElement('option');
option.value = theme;
option.innerText = Themes[theme].name;
themeSelector.appendChild(option);
}
themeSelector.value = 'cloudy';
document.getElementById('preview').onclick = async () => { document.getElementById('preview').onclick = async () => {
document.getElementById('app').replaceChildren(...[]) document.getElementById('dice-box').replaceChildren(...[])
diceBox = new DiceBox("#app", { const diceBox = new DiceBox("#dice-box", {
assetPath: "/vendor/dice-box/", assetPath: "/vendor/assets/",
light_intensity: 2, theme: document.getElementById('theme').value,
gravity_multiplier: 600, themeColor: document.getElementById('themeColor').value,
baseScale: 120, scale: +document.getElementById('scale').value
strength: Math.floor(Math.random() * 4),
}); });
await diceBox.initialize(); await diceBox.init()
diceBox.clearDice(); diceBox.roll(['1d2', '1d4', '1d6', '1d8', '1d10', '1d12', '1d20', '1d100']);
await diceBox.updateConfig({
theme_customColorset: {
background: document.getElementById('faceColor').value,
foreground: document.getElementById('numberColor').value,
texture: document.getElementById('theme').value
}
});
await diceBox.roll('1d2 & 1d4 & 1d6 & 1d8 & 1d10 & 1d12 & 1d20 & 1d100');
} }
document.getElementById('generate').onclick = async () => { document.getElementById('generate').onclick = async () => {
document.getElementById('link').value = url() + document.getElementById('link').value = url() +
"/chatoverlay/" + document.getElementById('channel').value + "/chatoverlay/" + document.getElementById('channel').value +
"?cmd=" + document.getElementById('cmd').value + "?cmd=" + document.getElementById('cmd').value +
"&theme=" + document.getElementById('theme').value + "&theme=" + document.getElementById('theme').value +
"&faceColor=" + encodeURIComponent(document.getElementById('faceColor').value) + "&themeColor=" + encodeURIComponent(document.getElementById('themeColor').value) +
"&numberColor=" + encodeURIComponent(document.getElementById('numberColor').value) +
"&scale=" + document.getElementById('scale').value + "&scale=" + document.getElementById('scale').value +
"&maxDice=" + document.getElementById('maxDice').value + "&maxDice=" + document.getElementById('maxDice').value +
"&clearAfter=" + document.getElementById('clearAfter').value + "&clearAfter=" + document.getElementById('clearAfter').value +

View File

@@ -3,8 +3,25 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Dice-Tower</title> <title>Dice-Tower</title>
<meta name="version" content="{version}">
<link rel="manifest" href="manifest.json" /> <meta property="og:title" content="Dice-Tower">
<meta name="twitter:title" content="Dice-Tower">
<meta property="og:type" content="website">
<meta name="twitter:card" content="summary_large_image">
<meta property="og:url" content="https://dice-tower.com">
<meta property="twitter:url" content="https://dice-tower.com">
<meta property="twitter:domain" content="dice-tower.com">
<meta property="og:image" content="https://dice-tower.com/rich.png">
<meta name="twitter:image" content="https://dice-tower.com/rich.png">
<meta name="description" content="
Easy to use online dice rolling with customizable overlays.
">
<link rel="stylesheet" href="/vendor/w3css/4/w3.css"> <link rel="stylesheet" href="/vendor/w3css/4/w3.css">
<link rel="stylesheet" href="/vendor/font-awesome/css/fontawesome.css"> <link rel="stylesheet" href="/vendor/font-awesome/css/fontawesome.css">
<link rel="stylesheet" href="/vendor/font-awesome/css/all.css"> <link rel="stylesheet" href="/vendor/font-awesome/css/all.css">
@@ -13,43 +30,12 @@
<script src="/vendor/color-picker.js"></script> <script src="/vendor/color-picker.js"></script>
<script type="module" src="/dice-preview.js"></script> <script type="module" src="/dice-preview.js"></script>
<script type="text/javascript" src="/app.js"></script> <script type="text/javascript" src="/app.js"></script>
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Dice-Tower">
<meta name="twitter:image" content="{http:request.scheme}://{http:request.authority}/rich.png">
<meta name="description" content="Easy to use online dice rolling with customizable overlays.">
<meta name="twitter:description" content="Easy to use online dice rolling with customizable overlays.">
<meta property="og:url" content="{http:request.absoluteURI}">
<meta property="og:image" content="{http:request.scheme}://{http:request.authority}/rich.png">
<meta property="og:description" content="Easy to use online dice rolling with customizable overlays.">
<meta property="og:title" content="Dice-Tower">
<meta property="og:site_name" content="Dice-Tower">
<meta property="og:type" content="website">
<meta property="twitter:url" content="{http:request.absoluteURI}">
<meta property="twitter:domain" content="{http:request.authority}">
</head> </head>
<body class="w3-theme-l1"> <body class="w3-theme-l1">
<script>
if (!localStorage.getItem("userId")) {
localStorage.setItem("userId", self.crypto.randomUUID());
}
addEventListener("beforeinstallprompt", (event) => {
event.preventDefault()
let install = document.createElement('button');
install.id = 'install'
install.style.position = 'absolute'
install.style.top = '25px'
install.style.right = '25px'
install.innerHTML = 'Install Dice-Tower'
install.onclick = () => event.prompt()
document.body.appendChild(install)
});
</script>
<div class="w3-container w3-content" <div class="w3-container w3-content"
style="height: 95vh; display: flex; flex-direction: column; justify-content: space-between; padding: 25px"> style="height: 95vh; display: flex; flex-direction: column; justify-content: space-between; padding: 25px">
<h1 style="text-align: center"><i class="fa-solid fa-dice-d20"></i> Dice-Tower <i class="fa-solid fa-dice-d20"></i> <h1 style="text-align: center"><i class="fa-solid fa-dice-d20"></i> Dice-Tower <i class="fa-solid fa-dice-d20"></i>
</h1> </h1>
<div class="w3-panel w3-theme-l4 w3-card w3-display-container" <div class="w3-panel w3-theme-l4 w3-card w3-display-container"
style="padding: 25px; text-align: center; margin-bottom: auto;"> style="padding: 25px; text-align: center; margin-bottom: auto;">
<h2 id="nameH" popovertarget="room-hint" data-trigger="hover" style="margin: 0" hidden>Name</h2> <h2 id="nameH" popovertarget="room-hint" data-trigger="hover" style="margin: 0" hidden>Name</h2>
@@ -89,7 +75,6 @@
<button style="border: transparent; border-radius: 100%; font-size: large; font-weight: bold; height: 50px; width: 50px" <button style="border: transparent; border-radius: 100%; font-size: large; font-weight: bold; height: 50px; width: 50px"
onclick="addDice()">+ onclick="addDice()">+
</button> </button>
<button style="font-size: large; font-weight: bold;" onclick="rollEasy('d2')">D2</button>
<button style="font-size: large; font-weight: bold;" onclick="rollEasy('d4')">D4</button> <button style="font-size: large; font-weight: bold;" onclick="rollEasy('d4')">D4</button>
<button style="font-size: large; font-weight: bold;" onclick="rollEasy('d6')">D6</button> <button style="font-size: large; font-weight: bold;" onclick="rollEasy('d6')">D6</button>
<button style="font-size: large; font-weight: bold;" onclick="rollEasy('d8')">D8</button> <button style="font-size: large; font-weight: bold;" onclick="rollEasy('d8')">D8</button>
@@ -150,10 +135,10 @@
</div> </div>
<div style="display: flex; flex-direction: row; justify-content: space-between; align-items: baseline"> <div style="display: flex; flex-direction: row; justify-content: space-between; align-items: baseline">
<div style="flex-grow: 1; padding: 0 10px"> <div style="flex-grow: 1; padding: 0 10px">
<color-picker id="faceColor" name="Face" value="#8d8981"></color-picker> <color-picker id="themeColor" name="Face"></color-picker>
</div> </div>
<div style="flex-grow: 1; padding: 10px 0"> <div style="flex-grow: 1; padding: 10px 0">
<color-picker id="numberColor" name="Numbers" value="black"></color-picker> <color-picker id="themeForegroundColor" name="Numbers"></color-picker>
</div> </div>
</div> </div>
<div id="dice-box"> <div id="dice-box">
@@ -202,8 +187,11 @@
<h2 style="text-align: center">How-To</h2> <h2 style="text-align: center">How-To</h2>
<ul> <ul>
<li> <li>
Join a room by entering your character name and the name of the room Join a room by entering your character name and the name of the room.<br/>
<strong>If you are a GM, make sure to join the room first or let all other players rejoin to get all
Overlay-URLs.</strong>
</li> </li>
<li>Open your Dice-Overlay either in a new Tab or as a browser source in OBS</li> <li>Open your Dice-Overlay either in a new Tab or as a browser source in OBS</li>
<ul> <ul>
<li>You can configure your Overlay with query parameters (for more information hover over the link) <li>You can configure your Overlay with query parameters (for more information hover over the link)

View File

@@ -36,8 +36,8 @@
diceBox.updateConfig({ diceBox.updateConfig({
theme_customColorset: { theme_customColorset: {
texture: data.theme, texture: data.theme,
background: data.faceColor, background: data.themeColor,
foreground: data.numberColor foreground: data.themeForegroundColor
} }
}).then(() => { }).then(() => {
diceBox.roll(data.roll.join('&')); diceBox.roll(data.roll.join('&'));

View File

@@ -34,7 +34,7 @@
resultText += '<br/><strong>&ensp; D' + result.sides + '</strong>: [' + values.map(value => value === 1 ? '<strong style="text-shadow: 2px 2px 10px red">' + value + '</strong>' : value === result.sides ? '<strong style="text-shadow: 2px 2px 10px green">' + value + '</strong>' : value).join(' + ') + (result.modifier > 0 ? ' <a style="text-decoration: underline">+' + result.modifier + '</a>' : result.modifier < 0 ? ' <a style="text-decoration: underline">' + result.modifier + '</a>' : '') + '] = <strong>' + result.value + '</strong> ' resultText += '<br/><strong>&ensp; D' + result.sides + '</strong>: [' + values.map(value => value === 1 ? '<strong style="text-shadow: 2px 2px 10px red">' + value + '</strong>' : value === result.sides ? '<strong style="text-shadow: 2px 2px 10px green">' + value + '</strong>' : value).join(' + ') + (result.modifier > 0 ? ' <a style="text-decoration: underline">+' + result.modifier + '</a>' : result.modifier < 0 ? ' <a style="text-decoration: underline">' + result.modifier + '</a>' : '') + '] = <strong>' + result.value + '</strong> '
}) })
} }
node.innerHTML = '<strong style="text-shadow: 2px 2px 10px ' + data.faceColor + ';">' + data.name + ':</strong> ' + resultText node.innerHTML = '<strong style="text-shadow: 2px 2px 10px ' + data.themeColor + ';">' + data.name + ':</strong> ' + resultText
name.appendChild(node) name.appendChild(node)
document.getElementById('results').insertBefore(name, document.getElementById('results').firstChild); document.getElementById('results').insertBefore(name, document.getElementById('results').firstChild);
} }