WLED/wled00/data/pxmagic.htm

1065 lines
46 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="pt_BR">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!--link
href="https://fonts.googleapis.com/icon?family=Material+Icons"
rel="stylesheet"
/-->
<link
rel="shortcut icon"
href="data:image/png;base64,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"
/>
<title>Pixel Magic Tool - @ajotanc</title>
</head>
<style>
* {
box-sizing: border-box;
}
::selection {
background: #1982c4;
color: #ffffff;
}
html {
scroll-behavior: smooth;
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
font-size: 12px;
font-family: "Tahoma", monospace;
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0;
}
h3 {
color: #5f5f5f;
}
.divider {
width: calc(100% - 10px);
height: 1px;
background: #ececec;
margin: 20px auto;
}
.container {
display: flex;
align-items: center;
justify-content: center;
}
.content {
width: 100%;
min-width: 540px;
max-width: 900px;
margin: 20px;
}
#response,
#preview,
#image,
form,
canvas {
width: 100%;
}
form {
margin: 0 auto;
padding: 20px;
background-color: #f8f8f8;
border-radius: 8px;
border: 1px solid #cccccc;
}
.row {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
margin: 20px 0 0;
}
.row:nth-child(2) {
margin: 0;
}
.column {
flex-basis: calc(50% - 10px);
position: relative;
padding: 0 5px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
button {
font-family: "Tahoma", monospace;
}
input[type="text"],
input[type="number"],
input[type="email"],
input[type="tel"],
select,
textarea {
width: 100%;
padding: 10px;
border-radius: 5px;
border: none;
background-color: #f0f0f0;
font-size: 12px;
display: inline-block;
font-family: "Tahoma", monospace;
outline: none;
}
input[type="color"] {
width: 32px;
height: 32px;
cursor: pointer;
padding: 0px 1px;
outline: none;
}
.input-group {
display: flex;
}
.input-group input {
border-radius: 5px 0 0 5px;
}
.input-description {
padding: 10px;
font-size: 14px;
color: #626262;
background: #d9d9d9;
border-radius: 0px 5px 5px 0;
}
select {
appearance: none;
-webkit-appearance: none;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath d='M.6 2.6L4 6l3.4-3.4L8 3.2 4 7.2.1 3.3z'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 10px center;
background-size: 10px 10px;
}
textarea {
resize: vertical;
min-height: 120px;
margin: 0 0 10px;
}
input[type="submit"] {
padding: 10px 20px;
border: none;
border-radius: 5px;
background-color: #4caf50;
color: #fff;
font-size: 12px;
cursor: pointer;
}
.dropzone {
width: 100%;
border: 1px dashed #a9a9a9;
background-color: #f5f5f5;
color: #666;
font-size: 12px;
text-align: center;
padding: 40px 10px;
border-radius: 5px;
margin: 20px 0;
transition: all 0.5s ease-in-out;
}
.dropzone p {
margin: 0;
padding: 0;
}
.dropzone:hover {
cursor: pointer;
background-color: #eee;
}
.dropzone.dragover {
background-color: #ddd;
}
.range-slider {
appearance: none;
background-color: #ddd;
height: 8px;
width: 100%;
border-radius: 10px;
outline: none;
margin: 16px 0;
}
.range-slider::-webkit-slider-thumb {
appearance: none;
height: 16px;
width: 16px;
background-color: #4caf50;
border-radius: 50%;
cursor: pointer;
border: 0;
}
.range-slider::-moz-range-thumb {
appearance: none;
height: 16px;
width: 16px;
background-color: #4caf50;
border-radius: 50%;
cursor: pointer;
border: 0;
}
.switch {
position: relative;
display: inline-block;
width: 38px;
height: 20px;
}
.switch input {
outline: none;
display: none;
}
.switch-slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
border-radius: 34px;
transition: 0.4s;
}
.switch-slider:before {
position: absolute;
content: "";
height: 14px;
width: 14px;
left: 3px;
bottom: 3px;
background-color: white;
border-radius: 50%;
transition: 0.4s;
}
input:checked + .switch-slider {
background-color: #4caf50;
}
input:focus + .switch-slider {
box-shadow: 0 0 1px #4caf50;
}
input:checked + .switch-slider:before {
transform: translateX(18px);
}
#toast-container {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 9999;
}
.toast {
display: flex;
align-items: center;
justify-content: space-between;
width: max-content;
padding: 6px 12px;
margin: 10px 0 0;
border-radius: 8px;
color: #fff;
font-size: 12px;
transform: translateY(30px);
opacity: 0;
visibility: hidden;
}
.toast-icon {
font-size: 22px;
margin-right: 8px;
}
.toast .toast-body {
padding: 8px 0;
color: #fdfdfd;
}
.toast.success {
background-color: #8ac926;
}
.toast.error {
background-color: #ff595e;
}
.toast.warning {
background-color: #ffca3a;
}
.toast-progress {
position: absolute;
left: 4px;
bottom: 4px;
width: calc(100% - 8px);
height: 3px;
transform: scaleX(0);
transform-origin: left;
border-radius: inherit;
}
.toast.success .toast-progress {
background: linear-gradient(to right, #8ac926, #c5ca30);
}
.toast.error .toast-progress {
background: linear-gradient(to right, #ff595e, #e23c4e);
}
.toast.warning .toast-progress {
background: linear-gradient(to right, #ffca3a, #ffda3d);
}
#multipleCanvas {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
position: relative;
}
#multipleCanvas .controls {
width: 100%;
position: absolute;
display: none;
justify-content: space-between;
align-items: center;
padding: 0 23px;
}
#multipleCanvas .controls button {
border: 0;
outline: 0;
width: 46px;
height: 46px;
background: rgba(0, 0, 0, 0.3);
color: #fdfdfd;
text-align: center;
font-size: 22px;
cursor: pointer;
}
#multipleCanvas .controls span {
vertical-align: middle;
}
#multipleCanvas .carousel {
display: flex;
height: 100%;
width: 100%;
cursor: pointer;
}
#multipleCanvas .carousel img {
display: block;
width: 100%;
height: 100%;
margin-right: 20px;
border: 0;
}
#multipleCanvas .carousel img:last-child {
margin-right: 0;
}
.button {
width: 100%;
border: 0;
padding: 10px 18px;
border-radius: 4px;
color: #fdfdfd;
cursor: pointer;
margin: 0 0 10px;
background: #1982c4;
transition: all 0.5s ease-in-out;
}
.button:hover {
background: #4267ac;
}
.button:last-child {
margin-bottom: 0;
}
.buttons {
display: flex;
flex-direction: column;
width: 100%;
}
.buttonRainbow {
width: 100%;
border: 0;
padding: 10px 18px;
border-radius: 4px;
color: #fdfdfd;
cursor: pointer;
background: linear-gradient(
to right,
#ff595e,
#ffca3a,
#8ac926,
#1982c4,
#6a4c93
);
}
.buttonRainbow:hover {
animation-play-state: paused;
}
#preview {
border: 1px solid #cccccc;
padding: 20px;
margin: 20px 0;
border-radius: 8px;
}
#preview .buttons {
margin: 0 0 20px;
}
.w-full {
flex-basis: 100% !important;
}
.margin-zero {
margin: 0;
}
#overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: none;
}
#overlay.loading::after {
content: "";
display: block;
position: absolute;
top: calc(50% - 19px);
left: calc(50% - 19px);
width: 26px;
height: 26px;
border: 6px solid rgba(255, 255, 255, 0.5);
border-radius: 50%;
animation: spin 1s linear infinite;
}
input.invalid,
select.invalid,
textarea.invalid {
border: 1px solid #df1f1f;
}
input.invalid + .error-message,
select.invalid + .error-message,
textarea.invalid + .error-message {
display: block;
color: #df1f1f;
padding: 4px 0;
font-size: 14px;
font-weight: 600;
}
.slide-container {
width: 100%;
display: flex;
overflow-x: auto;
scroll-snap-type: x mandatory;
}
.slide {
scroll-snap-align: center;
}
.header {
display: flex;
align-items: center;
padding: 0 0 30px;
flex-direction: column;
}
.header .brand {
width: 100%;
max-width: 300px;
height: 100%;
display: block;
outline: none;
border: 0;
}
.header .title {
display: none;
}
.github {
display: flex;
overflow: hidden;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial,
sans-serif;
font-size: 0;
line-height: 0;
white-space: nowrap;
font-size: 12px;
color: #24292f;
font-weight: 600;
margin: 10px 0;
justify-content: center;
}
.github .widget {
display: flex;
justify-content: center;
align-items: center;
margin-right: 5px;
}
.github .button {
margin: 0;
width: auto;
padding: 5px 10px;
color: #24292f;
background: #ebf0f4;
border: 1px solid rgba(31, 35, 40, 0.15);
background-image: linear-gradient(180deg, #f6f8fa, #ebf0f4 90%);
display: flex;
text-decoration: none;
align-items: center;
}
.github .button:not(:last-child) {
border-radius: 0.25em 0 0 0.25em;
}
.github .button:hover {
background-image: linear-gradient(180deg, #ebf0f4, #f6f8fa 90%);
}
.github .icon {
margin-right: 5px;
fill: #24292f;
}
.github .count {
display: block;
padding: 13px 10px;
border: 1px solid rgba(31, 35, 40, 0.15);
border-left: 0;
border-radius: 0 0.25em 0.25em 0;
}
#alert {
padding: 10px 20px;
border: 1px solid #ffe69c;
background: #fff3cd;
border-radius: 8px;
margin: 20px 0 0;
font-size: 14px;
font-weight: bold;
color: #664d03;
}
.subtitle {
display: block;
font-size: 11px;
font-weight: 400;
margin: 2px 0 5px;
color: #1982c4;
}
.subtitle a {
text-decoration: none;
font-weight: 600;
color: #1982c4;
}
.subtitle a:hover,
.subtitle a:focus,
.subtitle a:active {
color: #1982c4;
}
@media (max-width: 767px) {
.title h1 {
font-size: 20px;
}
.title h3 {
font-size: 14px;
}
.content {
min-width: 0;
}
.row {
flex-direction: column;
margin: 0;
}
.column {
flex-basis: 100%;
margin: 20px 0 0;
padding: 0;
}
.divider {
margin: 20px auto 0;
}
}
@media (min-width: 768px) {
.row {
flex-wrap: nowrap;
}
}
@keyframes progress {
to {
transform: scaleX(1);
}
}
@keyframes spin {
to {
transform: rotate(360deg);
}
0% {
border-top-color: #ff595e;
}
25% {
border-top-color: #ffca3a;
}
50% {
border-top-color: #8ac926;
}
75% {
border-top-color: #1982c4;
}
100% {
border-top-color: #6a4c93;
}
}
@keyframes rainbow {
0% {
background-position: 0% 0%;
}
50% {
background-position: 100% 100%;
}
100% {
background-position: 0% 0%;
}
}
@keyframes fadeIn {
5% {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
95% {
opacity: 1;
transform: translateY(0);
}
}
</style>
<body>
<div class="container">
<div class="content">
<form id="formGenerate" novalidate>
<div class="header">
<!--img
class="brand"
src="https://user-images.githubusercontent.com/47322034/244749589-300b240b-40a3-4a9a-a6f0-925631919d9b.png"
alt="Pixel Magic Tool"
title="Pixel Magic Tool"
/-->
<div class="title">
<h1>Pixel Magic Tool</h1>
<h3>Image converter for WLED presets and playlists JSON</h3>
</div>
</div>
<div class="row">
<div class="column valitade">
<label for="hostname">Hostname</label>
<input type="text" name="hostname" id="hostname" required />
</div>
<div class="column valitade">
<label for="name">Preset Name</label>
<input
type="text"
name="name"
id="name"
value="New Preset"
required
/>
</div>
</div>
<div class="row">
<div class="column valitade">
<label for="pattern">Pattern</label>
<select name="pattern" id="pattern" required>
<option value="">Select a choice</option>
<option value="1" title="['ffffff']" selected>
Individual
</option>
<option value="2" title="[0, 'ffffff']">Index</option>
<option value="3" title="[0, 5, 'ffffff']">Range</option>
</select>
</div>
<div class="column valitade">
<label for="output">Output</label>
<select name="output" id="output" required>
<option value="">Select a choice</option>
<option value="json" selected>WLED JSON</option>
<option value="ha">Home Assistant</option>
<option value="curl">CURL</option>
</select>
</div>
</div>
<div class="row output" style="display: none">
<div class="column valitade">
<label for="device">Device</label>
<input type="text" name="device" id="device" required />
</div>
<div class="column valitade">
<label for="uniqueId">Unique Id</label>
<input type="text" name="uniqueId" id="uniqueId" required />
</div>
<div class="column valitade">
<label for="friendlyName">Friendly Name</label>
<input
type="text"
name="friendlyName"
id="friendlyName"
required
/>
</div>
</div>
<div class="row">
<div class="column valitade">
<label for="segments">Segment Id</label>
<select name="segments" id="segments" required>
<option value="">Select a choice</option>
</select>
</div>
<div class="column valitade">
<label for="brightness">Brightness</label>
<input
type="range"
name="brightness"
id="brightness"
min="0"
max="255"
value="128"
class="range-slider"
/>
</div>
</div>
<div class="row">
<div class="column valitade">
<label for="animation">Animation</label>
<label class="switch">
<input type="checkbox" name="animation" id="animation" />
<span class="switch-slider"></span>
</label>
</div>
<div class="column valitade">
<label for="transparentImage">Transparent Image</label>
<label class="switch">
<input
type="checkbox"
name="transparentImage"
id="transparentImage"
/>
<span class="switch-slider"></span>
</label>
</div>
<div class="column valitade">
<label for="resizeImage">Resize Image</label>
<label class="switch">
<input type="checkbox" name="resizeImage" id="resizeImage" />
<span class="switch-slider"></span>
</label>
</div>
</div>
<div class="row resizeImage" style="display: none">
<div class="column valitade">
<label for="width">Width</label>
<input type="number" name="width" id="width" value="32" />
</div>
<div class="column valitade">
<label for="height">Height</label>
<input type="number" name="height" id="height" value="32" />
</div>
</div>
<div class="row animation" style="display: none">
<div class="column valitade">
<label for="frames">Frames</label>
<input type="number" name="frames" id="frames" value="4" />
</div>
<div class="column valitade">
<label for="duration">Duration</label>
<div class="input-group">
<input
type="number"
name="duration"
id="duration"
value="0.5"
required="required"
min="0"
step="0.1"
inputmode="numeric"
/>
<div class="input-description">sec</div>
</div>
</div>
<div class="column valitade">
<label for="transition">Transition</label>
<div class="input-group">
<input
type="number"
name="transition"
id="transition"
value="0.2"
required="required"
min="0"
step="0.1"
inputmode="numeric"
/>
<div class="input-description">sec</div>
</div>
</div>
</div>
<div class="row transparentImage" style="display: none">
<div class="column valitade w-full">
<label for="color">Choose a color</label>
<small class="subtitle"
>Color that will replace the
<strong>transparent pixels</strong> in the image</small
>
<input type="color" name="color" id="color" value="#ffffff" />
</div>
</div>
<div class="row">
<div class="column valitade w-full">
<label for="images">Images</label>
<small class="subtitle"
>Images uploaded to
<a href="http://[wled-ip]/edit" target="_blank">WLED</a>
or upload image</small
>
<select name="images" id="images" required>
<option value="">Select a choice</option>
</select>
</div>
</div>
<div id="alert" style="display: none">
<span
>To define a large number of colors. 32x32 or larger matrix
presets need to be split into multiple requests at the same
time!</span
>
</div>
<div id="dropzone" class="dropzone valitade" style="display: none">
<p id="dropzoneLabel">
Drag and drop a file here or click to select a file
</p>
<input
type="file"
name="source"
id="source"
accept="image/*"
style="display: none"
/>
</div>
<div class="row">
<div class="column w-full">
<button type="button" class="buttonRainbow" id="btnGenerate">
Generate
</button>
</div>
</div>
</form>
<div id="preview" style="display: none">
<div class="row margin-zero">
<div class="column w-full">
<textarea
name="response"
id="response"
cols="30"
rows="10"
readonly="readonly"
></textarea>
</div>
</div>
<div id="isNotAnimation">
<div class="buttons">
<div class="row margin-zero">
<div class="column">
<button type="button" class="button" id="btnCopyToClipboard">
Copy to Clipboard
</button>
</div>
<div class="column">
<button type="button" class="button" id="btnDownloadPreset">
Download
</button>
</div>
</div>
<div class="divider"></div>
<div class="row margin-zero" id="notBigData">
<div class="column">
<button type="button" class="button" id="btnSimulatePreset">
Simulate
</button>
</div>
<div class="column">
<button type="button" class="button" id="btnSavePreset">
Save
</button>
</div>
</div>
<div class="row margin-zero" id="bigData">
<div class="column w-full">
<button
type="button"
class="button"
id="btnSimulatePresetBigData"
>
Simulate
</button>
</div>
</div>
</div>
<div id="singleCanvas"></div>
</div>
<div id="isAnimation">
<div class="buttons">
<div class="row margin-zero">
<div class="column">
<button type="button" class="button" id="btnCopyToClipboard">
Copy to Clipboard
</button>
</div>
<div class="column">
<button type="button" class="button" id="btnDownloadPreset">
Download
</button>
</div>
</div>
<div class="divider"></div>
<div class="row margin-zero">
<div class="column w-full">
<button type="button" class="button" id="btnSavePlaylist">
Save
</button>
</div>
</div>
</div>
<div id="multipleCanvas"></div>
</div>
</div>
<div class="github">
<div class="widget">
<a
class="button"
id="profile"
href="https://github.com/ajotanc"
target="_blank"
title="Alerson Jorge"
>
<svg class="icon" viewBox="0 0 16 16" width="16" height="16">
<path
d="M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45.68 1.31 2.69.94 0 .67.01 1.3.01 1.49 0 .21-.15.45-.55.38A7.995 7.995 0 0 1 0 8c0-4.42 3.58-8 8-8Z"
></path>
</svg>
<span>Follow @ajotanc</span>
</a>
<span class="count" id="followers">0</span>
</div>
<div class="widget">
<a class="button" id="repository" target="_blank" href="#">
<svg class="icon" viewBox="0 0 16 16" width="16" height="16">
<path
d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Zm0 2.445L6.615 5.5a.75.75 0 0 1-.564.41l-3.097.45 2.24 2.184a.75.75 0 0 1 .216.664l-.528 3.084 2.769-1.456a.75.75 0 0 1 .698 0l2.77 1.456-.53-3.084a.75.75 0 0 1 .216-.664l2.24-2.183-3.096-.45a.75.75 0 0 1-.564-.41L8 2.694Z"
></path>
</svg>
<span>Star</span>
</a>
<span class="count" id="star">0</span>
</div>
<div class="widget">
<a class="button" id="issue" target="_blank" href="#">
<svg class="icon" viewBox="0 0 16 16" width="16" height="16">
<path d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path>
<path
d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z"
></path>
</svg>
<span>Issue</span>
</a>
</div>
</div>
</div>
</div>
<div id="toast-container"></div>
<div id="overlay"></div>
</body>
<script>
const e="file:"===window.location.protocol?"http:":window.location.protocol,t=window.location.host||"0.0.0.0",n="PixelMagicTool";let a=`${e}//${t}`;const o=document.getElementById("hostname");o.value=t,o.addEventListener("change",(async()=>{a=`${e}//${o.value}`,await m(),await r(),i()}));let s=[],c={},l=[];function i(){const e=document.getElementById("images").parentNode.querySelector("a");e.href=e.href.replace("[wled-ip]",o.value)}async function d(e,t=!1,n=5e3){const o=`${a}/presets.json`,s=`${a}/json`;let c=0;B();const l=e.map((async e=>new Promise(((t,a)=>{setTimeout((async()=>{try{const t=await fetch(o),n=await t.json(),a=Object.keys(n),c=a.find((t=>"object"==typeof n[t]&&!n[t].playlist&&n[t].n===e.n))||parseInt(a.pop())+1,l=Object.assign(e,{psave:c}),i={method:"POST",body:JSON.stringify(l)};try{const t=await fetch(s,i),{success:n}=await t.json();n&&w(`Preset "${e.n}" save successfully!`)}catch(e){w(`Error saving preset: ${e}`,"error")}}catch(e){w(e,"error")}finally{t()}}),n*c++)}))));await Promise.all(l),t?setTimeout((async()=>{await async function(){const{value:e}=document.getElementById("duration"),{value:t}=document.getElementById("transition"),{value:n}=document.getElementById("name"),o=`${a}/presets.json`,s=`${a}/json`;try{const a=await fetch(o),c=await a.json(),l=Object.keys(c),i=l.filter((e=>"object"==typeof c[e]&&!c[e].playlist&&c[e].n&&c[e].n.includes(n))),d={psave:l.find((e=>"object"==typeof c[e]&&c[e].playlist&&c[e].n&&c[e].n===n))||parseInt(l.pop())+1,n:n,on:!0,o:!1,playlist:{ps:i,dur:Array.from({length:i.length},(()=>10*e)),transition:Array.from({length:i.length},(()=>10*t)),repeat:0,end:0}},r={method:"POST",body:JSON.stringify(d)};try{const e=await fetch(s,r),{success:t}=await e.json();t&&w(`Playlist "${n}" save successfully!`)}catch(e){w(`Error saving preset: ${e}`,"error")}}catch(e){w(e,"error")}}().then((()=>{b()})).catch((()=>{b()}))}),n):b()}async function r(){const e=`${a}/edit?list=/`,t=document.getElementById("images");t.innerHTML="";[{text:"Select a choice",value:""},{text:"Upload",value:"upload"}].forEach((({text:e,value:n})=>{const a=new Option(e,n);t.appendChild(a)})),B();try{const n=await fetch(e),o=await n.json(),s=["jpeg","jpg","png","gif"];o.filter((e=>{const{name:t}=e,[n,a]=t.split(".");return e.name=t.replace("/",""),s.includes(a)})).map((e=>{const{name:n}=e,o=document.createElement("option");o.text=n,o.value=`${a}/${n}`,t.add(o)}))}catch(e){w(e,"error")}finally{b()}}async function m(){const e=document.getElementById("segments"),t=document.getElementById("width"),n=document.getElementById("height"),o=`${a}/json/state`;e.innerHTML="";[{text:"Select a choice",value:""}].forEach((({text:t,value:n})=>{const a=new Option(t,n);e.appendChild(a)})),B();try{const a=await fetch(o),{seg:s}=await a.json();s&&s.forEach((function({id:a,n:o,stop:s,stopY:c},l){const i=document.createElement("option");i.text=o||`Segment ${a}`,i.value=a,i.setAttribute("data-width",s),i.setAttribute("data-height",c),0===l&&(i.selected=!0,t.value=s,n.value=c),e.add(i)}))}catch(e){w(e,"error")}finally{b()}}!async function(){await async function(){const e=document.getElementById("followers"),t=document.getElementById("repository"),a=document.getElementById("issue"),o=document.getElementById("star"),s="https://api.github.com/users/ajotanc";try{const t=await fetch(s),n=await t.json();e.textContent=n.followers}catch(e){w(e,"error")}try{const e=await fetch(`${s}/repos`),c=await e.json(),{name:l,html_url:i,stargazers_count:d}=c.find((({name:e})=>e===n));t.href=i,a.href=`${i}/issues`,o.textContent=d}catch(e){w(e,"error")}}(),await m(),await r(),i()}();const u=document.getElementById("dropzone"),y=document.getElementById("source");function p(e){return new Promise(((t,n)=>{const a=new Image;a.addEventListener("load",(function(){t(a)})),a.addEventListener("error",(function(){n(new Error("Error loading image"))})),a.src=e}))}function g(e){const{value:t}=document.getElementById("pattern"),{value:n}=document.getElementById("segments"),{value:a}=document.getElementById("brightness"),{value:o}=document.getElementById("width"),{valu
</script>
</html>