Add settings sliders

This commit is contained in:
Andras Schmelczer 2023-05-27 15:00:04 +01:00
commit 752e1ae425
No known key found for this signature in database
GPG key ID: FC8F2C3D3D1A718C
9 changed files with 170 additions and 48 deletions

View file

@ -18,12 +18,12 @@
"plugins": ["unused-imports", "@typescript-eslint", "prettier"], "plugins": ["unused-imports", "@typescript-eslint", "prettier"],
"rules": { "rules": {
"prettier/prettier": "error", "prettier/prettier": "error",
"no-unused-vars": "off",
"unused-imports/no-unused-imports-ts": "error", "unused-imports/no-unused-imports-ts": "error",
"@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }], "@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }],
"@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/explicit-module-boundary-types": "off", "@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-non-null-assertion": "off", "@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/ban-ts-comment": "off" "@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-empty-function": "off"
} }
} }

View file

@ -49,16 +49,18 @@
<button class="restart"></button> <button class="restart"></button>
</nav> </nav>
<main class="pages hidden info-page"> <main class="pages info-page">
<h1>Title</h1> <section>
<p> <h1>Title</h1>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Eaque itaque <p>
perspiciatis nesciunt, molestiae officiis dignissimos porro! Provident totam sit Lorem ipsum dolor sit amet consectetur adipisicing elit. Eaque itaque
enim, dolores dicta possimus ex assumenda earum, ea tempore, aut quidem? perspiciatis nesciunt, molestiae officiis dignissimos porro! Provident totam
</p> sit enim, dolores dicta possimus ex assumenda earum, ea tempore, aut quidem?
</p>
</section>
</main> </main>
<main class="pages hidden settings-page"></main> <main class="pages hidden settings-page"><section></section></main>
</aside> </aside>
<script inline inline-asset="index.js" inline-asset-delete></script> <script inline inline-asset="index.js" inline-asset-delete></script>
</body> </body>

View file

@ -31,7 +31,6 @@ p {
html { html {
height: 100%; height: 100%;
-webkit-font-smooth: antialiased; -webkit-font-smooth: antialiased;
> body { > body {
width: 100%; width: 100%;
height: 100%; height: 100%;
@ -89,6 +88,7 @@ html {
top: 50%; top: 50%;
left: 0; left: 0;
transform: translateY(-50%); transform: translateY(-50%);
height: 400px;
} }
@include on-small-screen { @include on-small-screen {
@ -133,10 +133,20 @@ html {
} }
> main.pages { > main.pages {
overflow: hidden; overflow-x: hidden;
overflow-y: auto;
&::-webkit-scrollbar-track,
&::-webkit-scrollbar {
background-color: transparent;
width: 6px;
}
&::-webkit-scrollbar-thumb {
background-color: var(--main-color);
border-radius: var(--border-radius);
}
&, &,
* { > * {
transition: width var(--transition-time-long), transition: width var(--transition-time-long),
height var(--transition-time-long); height var(--transition-time-long);
@ -160,7 +170,50 @@ html {
} }
> section { > section {
margin: var(--normal-margin); padding: var(--normal-margin);
.slider {
$track-height: 12px;
margin-bottom: var(--small-margin);
p {
display: flex;
justify-content: space-between;
}
input[type='range'] {
width: 100%;
height: $track-height;
appearance: none;
background: transparent;
outline: none;
border-radius: 1000px;
&::-webkit-slider-runnable-track {
appearance: none;
cursor: pointer;
border-radius: 1000px;
@include square(15px);
background: var(--accent-color);
}
&::-webkit-slider-thumb {
appearance: none;
cursor: pointer;
border-radius: 1000px;
$size: 24px;
@include square($size);
background: white;
box-shadow: 0 0 5px 1px var(--accent-color);
transform: translateY(-5px);
transition: transform var(--transition-time);
&:hover {
transform: translateY(-5px) scale(1.1);
}
}
}
}
} }
} }
} }

View file

@ -67,14 +67,17 @@ const main = async () => {
const infoPageHandler = new CollapsiblePanelAnimator( const infoPageHandler = new CollapsiblePanelAnimator(
elements.infoButton, elements.infoButton,
elements.infoElement elements.infoElement,
elements.aside
); );
const settingsPageHandler = new CollapsiblePanelAnimator( const settingsPageHandler = new CollapsiblePanelAnimator(
elements.settingsButton, elements.settingsButton,
elements.settingsPage elements.settingsPage,
elements.aside
); );
settingsPageHandler.onOpen = infoPageHandler.close.bind(infoPageHandler); settingsPageHandler.onOpen = infoPageHandler.close.bind(infoPageHandler);
infoPageHandler.onOpen = settingsPageHandler.close.bind(settingsPageHandler); infoPageHandler.onOpen = settingsPageHandler.close.bind(settingsPageHandler);
infoPageHandler.open();
new MenuHider(elements.aside, FullScreenHandler.isInFullScreenMode); new MenuHider(elements.aside, FullScreenHandler.isInFullScreenMode);
new FullScreenHandler( new FullScreenHandler(
@ -103,9 +106,7 @@ next gen: ${formatNumber(game?.aliveAgentCounts.nextGenerationCount ?? 0)}`;
game = new GameLoop(elements.canvas, gpu, deltaTimeCalculator, gameRules); game = new GameLoop(elements.canvas, gpu, deltaTimeCalculator, gameRules);
if (!isSettingsPageSetUp) { if (!isSettingsPageSetUp) {
isSettingsPageSetUp = true; isSettingsPageSetUp = true;
setUpSettingsPage(elements.settingsPage, game.maxAgentCount, () => setUpSettingsPage(elements.settingsPage, game.maxAgentCount);
game?.destroy()
);
} }
await game.start(); await game.start();

View file

@ -6,20 +6,14 @@ export class CollapsiblePanelAnimator {
public constructor( public constructor(
infoButton: HTMLButtonElement, infoButton: HTMLButtonElement,
private readonly infoPage: HTMLElement private readonly infoPage: HTMLElement,
ignoreForCloseOnClick: HTMLElement
) { ) {
infoButton.addEventListener('click', this.toggle.bind(this)); infoButton.addEventListener('click', this.toggle.bind(this));
window.addEventListener('click', (event) => { window.addEventListener(
if ([infoButton, this.infoPage].includes(event.target as HTMLElement)) { 'click',
return; (event) => !ignoreForCloseOnClick.contains(event.target as Node) && this.close()
} );
if (this.infoPage.contains(event.target as Node)) {
return;
}
this.close();
});
} }
public open() { public open() {

View file

@ -0,0 +1,65 @@
import { settings } from '../settings';
import { SettingsSlider, ValueScaling } from '../utils/settings-slider';
export const setUpSettingsPage = (
settingsPage: HTMLDivElement,
maxAgentCount: number
) => {
const sliders = [
[
new SettingsSlider(settings, 'agentCount', {
min: 1,
max: maxAgentCount,
scaling: ValueScaling.Logarithmic,
rounding: Math.round,
}),
new SettingsSlider(settings, 'aggressionFactor', {
min: 0,
max: 10,
}),
new SettingsSlider(settings, 'nextGenerationSpawnRadius', {
min: 1,
max: 1000,
}),
new SettingsSlider(settings, 'nextGenerationSpawnInterval', {
min: 0.1,
max: 600,
}),
new SettingsSlider(settings, 'moveSpeed', {
min: 10,
max: 500,
}),
],
[
new SettingsSlider(settings, 'brushWidth', {
min: 1,
max: 60,
}),
new SettingsSlider(settings, 'brushWidthRandomness', {
min: 0,
max: 1,
}),
],
[
new SettingsSlider(settings, 'clarity', {
min: 0.1,
max: 8,
}),
],
];
sliders.forEach((sliderContainer) => {
const sliderContainerElement = document.createElement('div');
sliderContainer.forEach((slider) => {
sliderContainerElement.appendChild(slider.element);
});
settingsPage.querySelector('section').appendChild(sliderContainerElement);
});
};

View file

@ -3,23 +3,21 @@ import { AgentSettings } from './pipelines/agents/agent-settings';
import { BrushSettings } from './pipelines/brush/brush-settings'; import { BrushSettings } from './pipelines/brush/brush-settings';
import { DiffusionSettings } from './pipelines/diffusion/diffusion-settings'; import { DiffusionSettings } from './pipelines/diffusion/diffusion-settings';
import { RenderSettings } from './pipelines/render/render-settings'; import { RenderSettings } from './pipelines/render/render-settings';
import { persist } from './utils/persist';
export const settings: GameLoopSettings & export const settings: { [key: string]: number } & GameLoopSettings &
AgentSettings & AgentSettings &
BrushSettings & BrushSettings &
DiffusionSettings & DiffusionSettings &
RenderSettings = { RenderSettings = persist({
agentCount: 4_000_000, // requires restart agentCount: 1_000_000,
brushWidth: 12,
brushWidthRandomness: 0.5,
aggressionFactor: 3, aggressionFactor: 3,
nextGenerationSpawnRadius: 5, nextGenerationSpawnRadius: 5,
nextGenerationSpawnInterval: 1, nextGenerationSpawnInterval: 600,
renderSpeed: 2,
simulatedDelayMs: 0,
brushWidth: 12,
brushWidthRandomness: 5.5,
brushTrailWeight: 5, brushTrailWeight: 5,
moveSpeed: 80, moveSpeed: 80,
@ -37,5 +35,12 @@ export const settings: GameLoopSettings &
decayRateBrush: 0.003, decayRateBrush: 0.003,
clarity: 2, clarity: 2,
startColorHue: 200, startColorHue: 200,
};
maxAgentCountUpperLimit: 64_000_000, // requires restart
// debug options
renderSpeed: 1,
simulatedDelayMs: 0,
});

View file

@ -5,12 +5,10 @@
--transition-time-long: 350ms; --transition-time-long: 350ms;
--line-width: 4px; --line-width: 4px;
--line-height: 1.125rem; --line-height: 1.125rem;
--accent-color: #ff6b6b; --accent-color: rgb(6.39851188659668, 70.28645324707031, 102.23043060302734);
--sun-color: #f7f78c;
--very-light-text-color: #ffffff; --very-light-text-color: #ffffff;
--background: #ffffff; --main-color: #aaa;
--normal-text-color: #31343f; --normal-text-color: #31343f;
--card-color: #ffffff;
--blurred-card-color: transparent; --blurred-card-color: transparent;
--blur-radius: 12px; --blur-radius: 12px;
--special-text-color: var(--accent-color); --special-text-color: var(--accent-color);

View file

@ -63,11 +63,15 @@ export class SettingsSlider<T extends Record<string, number>> {
valueDisplay: HTMLSpanElement valueDisplay: HTMLSpanElement
) { ) {
const wrapper = document.createElement('div'); const wrapper = document.createElement('div');
wrapper.classList.add('slider');
const label = document.createElement('label'); const label = document.createElement('label');
label.innerText = SettingsSlider.formatLabel(name); const title = document.createElement('p');
title.innerText = SettingsSlider.formatLabel(name);
title.appendChild(valueDisplay);
label.appendChild(title);
label.appendChild(slider); label.appendChild(slider);
label.appendChild(valueDisplay);
wrapper.appendChild(label); wrapper.appendChild(label);
return wrapper; return wrapper;