Add settings sliders
This commit is contained in:
parent
cd9aff0362
commit
752e1ae425
9 changed files with 170 additions and 48 deletions
|
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
11
src/index.ts
11
src/index.ts
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
||||||
|
|
|
||||||
65
src/page/set-up-settings-page.ts
Normal file
65
src/page/set-up-settings-page.ts
Normal 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);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
@ -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,
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue