}
.game-upintheair.font-atkinson * {
font-family: 'Atkinson Hyperlegible' !important;
+ font-size-adjust: 0.45;
}
.game-upintheair.font-opendyslexic * {
font-family: 'OpenDyslexic' !important;
margin-top: 1em;
text-align: center;
}
+ .ui-page .area.twocol {
+ flex-grow: 1;
+ display: flex;
+ flex-direction: row;
+ gap: 2em;
+ }
+ .ui-page .area.twocol .column {
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+ justify-content: space-between;
+ gap: 1ex;
+ }
+ .ui-page .area.twocol .column:last-child {
+ width: 40%;
+ flex-grow: 0;
+ flex-shrink: 0;
+ }
+ .ui-page.options .feather {
+ flex-grow: 1;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-evenly;
+ align-items: center;
+ }
+ .ui-page.options .feather input {
+ position: absolute;
+ left: -99999px;
+ width: 1px;
+ height: 1px;
+ opacity: 0;
+ }
+ .ui-page.options .feather img {
+ width: 6em;
+ margin: -1em 0;
+ transition: 150ms transform;
+ }
+ .ui-page.options .feather img {
+ transform: translateX(-1em);
+ }
+ .ui-page.options .feather input:checked + img {
+ transform: translateX(1em);
+ }
+ .ui-page.options .feather label:hover img, .ui-page.options .feather label:focus-within img {
+ filter:
+ drop-shadow(-.1em -.1em 0 #fff)
+ drop-shadow(.1em -.1em 0 #fff)
+ drop-shadow(.1em .1em 0 #fff)
+ drop-shadow(-.1em .1em 0 #fff);
+ }
.ui-page.loading {
display: flex;
flex-direction: column;
align-items: center;
gap: 1em;
}
+ .ui-page.options .area.accessibility {
+ display: none;
+ }
+ .ui-page.options .areatabs {
+ margin-bottom: -1em;
+ display: flex;
+ align-items: center;
+ gap: 1ex;
+ }
+ .ui-page.options .areatabs button {
+ font-size: 1.6em;
+ background: #000b;
+ color: #fff;
+ font-family: 'Jersey 10';
+ border: none;
+ border-radius: 1em 1em 0 0;
+ cursor: pointer;
+ }
+ .ui-page.options .areatabs button.active {
+ padding-bottom: .7em;
+ }
.ui-page.options button {
width: 8em;
padding: .45em .6em;
}
.ui-page input[type=range] {
font-size: 1em;
- accent-color: #f998a6;
+ accent-color: #c50031;
+ }
+ .ui-page input[type=radio], .ui-page input[type=checkbox] {
+ width: 1.3em;
+ height: 1.3em;
+ margin: .2em 0;
+ font-size: 1em;
+ vertical-align: sub;
+ accent-color: #c50031;
}
.ui-page.options .area button {
padding: .3em;
font-size: 1em;
font-family: 'Jersey 10';
}
+ .ui-page.options .controls p:last-child {
+ margin-top: 1em;
+ padding-right: 1em;
+ height: 4em;
+ }
+ .ui-page.options .controls p:last-child span:not(:first-child) {
+ display: none;
+ }
+ .ui-page.options .graphics *:not(.audio) label {
+ display: inline;
+ margin-left: 1ex;
+ }
+ .ui-page.options p.annotation {
+ margin-left: 1.6em;
+ }
+ .ui-page.options label.standardfont {
+ font-family: 'Jersey 10' !important;
+ font-size-adjust: 0.45;
+ }
+ .ui-page.options label.atkinson {
+ font-family: 'Atkinson Hyperlegible' !important;
+ font-size-adjust: 0.45;
+ }
+ .ui-page.options label.opendyslexic {
+ font-family: OpenDyslexic !important;
+ font-size-adjust: 0.4;
+ }
+ .ui-page.options div.difficulty p:nth-child(4) {
+ margin-top: 1ex;
+ }
.ui-page .audio {
display: grid;
gap: .5ex 1ex;
.ui-page.options .audio {
grid-template-columns: auto auto auto;
}
+ .ui-page.options .audio h3 {
+ grid-column: 1 / 4;
+ }
.ui-page.pause .audio {
grid-template-columns: auto auto;
color: #fff;
justify-content: end;
gap: 1ex;
}
+ .ui-page.options *:not(.audio) > label {
+ display: flex;
+ align-items: center;
+ justify-content: start;
+ gap: 1ex;
+ width: max-content;
+ }
+ .ui-page.options .keyboard {
+ display: flex;
+ flex-direction: column;
+ gap: 1ex;
+ }
+ .ui-page.options .keyboard label:not(:nth-child(8)) {
+ width: 8em;
+ margin: 0 auto;
+ display: flex;
+ justify-content: flex-end;
+ }
+ .ui-page.options .keyboard label button {
+ box-sizing: border-box;
+ width: 5em;
+ }
.ui-page .audio input[type=range] {
width: 8em;
}
</div>
<div class="ui-page options options-general">
<h2>Options</h2>
-<div class="area">
+<div class="areatabs">
+<button class="general active">General</button>
+<button class="accessibility">Accessibility</button>
+</div>
+<div class="area twocol general">
+<div class="column">
+<div class="controls">
+<h3>Controls</h3>
+<p><label><input type="radio" name="upInTheAirGame-controls" value="mouse" checked> Mouse movement</label></p>
+<p><label><input type="radio" name="upInTheAirGame-controls" value="touchpad"> Virtual touchpad</label></p>
+<p><label><input type="radio" name="upInTheAirGame-controls" value="thumbstick"> Virtual thumbstick</label></p>
+<p><label><input type="radio" name="upInTheAirGame-controls" value="keyboard"> Keyboard</label></p>
+<p><label><input type="radio" name="upInTheAirGame-controls" value="gamepad"> Gamepad</label></p>
+<p>
+<span class="mouse">The game is controlled by moving the mouse cursor around directly in the play area.</span>
+<span class="touchpad">The game is controlled through touch movements on an on-screen touchpad. Movements correspond directly to the play area.</span>
+<span class="thumbstick">The game is controlled through touch movements on an on-screen thumbstick. Directional movements steer the cursor.</span>
+<span class="keyboard">The game is controlled through arrow or WASD key presses. Key rebinding and additional accessibility options are available.</span>
+<span class="gamepad">The game is controlled with the thumbstick or d-pad of an attached gamepad accessory.</span>
+</p>
+</div>
+<div class="graphics">
+<h3>Graphics</h3>
+<p>Quality:
+<label><input type="radio" name="upInTheAirGame-font" value="standard" checked> Full</label>
+<label><input type="radio" name="upInTheAirGame-font" value="standard" checked> Reduced</label>
+<label><input type="radio" name="upInTheAirGame-font" value="standard" checked> Minimal</label>
+</div>
<div class="audio">
+<h3>Audio</h3>
<label>Music:
<input type="range" min="0" max="100" value="50" step="1" class="music"></label>
<span>50</span>
<span>50</span>
<button class="sounds">Test</button>
</div>
-<p><label>Font: <select class="font">
+</div>
+
+<div class="column">
+<h3>Feather Customization</h3>
+<p>You can change the feather’s visual appearance. This is an aesthetic choice with no impact on the game mechanics.</p>
+<div class="feather">
+<label><input type="radio" name="upInTheAirGame-feather" value="blue" checked><img src="textures/feather.png" alt="Blue feather"></label>
+<label><input type="radio" name="upInTheAirGame-feather" value="red"><img src="textures/feather.png" alt="Red feather"></label>
+<label><input type="radio" name="upInTheAirGame-feather" value="green"><img src="textures/feather.png" alt="Green feather"></label>
+<label><input type="radio" name="upInTheAirGame-feather" value="black"><img src="textures/feather.png" alt="Black feather"></label>
+<label><input type="radio" name="upInTheAirGame-feather" value="brown"><img src="textures/feather.png" alt="Brown feather"></label>
+</div>
+</div>
+</div>
+
+
+<div class="area twocol accessibility">
+<div class="column">
+<div>
+<h3>Visuals</h3>
+<label><input type="checkbox" value="highcontrast"> High contrast mode</label>
+<p class="annotation">Render collectibles as bright green dots, replace clouds with dark background.</p>
+</div>
+<div>
+<h3>Font</h3>
+<p><label class="standardfont"><input type="radio" name="upInTheAirGame-font" value="standard" checked> Standard</label></p>
+<p><label class="atkinson"><input type="radio" name="upInTheAirGame-font" value="atkinson"> Atkinson Hyperlegible</label></p>
+<p><label class="opendyslexic"><input type="radio" name="upInTheAirGame-font" value="opendyslexic"> OpenDyslexic</label></p>
+</div>
+<div class="difficulty">
+<h3>Difficulty</h3>
+<p><label>Collecting radius: <select class="collectingradius">
<option value="standard" selected>Standard</option>
-<option value="atkinson">Atkinson Hyperlegible</option>
-<option value="opendyslexic">OpenDyslexic</option>
+<option value="generous">Generous</option>
+<option value="eager">Eager</option>
+</select></label></p>
+<p class="annotation">This setting adjusts how close you need to get to a collectible in order to pick it up.</p>
+<p><label>Gameplay speed: <select class="gameplayspeed">
+<option value="100" selected>100 %</option>
+<option value="50">50 %</option>
+<option value="25">25 %</option>
+<option value="10">10 %</option>
</select></label></p>
+<p class="annotation">This setting adjusts the speed of the gameplay clock – movement through the course and the feather’s physics will be slower.</p>
+</div>
+</div>
+
+<div class="column">
+<div class="keyboard">
+<h3>Keyboard Settings</h3>
+<p>These settings only have an effect if keyboard controls are enabled.</p>
+<label>Up: <button class="up" value="Arrow up|w">🠕 or W</button></label>
+<label>Right: <button class="right" value="Arrow right|d">🠖 or D</button></label>
+<label>Down: <button class="down" value="Arrow down|s">🠗 or S</button></label>
+<label>Left: <button class="left" value="Arrow left|a">🠔 or A</button></label>
+<button value="reset">Reset to default</button>
+<label><input type="checkbox" value="tapmode"> Tap mode</label>
+<p class="annotation">With this setting enabled, movement gets triggered by tapping the keys instead of holding them. Tap a direction multiple times to accelerate, tap the opposite direction to stop.</p>
+</div>
+</div>
</div>
+
+
<button class="goto title">Back</button>
</div>
<div class="ui-page credits">
}
});
});
-function checkFontSelection(select) {
+function checkFontSelection() {
+ const checked = document.querySelector('input[name=upInTheAirGame-font]:checked');
+ if(!checked) {
+ return;
+ }
+ const newFont = checked.value;
game.ui.root.classList.remove('font-atkinson', 'font-opendyslexic');
- const newFont = select.value;
if(newFont != 'standard') {
game.ui.root.classList.add('font-' + newFont);
}
}
-checkFontSelection(game.ui.root.querySelector('.options select.font'));
-game.ui.root.querySelector('.options select.font').addEventListener('change', e => checkFontSelection(e.target));
+checkFontSelection();
+game.ui.root.querySelectorAll('.options input[name=upInTheAirGame-font]').forEach((radio) => {
+ radio.addEventListener('change', e => checkFontSelection());
+});
+game.ui.root.querySelectorAll('.options .controls input').forEach((radio) => {
+ radio.addEventListener('change', (e) => {
+ e.target.closest('.controls').querySelectorAll('span:not(.' + e.target.value + ')').forEach(span => span.style.display = 'none');
+ e.target.closest('.controls').querySelector('span.' + e.target.value).style.display = 'block';
+ });
+});
+game.ui.root.querySelectorAll('.ui-page .areatabs button').forEach((btn) => {
+ btn.addEventListener('click', (e) => {
+ btn.parentNode.querySelectorAll('button').forEach((otherBtn) => {
+ otherBtn.classList.remove('active');
+ let val = otherBtn.classList[0];
+ otherBtn.closest('.ui-page').querySelector('div.' + val).style.display = 'none';
+ });
+ btn.classList.add('active');
+ let val = Array.from(btn.classList).filter(c => c != 'active')[0];
+ btn.closest('.ui-page').querySelector('div.' + val).style.display = 'flex';
+ });
+});
game.ui.moveToPage = (target, skipFade = false) => {
let fadeDuration = 250;
if(skipFade) {