Merge branch 'feature/button-generator'

This commit is contained in:
Dan 2026-01-08 14:16:58 +00:00
commit bedb1166bc
14 changed files with 2538 additions and 15 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,528 @@
@import url(https://fonts.bunny.net/css?family=bebas-neue:400|lato:400,400i,700,700i|montserrat:400,400i,700,700i|open-sans:400,400i,700,700i|oswald:400,700|press-start-2p:400|roboto:400,400i,700,700i|roboto-mono:400,400i,700,700i|vt323:400);
#button-generator-app {
margin: 2rem 0;
padding: 2rem;
background: linear-gradient(
145deg,
rgba(5, 15, 30, 0.9) 0%,
rgba(10, 20, 40, 0.95) 100%
);
border-radius: 6px;
border: 1px solid rgba(0, 150, 255, 0.4);
box-shadow:
0 0 30px rgba(0, 150, 255, 0.15),
0 0 50px rgba(255, 120, 0, 0.08),
inset 0 0 60px rgba(0, 100, 200, 0.05);
position: relative;
overflow: visible;
&::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
height: 3px;
background: linear-gradient(
90deg,
transparent,
rgba(0, 150, 255, 0.6),
rgba(255, 120, 0, 0.6),
transparent
);
}
.generator-container {
display: grid;
grid-template-columns: 1fr 2fr;
gap: 2rem;
margin-top: 1rem;
position: relative;
z-index: 1;
@media (max-width: 768px) {
grid-template-columns: 1fr;
}
}
.preview-section {
background: linear-gradient(
135deg,
rgba(0, 100, 180, 0.15) 0%,
rgba(0, 80, 150, 0.1) 100%
);
padding: 1.5rem;
border-radius: 6px;
border: 1px solid rgba(0, 150, 255, 0.3);
display: flex;
flex-direction: column;
gap: 1rem;
position: sticky;
top: 1rem;
align-self: flex-start;
max-height: calc(100vh - 2rem);
overflow-y: auto;
box-shadow:
0 0 20px rgba(0, 150, 255, 0.1),
inset 0 0 40px rgba(0, 100, 200, 0.05);
&::before {
content: "";
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 4px;
background: linear-gradient(
180deg,
rgba(0, 150, 255, 0.7),
rgba(255, 120, 0, 0.5)
);
border-radius: 6px 0 0 6px;
}
h3 {
margin-top: 0;
color: #0096ff;
font-family: Verdana, "Trebuchet MS", Tahoma, sans-serif;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.1em;
text-shadow: 0 0 15px rgba(0, 150, 255, 0.5);
font-size: 1.2rem;
}
}
.presets-container {
margin-top: 1.5rem;
padding-top: 1.5rem;
border-top: 2px solid;
border-image: linear-gradient(
90deg,
transparent,
rgba(0, 150, 255, 0.5),
transparent
)
1;
h3 {
margin-top: 0;
margin-bottom: 1rem;
color: rgba(100, 180, 255, 0.9);
font-family: Verdana, "Trebuchet MS", Tahoma, sans-serif;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.08em;
text-shadow: 0 0 10px rgba(0, 150, 255, 0.4);
font-size: 1rem;
}
}
.preview-container {
display: flex;
flex-direction: column;
gap: 1rem;
}
.preview-wrapper {
background: repeating-conic-gradient(
rgba(20, 30, 50, 0.8) 0% 25%,
rgba(10, 20, 40, 0.9) 0% 50%
)
50% / 20px 20px;
padding: 2rem;
display: flex;
justify-content: center;
align-items: center;
border-radius: 4px;
border: 1px solid rgba(0, 150, 255, 0.2);
}
#button-canvas {
image-rendering: pixelated;
image-rendering: -moz-crisp-edges;
image-rendering: crisp-edges;
//border: 1px solid rgba(0, 150, 255, 0.4);
box-shadow: 0 0 15px rgba(0, 150, 255, 0.2);
}
.controls-section {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.control-group {
background: linear-gradient(
135deg,
rgba(0, 100, 180, 0.15) 0%,
rgba(0, 80, 150, 0.1) 100%
);
padding: 1rem;
border-radius: 6px;
border: 1px solid rgba(0, 150, 255, 0.3);
box-shadow:
0 0 20px rgba(0, 150, 255, 0.1),
inset 0 0 40px rgba(0, 100, 200, 0.05);
position: relative;
&::before {
content: "";
position: absolute;
left: 0;
top: 0;
width: 3px;
height: 100%;
background: linear-gradient(
180deg,
rgba(0, 150, 255, 0.7),
rgba(255, 120, 0, 0.5)
);
opacity: 0;
transition: opacity 0.3s ease;
}
&:hover::before {
opacity: 1;
}
h3 {
margin-top: 0;
margin-bottom: 1rem;
}
label {
display: block;
margin-top: 0.75rem;
margin-bottom: 0.25rem;
font-weight: 500;
font-size: 0.85rem;
color: rgba(100, 180, 255, 0.8);
text-transform: uppercase;
letter-spacing: 0.05em;
}
input[type="text"],
select {
width: 100%;
padding: 0.75rem 1rem;
border: 1px solid rgba(0, 150, 255, 0.4);
border-radius: 4px;
font-size: 0.9rem;
background: rgba(5, 15, 30, 0.7);
color: rgba(200, 220, 255, 0.95);
transition: all 0.3s ease;
box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.3);
&:focus {
outline: none;
border-color: rgba(0, 150, 255, 0.7);
box-shadow:
0 0 15px rgba(0, 150, 255, 0.3),
inset 0 2px 8px rgba(0, 0, 0, 0.4);
background: rgba(5, 15, 30, 0.9);
}
}
select {
cursor: pointer;
option {
background: rgba(5, 15, 30, 0.95);
color: rgba(200, 220, 255, 0.95);
}
}
// Font preview in dropdowns
select#font-family,
select#font-family2 {
option[value="Lato"] {
font-family: "Lato", sans-serif;
}
option[value="Roboto"] {
font-family: "Roboto", sans-serif;
}
option[value="Open Sans"] {
font-family: "Open Sans", sans-serif;
}
option[value="Montserrat"] {
font-family: "Montserrat", sans-serif;
}
option[value="Oswald"] {
font-family: "Oswald", sans-serif;
}
option[value="Bebas Neue"] {
font-family: "Bebas Neue", display;
}
option[value="Roboto Mono"] {
font-family: "Roboto Mono", monospace;
}
option[value="VT323"] {
font-family: "VT323", monospace;
}
option[value="Press Start 2P"] {
font-family: "Press Start 2P", display;
}
}
input[type="range"] {
width: 100%;
margin-top: 0.25rem;
-webkit-appearance: none;
appearance: none;
background: rgba(0, 100, 180, 0.2);
border-radius: 4px;
height: 6px;
outline: none;
&::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 18px;
height: 18px;
background: linear-gradient(135deg, #0096ff, #66ccff);
cursor: pointer;
border-radius: 50%;
box-shadow: 0 0 10px rgba(0, 150, 255, 0.6);
border: 2px solid rgba(0, 150, 255, 0.8);
}
&::-moz-range-thumb {
width: 18px;
height: 18px;
background: linear-gradient(135deg, #0096ff, #66ccff);
cursor: pointer;
border-radius: 50%;
box-shadow: 0 0 10px rgba(0, 150, 255, 0.6);
border: 2px solid rgba(0, 150, 255, 0.8);
}
}
input[type="color"] {
width: 100%;
height: 50px;
border: 1px solid rgba(0, 150, 255, 0.4);
border-radius: 4px;
cursor: pointer;
background: rgba(5, 15, 30, 0.7);
padding: 4px;
transition: all 0.3s ease;
&:hover {
border-color: rgba(0, 150, 255, 0.7);
box-shadow: 0 0 15px rgba(0, 150, 255, 0.3);
}
}
input[type="checkbox"] {
width: auto;
margin-left: 0.5rem;
cursor: pointer;
accent-color: #0096ff;
}
}
.control-group-header {
display: flex;
justify-content: space-between;
align-items: center;
cursor: pointer;
user-select: none;
margin: 0;
padding: 0.5rem 0;
border-bottom: 2px solid;
border-image: linear-gradient(
90deg,
transparent,
rgba(0, 150, 255, 0.5),
transparent
)
1;
margin-bottom: 1rem;
color: rgba(100, 180, 255, 0.9);
font-family: Verdana, "Trebuchet MS", Tahoma, sans-serif;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.08em;
transition: all 0.3s ease;
&:hover {
color: #66ccff;
text-shadow: 0 0 10px rgba(0, 150, 255, 0.5);
}
}
.toggle-icon {
font-size: 1.5rem;
font-weight: bold;
transition: transform 0.3s ease;
color: rgba(0, 150, 255, 0.8);
}
.control-group.collapsed .toggle-icon {
transform: rotate(180deg);
}
.control-group-content {
overflow: hidden;
max-height: 2000px;
transition:
max-height 0.3s ease,
opacity 0.3s ease;
}
.control-group.collapsed .control-group-content {
max-height: 0;
opacity: 0;
pointer-events: none;
}
.info-text {
font-size: 0.85rem;
color: rgba(150, 200, 255, 0.7);
font-style: italic;
margin-bottom: 1rem;
padding: 0.5rem;
background: rgba(0, 100, 180, 0.1);
border-left: 3px solid rgba(0, 150, 255, 0.5);
border-radius: 2px;
}
h4 {
margin-top: 1.5rem;
margin-bottom: 0.75rem;
color: rgba(100, 180, 255, 0.85);
font-family: Verdana, "Trebuchet MS", Tahoma, sans-serif;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.08em;
font-size: 0.9rem;
padding-bottom: 0.5rem;
border-bottom: 1px solid rgba(0, 150, 255, 0.3);
}
.checkbox-row {
display: flex;
gap: 1.5rem;
margin-top: 0.75rem;
}
.checkbox-label {
display: flex;
align-items: center;
gap: 0.5rem;
font-weight: 500;
font-size: 0.85rem;
cursor: pointer;
margin: 0;
color: rgba(100, 180, 255, 0.8);
text-transform: uppercase;
letter-spacing: 0.05em;
transition: color 0.3s ease;
&:hover {
color: #66ccff;
}
input[type="checkbox"] {
margin: 0;
cursor: pointer;
}
span {
user-select: none;
}
}
.btn-primary,
.btn-secondary {
width: 100%;
padding: 0.75rem 1.5rem;
font-size: 0.95rem;
font-weight: 600;
border: 1px solid rgba(0, 150, 255, 0.5);
border-radius: 4px;
cursor: pointer;
transition: all 0.3s ease;
text-transform: uppercase;
letter-spacing: 0.08em;
position: relative;
overflow: hidden;
&::before {
content: "";
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(
90deg,
transparent,
rgba(0, 150, 255, 0.3),
transparent
);
transition: left 0.5s ease;
}
&:hover::before {
left: 100%;
}
}
.btn-primary {
background: linear-gradient(
135deg,
rgba(0, 120, 200, 0.3) 0%,
rgba(0, 100, 180, 0.2) 100%
);
color: #66ccff;
&:hover {
background: linear-gradient(
135deg,
rgba(0, 150, 255, 0.4) 0%,
rgba(255, 100, 0, 0.3) 100%
);
border-color: rgba(0, 150, 255, 0.8);
box-shadow:
0 0 20px rgba(0, 150, 255, 0.4),
0 0 30px rgba(255, 120, 0, 0.2);
color: #fff;
text-shadow: 0 0 10px rgba(0, 150, 255, 0.6);
transform: translateY(-2px);
}
&:active {
transform: translateY(0);
}
}
.btn-secondary {
background: linear-gradient(
135deg,
rgba(0, 100, 180, 0.2) 0%,
rgba(0, 80, 150, 0.15) 100%
);
color: #66ccff;
margin-top: 0.5rem;
&:hover {
background: linear-gradient(
135deg,
rgba(0, 120, 200, 0.3) 0%,
rgba(255, 100, 0, 0.2) 100%
);
border-color: rgba(0, 150, 255, 0.6);
transform: translateY(-2px);
box-shadow: 0 0 20px rgba(0, 150, 255, 0.3);
color: #fff;
text-shadow: 0 0 8px rgba(0, 150, 255, 0.5);
}
&:active {
transform: translateY(0);
}
}
}

View file

@ -244,6 +244,7 @@
inset 0 1px 2px rgba(255, 255, 255, 0.1);
border-radius: 1em;
cursor: pointer;
position: relative;
&::after {
content: "Interests and Tools";
@ -267,7 +268,7 @@
@include media-down(lg) {
margin-left: -0.5em;
opacity: 1;
bottom: 0;
bottom: -40px;
font-size: 20px;
}
}

View file

@ -84,7 +84,7 @@
max-width: 1400px;
margin: 0 auto;
position: relative;
z-index: 1;
z-index: 10;
}
// Portal Header with portals on either side
@ -97,7 +97,7 @@
position: relative;
.portal-title {
font-size: 3.5rem;
font-size: 2.5rem;
font-family: Verdana, "Trebuchet MS", Tahoma, sans-serif;
font-weight: 700;
text-transform: uppercase;
@ -108,11 +108,13 @@
0 0 40px rgba(255, 255, 255, 0.4),
0 2px 4px rgba(0, 0, 0, 0.3);
margin: 0;
margin-top: 50px;
position: relative;
z-index: 2;
@include media-up(md) {
font-size: 4rem;
margin-top: 0;
}
}
@ -192,7 +194,7 @@
left: 5%;
bottom: 5%;
width: 150px;
z-index: -1;
z-index: 1;
.heart-icon {
font-size: 2em;
@ -257,6 +259,7 @@
.portal-sign {
position: relative;
padding: 3rem 2rem;
z-index: 10;
border: 10px solid black;
background: white;
@ -479,6 +482,38 @@
}
}
&.button-generator {
background: #000;
height: 40%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
&::before,
&::after {
content: "";
position: absolute;
width: 90%;
height: 30%;
top: 15%;
left: 5%;
background: #fff;
animation: button 2s ease-in-out infinite;
}
&::after {
bottom: 15%;
top: auto;
left: 50%;
transform: translateX(-50%);
width: 50%;
animation: button 1.2s ease-in-out infinite;
}
}
// Last.fm stats icon
&.lastfm-stats {
background: black;
@ -503,13 +538,13 @@
&::before {
left: 20px;
height: 35px;
animation: equalizer-1 0.8s ease-in-out infinite;
animation: equalizer-1 3s ease-in-out infinite;
}
&::after {
left: 35px;
height: 25px;
animation: equalizer-2 0.8s ease-in-out infinite 0.2s;
animation: equalizer-2 1s ease-in-out infinite 0.2s;
}
}
}
@ -524,6 +559,16 @@
}
}
@keyframes button {
0%,
100% {
scale: 1;
}
50% {
scale: 0.95;
}
}
@keyframes equalizer-1 {
0%,
100% {
@ -579,7 +624,8 @@
inset 0 0 100px rgba(0, 100, 200, 0.05),
0 8px 32px rgba(0, 0, 0, 0.4);
position: relative;
overflow: hidden;
overflow: visible;
z-index: 10;
// Subtle tech panel grid pattern
&::before {
@ -699,26 +745,26 @@
&::before {
content: "";
position: absolute;
left: -4rem;
left: -2rem;
top: 50%;
transform: translateY(-50%);
width: 3rem;
height: 3px;
background: linear-gradient(90deg, transparent, #0096ff);
box-shadow: 0 0 10px rgba(0, 150, 255, 0.8);
//box-shadow: 0 0 10px rgba(0, 150, 255, 0.8);
}
// Orange line on the right
&::after {
content: "";
position: absolute;
right: -4rem;
right: -2rem;
top: 50%;
transform: translateY(-50%);
width: 3rem;
height: 3px;
background: linear-gradient(90deg, #ff7800, transparent);
box-shadow: 0 0 10px rgba(255, 120, 0, 0.8);
//box-shadow: 0 0 10px rgba(255, 120, 0, 0.8);
}
@include media-up(md) {
@ -726,15 +772,15 @@
&::before,
&::after {
width: 5rem;
width: 6rem;
}
&::before {
left: -6rem;
left: -2rem;
}
&::after {
right: -6rem;
right: -2rem;
}
}
}

View file

@ -26,6 +26,7 @@
@import "pages/blog";
@import "pages/media";
@import "pages/resources";
@import "pages/button-generator";
@import url(https://fonts.bunny.net/css?family=abel:400|barlow-condensed:400,500|caveat:400|lato:300,300i,400,400i|neonderthaw:400);

View file

@ -9,6 +9,8 @@ draft: true
- ❄️ It's been pretty cold and we've had the lightest sprinkling of snow.
- 📱 I did a mobile pass on some of the pages on this website, it works a bit better on phones now.
- 🟠 Added the [resources](/resources) section with a script to pull weekly last.fm stats (see example output below!)
- 🆒 Started working on an [88x31 button creator](/resources/button-generator/), it's got a decent amount of functionality so far.
## Links I Found Interesting

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,23 @@
---
title: "88x31 Button Creator"
date: 2026-01-08
description: "Make custom 88x31 pixel buttons with text, colors, gradients, and textures"
icon: "button-generator"
demo_url: ""
source_url: ""
draft: false
---
Welcome to my 88x31 button creator, this is a pretty rough and ready implementation so it could be buggy, please let me know if you find any issues.
This supports gif despite the basic `canvas` tag limitation courtesy of [gif.js](https://github.com/jnordberg/gif.js) - none of this would be possible without that project.
Big thanks to [neonaut's 88x31 archive](https://neonaut.neocities.org/cyber/88x31) and everyone who made the buttons that appear there. You should check it out if you need inspiration for your button!
{{< button-generator >}}
---
### Changelog
- 08/01/2025 - Initial release.

View file

@ -33,5 +33,12 @@
<main role="main">{{ block "main" . }}{{ end }}</main>
{{ block "footer" . }}{{ partial "site-footer.html" . }}{{ end }} {{ block
"scripts" . }}{{ partial "site-scripts.html" . }}{{ end }}
<!-- Button Generator - only load if page content contains button-generator shortcode -->
{{ if or (findRE "{{<\\s*button-generator" .RawContent) (findRE "{{%\\s*button-generator" .RawContent) }}
<script src="{{ "js/gif.js" | relURL }}"></script>
{{ $buttonGenerator := resources.Get "js/button-generator.js" | resources.Minify | resources.Fingerprint }}
<script src="{{ $buttonGenerator.RelPermalink }}" integrity="{{ $buttonGenerator.Data.Integrity }}"></script>
{{ end }}
</body>
</html>

View file

@ -7,7 +7,7 @@
{{ $filtered := slice }}
{{ range $remaining }}
{{ $path := .RelPermalink }}
{{ if and (not (strings.Contains $path "/terminal.js")) (not (strings.Contains $path "/init.js")) }}
{{ if and (not (strings.Contains $path "/terminal.js")) (not (strings.Contains $path "/init.js")) (not (strings.Contains $path "/button-generator.js")) }}
{{ $filtered = $filtered | append . }}
{{ end }}
{{ end }}

View file

@ -48,5 +48,8 @@
{{ end }}
</nav>
</article>
<div class="background-cube">
{{ partial "elements/companion-cube.html" . }}
</div>
</div>
{{ end }}

View file

@ -0,0 +1,607 @@
<div id="button-generator-app">
<div class="generator-container">
<div class="preview-section">
<h3>Preview</h3>
<div class="preview-container">
<div class="preview-wrapper">
<canvas id="button-canvas" width="88" height="31"></canvas>
</div>
</div>
<button id="download-button" class="btn-primary">Download Button</button>
<div class="presets-container">
<h3>Presets</h3>
<button id="preset-random" class="btn-secondary">Random Button</button>
<button id="preset-classic" class="btn-secondary">Classic Style</button>
<button id="preset-modern" class="btn-secondary">Modern Style</button>
</div>
</div>
<div class="controls-section">
<div class="control-group">
<h3 class="control-group-header">
<span>Text Line 1</span>
<span class="toggle-icon"></span>
</h3>
<div class="control-group-content">
<label for="button-text">Text</label>
<input
type="text"
id="button-text"
value="RITUAL.SH"
maxlength="20"
/>
<label class="checkbox-label">
<input type="checkbox" id="text-enabled" checked />
<span>Enable Text Line 1</span>
</label>
<label for="font-size"
>Font Size: <span id="font-size-value">14</span>px</label
>
<input type="range" id="font-size" min="6" max="24" value="14" />
<label for="text-x"
>Horizontal Position: <span id="text-x-value">50</span>%</label
>
<input type="range" id="text-x" min="0" max="100" value="50" />
<label for="text-y"
>Vertical Position: <span id="text-y-value">35</span>%</label
>
<input type="range" id="text-y" min="0" max="100" value="35" />
<label for="text-color-type">Text Color Type</label>
<select id="text-color-type">
<option value="solid">Solid Color</option>
<option value="gradient">Gradient</option>
</select>
<div id="text-solid-color">
<label for="text-color">Text Color</label>
<input type="color" id="text-color" value="#ffffff" />
</div>
<div id="text-gradient-color" style="display: none">
<label for="text-gradient-color1">Gradient Color 1</label>
<input type="color" id="text-gradient-color1" value="#ffffff" />
<label for="text-gradient-color2">Gradient Color 2</label>
<input type="color" id="text-gradient-color2" value="#00ffff" />
<label for="text-gradient-angle"
>Gradient Angle:
<span id="text-gradient-angle-value">0</span>°</label
>
<input
type="range"
id="text-gradient-angle"
min="0"
max="360"
value="0"
/>
</div>
<label class="checkbox-label">
<input type="checkbox" id="text-outline" />
<span>Outline</span>
</label>
<input
type="color"
id="outline-color"
value="#000000"
style="display: none"
/>
<label for="font-family">Font</label>
<select id="font-family">
<option value="Lato">Lato</option>
<option value="Roboto">Roboto</option>
<option value="Open Sans">Open Sans</option>
<option value="Montserrat">Montserrat</option>
<option value="Oswald">Oswald</option>
<option value="Bebas Neue">Bebas Neue</option>
<option value="Roboto Mono">Roboto Mono</option>
<option value="VT323">VT323</option>
<option value="Press Start 2P">Press Start 2P</option>
<option value="DSEG7-Classic">DSEG7</option>
</select>
<div class="checkbox-row">
<label class="checkbox-label">
<input type="checkbox" id="font-bold" />
<span>Bold</span>
</label>
<label class="checkbox-label">
<input type="checkbox" id="font-italic" />
<span>Italic</span>
</label>
</div>
</div>
</div>
<div class="control-group">
<h3 class="control-group-header">
<span>Text Line 1 Animation</span>
<span class="toggle-icon"></span>
</h3>
<div class="control-group-content">
<label class="checkbox-label">
<input type="checkbox" id="animate-text-wave" />
<span>Wave Animation</span>
</label>
<div id="wave-controls" style="display: none">
<label for="wave-amplitude"
>Amplitude: <span id="wave-amplitude-value">3</span>px</label
>
<input
type="range"
id="wave-amplitude"
min="0"
max="10"
value="3"
step="0.5"
/>
<label for="wave-speed"
>Speed: <span id="wave-speed-value">1.0</span>x</label
>
<input
type="range"
id="wave-speed"
min="0.5"
max="3"
value="1.0"
step="0.1"
/>
</div>
<label class="checkbox-label">
<input type="checkbox" id="animate-text-rainbow" />
<span>Rainbow Text</span>
</label>
<div id="rainbow-text-controls" style="display: none">
<label for="text-rainbow-speed"
>Speed: <span id="text-rainbow-speed-value">1.0</span>x</label
>
<input
type="range"
id="text-rainbow-speed"
min="0.5"
max="5"
value="1.0"
step="0.1"
/>
</div>
</div>
</div>
<div class="control-group">
<h3 class="control-group-header">
<span>Text Line 2</span>
<span class="toggle-icon"></span>
</h3>
<div class="control-group-content">
<label for="button-text2">Text</label>
<input type="text" id="button-text2" value="" maxlength="20" />
<label class="checkbox-label">
<input type="checkbox" id="text2-enabled" />
<span>Enable Text Line 2</span>
</label>
<label for="font-size2"
>Font Size: <span id="font-size2-value">12</span>px</label
>
<input type="range" id="font-size2" min="6" max="24" value="12" />
<label for="text2-x"
>Horizontal Position: <span id="text2-x-value">50</span>%</label
>
<input type="range" id="text2-x" min="0" max="100" value="50" />
<label for="text2-y"
>Vertical Position: <span id="text2-y-value">65</span>%</label
>
<input type="range" id="text2-y" min="0" max="100" value="65" />
<label for="text2-color-type">Text Color Type</label>
<select id="text2-color-type">
<option value="solid">Solid Color</option>
<option value="gradient">Gradient</option>
</select>
<div id="text2-solid-color">
<label for="text2-color">Text Color</label>
<input type="color" id="text2-color" value="#ffffff" />
</div>
<div id="text2-gradient-color" style="display: none">
<label for="text2-gradient-color1">Gradient Color 1</label>
<input type="color" id="text2-gradient-color1" value="#ffffff" />
<label for="text2-gradient-color2">Gradient Color 2</label>
<input type="color" id="text2-gradient-color2" value="#00ffff" />
<label for="text2-gradient-angle"
>Gradient Angle:
<span id="text2-gradient-angle-value">0</span>°</label
>
<input
type="range"
id="text2-gradient-angle"
min="0"
max="360"
value="0"
/>
</div>
<label class="checkbox-label">
<input type="checkbox" id="text2-outline" />
<span>Outline</span>
</label>
<input
type="color"
id="outline2-color"
value="#000000"
style="display: none"
/>
<label for="font-family2">Font</label>
<select id="font-family2">
<option value="Lato">Lato</option>
<option value="Roboto">Roboto</option>
<option value="Open Sans">Open Sans</option>
<option value="Montserrat">Montserrat</option>
<option value="Oswald">Oswald</option>
<option value="Bebas Neue">Bebas Neue</option>
<option value="Roboto Mono">Roboto Mono</option>
<option value="VT323">VT323</option>
<option value="Press Start 2P">Press Start 2P</option>
<option value="DSEG7-Classic">DSEG7</option>
</select>
<div class="checkbox-row">
<label class="checkbox-label">
<input type="checkbox" id="font-bold2" />
<span>Bold</span>
</label>
<label class="checkbox-label">
<input type="checkbox" id="font-italic2" />
<span>Italic</span>
</label>
</div>
</div>
</div>
<div class="control-group">
<h3 class="control-group-header">
<span>Text Line 2 Animation</span>
<span class="toggle-icon"></span>
</h3>
<div class="control-group-content">
<label class="checkbox-label">
<input type="checkbox" id="animate-text-wave2" />
<span>Wave Animation</span>
</label>
<div id="wave-controls2" style="display: none">
<label for="wave-amplitude2"
>Amplitude: <span id="wave-amplitude2-value">3</span>px</label
>
<input
type="range"
id="wave-amplitude2"
min="0"
max="10"
value="3"
step="0.5"
/>
<label for="wave-speed2"
>Speed: <span id="wave-speed2-value">1.0</span>x</label
>
<input
type="range"
id="wave-speed2"
min="0.5"
max="3"
value="1.0"
step="0.1"
/>
</div>
<label class="checkbox-label">
<input type="checkbox" id="animate-text-rainbow2" />
<span>Rainbow Text</span>
</label>
<div id="rainbow-text2-controls" style="display: none">
<label for="text-rainbow-speed2"
>Speed: <span id="text-rainbow-speed2-value">1.0</span>x</label
>
<input
type="range"
id="text-rainbow-speed2"
min="0.5"
max="5"
value="1.0"
step="0.1"
/>
</div>
</div>
</div>
<div class="control-group">
<h3 class="control-group-header">
<span>Background</span>
<span class="toggle-icon"></span>
</h3>
<div class="control-group-content">
<label for="bg-type">Background Type</label>
<select id="bg-type">
<option value="solid">Solid Color</option>
<option value="gradient">Gradient</option>
<option value="texture">Texture</option>
</select>
<div id="solid-controls">
<label for="bg-color">Background Color</label>
<input type="color" id="bg-color" value="#0066cc" />
</div>
<div id="gradient-controls" style="display: none">
<label for="gradient-color1">Color 1</label>
<input type="color" id="gradient-color1" value="#0066cc" />
<label for="gradient-color2">Color 2</label>
<input type="color" id="gradient-color2" value="#00ccff" />
<label for="gradient-angle"
>Angle: <span id="gradient-angle-value">90</span>°</label
>
<input
type="range"
id="gradient-angle"
min="0"
max="360"
value="90"
/>
</div>
<div id="texture-controls" style="display: none">
<label for="texture-type">Texture Pattern</label>
<select id="texture-type">
<option value="dots">Dots</option>
<option value="grid">Grid</option>
<option value="diagonal">Diagonal Lines</option>
<option value="checkerboard">Checkerboard</option>
<option value="noise">Noise</option>
<option value="stars">Stars</option>
</select>
<label for="texture-color1">Base Color</label>
<input type="color" id="texture-color1" value="#0066cc" />
<label for="texture-color2">Pattern Color</label>
<input type="color" id="texture-color2" value="#0099ff" />
<label for="texture-scale"
>Pattern Scale: <span id="texture-scale-value">50</span>%</label
>
<input
type="range"
id="texture-scale"
min="10"
max="100"
value="50"
/>
</div>
</div>
</div>
<div class="control-group">
<h3 class="control-group-header">
<span>Background Animation</span>
<span class="toggle-icon"></span>
</h3>
<div class="control-group-content">
<label class="checkbox-label">
<input type="checkbox" id="animate-bg-rainbow" />
<span>Rainbow Flash</span>
</label>
<div id="rainbow-bg-controls" style="display: none">
<label for="rainbow-speed"
>Speed: <span id="rainbow-speed-value">0.5</span>x</label
>
<input
type="range"
id="rainbow-speed"
min="0.1"
max="3"
value="0.5"
step="0.1"
/>
</div>
<label class="checkbox-label">
<input type="checkbox" id="animate-bg-rainbow-gradient" />
<span>Rainbow Gradient</span>
</label>
</div>
</div>
<div class="control-group">
<h3 class="control-group-header">
<span>Border</span>
<span class="toggle-icon"></span>
</h3>
<div class="control-group-content">
<label for="border-width"
>Border Width: <span id="border-width-value">2</span>px</label
>
<input type="range" id="border-width" min="0" max="5" value="2" />
<label for="border-color">Border Color</label>
<input type="color" id="border-color" value="#000000" />
<label for="border-style">Border Style</label>
<select id="border-style">
<option value="solid">Solid</option>
<option value="inset">Inset (3D)</option>
<option value="outset">Outset (3D)</option>
<option value="ridge">Ridge</option>
</select>
</div>
</div>
<div class="control-group">
<h3 class="control-group-header">
<span>Special Effects</span>
<span class="toggle-icon"></span>
</h3>
<div class="control-group-content">
<p class="info-text">
Almost all animations should stack, so pick as many as you want.
</p>
<label class="checkbox-label">
<input type="checkbox" id="animate-glitch" />
<span>Glitch Effect</span>
</label>
<div id="glitch-controls" style="display: none">
<label for="glitch-intensity"
>Intensity: <span id="glitch-intensity-value">3</span></label
>
<input
type="range"
id="glitch-intensity"
min="1"
max="10"
value="3"
/>
</div>
<label class="checkbox-label">
<input type="checkbox" id="animate-pulse" />
<span>Pulse Effect</span>
</label>
<div id="pulse-controls" style="display: none">
<label for="pulse-scale"
>Scale: <span id="pulse-scale-value">1.1</span>x</label
>
<input
type="range"
id="pulse-scale"
min="1.0"
max="1.3"
value="1.1"
step="0.05"
/>
</div>
<label class="checkbox-label">
<input type="checkbox" id="animate-shimmer" />
<span>Shimmer Effect</span>
</label>
<label class="checkbox-label">
<input type="checkbox" id="animate-scanline" />
<span>Scanline Effect</span>
</label>
<div id="scanline-controls" style="display: none">
<label for="scanline-intensity"
>Intensity: <span id="scanline-intensity-value">0.3</span></label
>
<input
type="range"
id="scanline-intensity"
min="0.1"
max="1"
value="0.3"
step="0.1"
/>
<label for="scanline-speed"
>Speed: <span id="scanline-speed-value">1.0</span>x</label
>
<input
type="range"
id="scanline-speed"
min="0.5"
max="3"
value="1.0"
step="0.1"
/>
</div>
<label class="checkbox-label">
<input type="checkbox" id="animate-rgb-split" />
<span>RGB Split Effect</span>
</label>
<div id="rgb-split-controls" style="display: none">
<label for="rgb-split-intensity"
>Intensity: <span id="rgb-split-intensity-value">2</span>px</label
>
<input
type="range"
id="rgb-split-intensity"
min="1"
max="5"
value="2"
step="0.5"
/>
</div>
<label class="checkbox-label">
<input type="checkbox" id="animate-noise" />
<span>Noise Effect</span>
</label>
<div id="noise-controls" style="display: none">
<label for="noise-intensity"
>Intensity: <span id="noise-intensity-value">0.1</span></label
>
<input
type="range"
id="noise-intensity"
min="0.05"
max="0.5"
value="0.1"
step="0.05"
/>
</div>
{{/*
<label class="checkbox-label">
<input type="checkbox" id="animate-rotate" />
<span>Rotate Effect</span>
</label>
<div id="rotate-controls" style="display: none">
<label for="rotate-angle"
>Max Angle: <span id="rotate-angle-value">5</span>°</label
>
<input
type="range"
id="rotate-angle"
min="2"
max="15"
value="5"
step="1"
/>
<label for="rotate-speed"
>Speed: <span id="rotate-speed-value">1.0</span>x</label
>
<input
type="range"
id="rotate-speed"
min="0.5"
max="3"
value="1.0"
step="0.1"
/>
</div>
*/}}
</div>
</div>
</div>
</div>
</div>

3
static/js/gif.js Normal file

File diff suppressed because one or more lines are too long

3
static/js/gif.worker.js Normal file

File diff suppressed because one or more lines are too long