This commit is contained in:
PaulK 2024-11-19 10:12:02 +01:00
commit acea5ba561
29 changed files with 1139 additions and 0 deletions

11
.editorconfig Normal file
View File

@ -0,0 +1,11 @@
# editorconfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

194
.gitattributes vendored Normal file
View File

@ -0,0 +1,194 @@
## GITATTRIBUTES FOR WEB PROJECTS
#
# These settings are for any web project.
#
# Details per file setting:
# text These files should be normalized (i.e. convert CRLF to LF).
# binary These files are binary and should be left untouched.
#
# Note that binary is a macro for -text -diff.
######################################################################
## AUTO-DETECT
## Handle line endings automatically for files detected as
## text and leave all files detected as binary untouched.
## This will handle all files NOT defined below.
* text=auto
## SOURCE CODE
*.bat text eol=crlf
*.coffee text
*.css text
*.htm text
*.html text
*.inc text
*.ini text
*.js text
*.json text
*.jsx text
*.less text
*.od text
*.onlydata text
*.php text
*.pl text
*.py text
*.rb text
*.sass text
*.scm text
*.scss text
*.sh text eol=lf
*.sql text
*.styl text
*.tag text
*.ts text
*.tsx text
*.xml text
*.xhtml text
## DOCKER
*.dockerignore text
Dockerfile text
## DOCUMENTATION
*.markdown text
*.md text
*.mdwn text
*.mdown text
*.mkd text
*.mkdn text
*.mdtxt text
*.mdtext text
*.txt text
AUTHORS text
CHANGELOG text
CHANGES text
CONTRIBUTING text
COPYING text
copyright text
*COPYRIGHT* text
INSTALL text
license text
LICENSE text
NEWS text
readme text
*README* text
TODO text
## TEMPLATES
*.dot text
*.ejs text
*.haml text
*.handlebars text
*.hbs text
*.hbt text
*.jade text
*.latte text
*.mustache text
*.njk text
*.phtml text
*.tmpl text
*.tpl text
*.twig text
## LINTERS
.babelrc text
.csslintrc text
.eslintrc text
.htmlhintrc text
.jscsrc text
.jshintrc text
.jshintignore text
.prettierrc text
.stylelintrc text
## CONFIGS
*.bowerrc text
*.cnf text
*.conf text
*.config text
.browserslistrc text
.editorconfig text
.gitattributes text
.gitconfig text
.gitignore text
.htaccess text
*.npmignore text
*.yaml text
*.yml text
browserslist text
Makefile text
makefile text
## HEROKU
Procfile text
.slugignore text
## GRAPHICS
*.ai binary
*.bmp binary
*.eps binary
*.gif binary
*.ico binary
*.jng binary
*.jp2 binary
*.jpg binary
*.jpeg binary
*.jpx binary
*.jxr binary
*.pdf binary
*.png binary
*.psb binary
*.psd binary
*.svg text
*.svgz binary
*.tif binary
*.tiff binary
*.wbmp binary
*.webp binary
## AUDIO
*.kar binary
*.m4a binary
*.mid binary
*.midi binary
*.mp3 binary
*.ogg binary
*.ra binary
## VIDEO
*.3gpp binary
*.3gp binary
*.as binary
*.asf binary
*.asx binary
*.fla binary
*.flv binary
*.m4v binary
*.mng binary
*.mov binary
*.mp4 binary
*.mpeg binary
*.mpg binary
*.ogv binary
*.swc binary
*.swf binary
*.webm binary
## ARCHIVES
*.7z binary
*.gz binary
*.jar binary
*.rar binary
*.tar binary
*.zip binary
## FONTS
*.ttf binary
*.eot binary
*.otf binary
*.woff binary
*.woff2 binary
## EXECUTABLES
*.exe binary
*.pyc binary

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
# Include your project-specific ignores in this file
# Read about how to use .gitignore: https://help.github.com/articles/ignoring-files
# Useful .gitignore templates: https://github.com/github/gitignore
node_modules
dist
.cache

8
.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

9
.idea/RC_Car.iml generated Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

6
.idea/misc.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

8
.idea/modules.xml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/RC_Car.iml" filepath="$PROJECT_DIR$/.idea/RC_Car.iml" />
</modules>
</component>
</project>

62
404.html Normal file
View File

@ -0,0 +1,62 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Page Not Found</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
* {
line-height: 1.2;
margin: 0;
}
html {
color: #888;
display: table;
font-family: sans-serif;
height: 100%;
text-align: center;
width: 100%;
}
body {
display: table-cell;
vertical-align: middle;
margin: 2em auto;
}
h1 {
color: #555;
font-size: 2em;
font-weight: 400;
}
p {
margin: 0 auto;
width: 280px;
}
@media only screen and (max-width: 280px) {
body,
p {
width: 95%;
}
h1 {
font-size: 1.5em;
margin: 0 0 0.3em;
}
}
</style>
</head>
<body>
<h1>Page Not Found</h1>
<p>Sorry, but the page you were trying to view does not exist.</p>
</body>
</html>
<!-- IE needs 512+ bytes: https://docs.microsoft.com/archive/blogs/ieinternals/friendly-http-error-pages -->

19
LICENSE.txt Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) HTML5 Boilerplate
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

BIN
arrow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

24
connect.py Normal file
View File

@ -0,0 +1,24 @@
from flask import Flask, render_template, request
import bluetooth
app = Flask(__name__)
# Bluetooth-Geräte in der Nähe scannen
def scan_devices():
nearby_devices = bluetooth.discover_devices(duration=8, lookup_names=True)
devices = [(addr, name) for addr, name in nearby_devices]
return devices
@app.route('/')
def index():
devices = scan_devices()
return render_template('controller.html', devices=devices)
@app.route('/connect', methods=['POST'])
def connect():
selected_device = request.form['device']
# Hier fügst du den Code hinzu, um dich mit dem ausgewählten Gerät zu verbinden
return f"Connecting to device: {selected_device}"
if __name__ == '__main__':
app.run(debug=True)

19
controller.html Normal file
View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bluetooth Controller Auswahl</title>
</head>
<body>
<h1>Verfügbare Bluetooth-Controller</h1>
<form action="/connect" method="post">
<select name="controller">
{% for addr, name in controllers %}
<option value="{{ addr }}">{{ name }}</option>
{% endfor %}
</select>
<button type="submit">Verbinden</button>
</form>
</body>
</html>

BIN
controller.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

247
css/style.css Normal file
View File

@ -0,0 +1,247 @@
/*! HTML5 Boilerplate v9.0.0-RC1 | MIT License | https://html5boilerplate.com/ */
/* main.css 3.0.0 | MIT License | https://github.com/h5bp/main.css#readme */
/*
* What follows is the result of much research on cross-browser styling.
* Credit left inline and big thanks to Nicolas Gallagher, Jonathan Neal,
* Kroc Camen, and the H5BP dev community and team.
*/
/* ==========================================================================
Base styles: opinionated defaults
========================================================================== */
html {
color: #222;
font-size: 1em;
line-height: 1.4;
}
/*
* Remove text-shadow in selection highlight:
* https://twitter.com/miketaylr/status/12228805301
*
* Customize the background color to match your design.
*/
::-moz-selection {
background: #b3d4fc;
text-shadow: none;
}
::selection {
background: #b3d4fc;
text-shadow: none;
}
/*
* A better looking default horizontal rule
*/
hr {
display: block;
height: 1px;
border: 0;
border-top: 1px solid #ccc;
margin: 1em 0;
padding: 0;
}
/*
* Remove the gap between audio, canvas, iframes,
* images, videos and the bottom of their containers:
* https://github.com/h5bp/html5-boilerplate/issues/440
*/
audio,
canvas,
iframe,
img,
svg,
video {
vertical-align: middle;
}
/*
* Remove default fieldset styles.
*/
fieldset {
border: 0;
margin: 0;
padding: 0;
}
/*
* Allow only vertical resizing of textareas.
*/
textarea {
resize: vertical;
}
/* ==========================================================================
Author's custom styles
========================================================================== */
/* ==========================================================================
Helper classes
========================================================================== */
/*
* Hide visually and from screen readers
*/
.hidden,
[hidden] {
display: none !important;
}
/*
* Hide only visually, but have it available for screen readers:
* https://snook.ca/archives/html_and_css/hiding-content-for-accessibility
*
* 1. For long content, line feeds are not interpreted as spaces and small width
* causes content to wrap 1 word per line:
* https://medium.com/@jessebeach/beware-smushed-off-screen-accessible-text-5952a4c2cbfe
*/
.visually-hidden {
border: 0;
clip: rect(0, 0, 0, 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
white-space: nowrap;
width: 1px;
/* 1 */
}
/*
* Extends the .visually-hidden class to allow the element
* to be focusable when navigated to via the keyboard:
* https://www.drupal.org/node/897638
*/
.visually-hidden.focusable:active,
.visually-hidden.focusable:focus {
clip: auto;
height: auto;
margin: 0;
overflow: visible;
position: static;
white-space: inherit;
width: auto;
}
/*
* Hide visually and from screen readers, but maintain layout
*/
.invisible {
visibility: hidden;
}
/*
* Clearfix: contain floats
*
* The use of `table` rather than `block` is only necessary if using
* `::before` to contain the top-margins of child elements.
*/
.clearfix::before,
.clearfix::after {
content: "";
display: table;
}
.clearfix::after {
clear: both;
}
/* ==========================================================================
EXAMPLE Media Queries for Responsive Design.
These examples override the primary ('mobile first') styles.
Modify as content requires.
========================================================================== */
@media only screen and (min-width: 35em) {
/* Style adjustments for viewports that meet the condition */
}
@media print,
(-webkit-min-device-pixel-ratio: 1.25),
(min-resolution: 1.25dppx),
(min-resolution: 120dpi) {
/* Style adjustments for high resolution devices */
}
/* ==========================================================================
Print styles.
Inlined to avoid the additional HTTP request:
https://www.phpied.com/delay-loading-your-print-css/
========================================================================== */
@media print {
*,
*::before,
*::after {
background: #fff !important;
color: #000 !important;
/* Black prints faster */
box-shadow: none !important;
text-shadow: none !important;
}
a,
a:visited {
text-decoration: underline;
}
a[href]::after {
content: " (" attr(href) ")";
}
abbr[title]::after {
content: " (" attr(title) ")";
}
/*
* Don't show links that are fragment identifiers,
* or use the `javascript:` pseudo protocol
*/
a[href^="#"]::after,
a[href^="javascript:"]::after {
content: "";
}
pre {
white-space: pre-wrap !important;
}
pre,
blockquote {
border: 1px solid #999;
page-break-inside: avoid;
}
tr,
img {
page-break-inside: avoid;
}
p,
h2,
h3 {
orphans: 3;
widows: 3;
}
h2,
h3 {
page-break-after: avoid;
}
}

BIN
favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

BIN
handy.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

1
icon.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 192 192"><path fill="#e08524" d="M75.3 73.4H18.4l45.3 34.3L48.3 163l46.1-32.3 48.2 34.6-16.9-58.3 44.9-33.6H115l-20.5-55-19.2 55z"/><path d="m96.7 18.8 18.2 8.2 16.5 44.3h-15.1L96.7 18.8zm-47 146 18.7 9.9 42.6-29.9-16.5-11.4-44.8 31.4zm79.1-56.8 17.4 9.4 18.6 60.1-19.7-11.3-16.3-58.2z"/><path d="m173.1 74.3 17.8 9.2-44.7 34-17.4-9.4 44.3-33.8z"/></svg>

After

Width:  |  Height:  |  Size: 429 B

0
img/.gitkeep Normal file
View File

90
index.html Normal file
View File

@ -0,0 +1,90 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mein Menü</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
.menu {
background-color: #333;
overflow: hidden;
}
.menu a {
float: left;
display: block;
color: white;
text-align: center;
padding: 14px 16px;
text-decoration: none;
}
.menu a:hover {
background-color: #ddd;
color: black;
}
.content {
padding: 20px;
}
.hidden {
display: none;
}
#control img {
max-width: 25%;
height: auto;
cursor: pointer; /* Hinzugefügt, um den Mauszeiger zu ändern */
}
</style>
</head>
<body>
<div class="menu">
<a href="#" onclick="showContent('home')">Startseite</a>
<a href="#" onclick="showContent('control')">Steuerung</a>
</div>
<div id="home" class="content">
<h2>Startseite</h2>
<p>Willkommen auf der Startseite!</p>
</div>
<!-- Bild -->
<div id="control" class="content hidden">
<h2>Steuerung</h2>
<p>Wählen Sie ein Steuergerät!</p>
<a href="joystick.html" style="position: absolute; top: 250px; left: 200px;">
<img src="handy.jpg" alt="Handy Bild" style="width: 250px; height: 100px;">
</a>
<a href="controller.html" style="position: absolute; top: 450px; left: 200px">
<img src="controller.jpg" alt="Controller Bild" style="width: 400px; height: 90px;">
</a>
</div>
<script>
function showContent(id) {
// Alle Inhalte ausblenden
var contents = document.getElementsByClassName("content");
for (var i = 0; i < contents.length; i++) {
contents[i].classList.add("hidden");
}
// Nur das angeklickte Element anzeigen
var element = document.getElementById(id);
if (element) {
element.classList.remove("hidden");
}
}
</script>
</body>
</html>

343
joystick.html Normal file
View File

@ -0,0 +1,343 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Circular Control Stick</title>
<style>
body {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
margin: 0;
background-color: #f0f0f0; /* Change the background color as needed */
}
#control-container {
position: relative;
width: 400px; /* Adjust the overall size as needed */
height: 400px; /* Adjust the overall size as needed */
border-radius: 50%;
border: 2px solid black; /* Outline style for the outer circle */
box-sizing: border-box;
touch-action: none; /* Disable touch actions to prevent scrolling on touch devices */
overflow: hidden; /* Hide the overflow of the lines */
}
#inner-stick {
position: absolute;
width: 80px; /* Adjust the inner control stick size as needed */
height: 80px; /* Adjust the inner control stick size as needed */
background-color: black; /* Filled color for the inner circle */
border-radius: 50%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
touch-action: none; /* Disable touch actions on the inner stick */
user-select: none; /* Disable text selection on the inner stick */
}
.line {
position: absolute;
width: 100%;
height: 2px;
background-color: black;
transform-origin: 50% 50%;
left: 0;
top: 50%;
}
.line:nth-child(1) {
transform: rotate(22.5deg);
}
.line:nth-child(2) {
transform: rotate(67.5deg);
}
.line:nth-child(3) {
transform: rotate(112.5deg);
}
.line:nth-child(4) {
transform: rotate(157.5deg);
}
.line:nth-child(5) {
transform: rotate(202.5deg);
}
.line:nth-child(6) {
transform: rotate(247.5deg);
}
.line:nth-child(7) {
transform: rotate(292.5deg);
}
.line:nth-child(8) {
transform: rotate(337.5deg);
}
.text {
position: absolute;
width: 100%;
text-align: center;
font-size: 15px;
color: black;
transform-origin: 50% 50%;
}
#text-forward {
top: 5px;
}
#text-forward-right {
top: 25%;
left: 20%;
transform: rotate(-45deg);
}
#text-forward-left {
top: 25%;
right: 20%;
transform: rotate(45deg);
}
#text-right {
left: 45%;
top: 50%;
transform: translateY(-50%) rotate(-90deg);
}
#text-left {
right: 45%;
top: 50%;
transform: translateY(-50%) rotate(90deg);
}
#text-backward {
bottom: 5px;
}
#text-backward-right {
bottom: 25%;
left: 20%;
transform: rotate(45deg);
}
#text-backward-left {
bottom: 25%;
right: 20%;
transform: rotate(-45deg);
}
</style>
</head>
<body>
<!-- Image clickable -->
<a href="index.html" style="position: absolute; top: 10px; left: 10px;">
<img src="arrow.png" alt="Klickbarer Pfeil" style="width: 150px; height: 100px;">
</a>
<div id="control-container">
<!-- Lines to divide the outer circle -->
<div class="line"></div>
<div class="line"></div>
<div class="line"></div>
<div class="line"></div>
<!-- Text elements -->
<div class="text" id="text-forward">Forward</div>
<div class="text" id="text-forward-left">Forward-Left</div>
<div class="text" id="text-forward-right">Forward-Right</div>
<div class="text" id="text-left">Left</div>
<div class="text" id="text-right">Right</div>
<div class="text" id="text-backward">Backward</div>
<div class="text" id="text-backward-left">Backward-Left</div>
<div class="text" id="text-backward-right">Backward-Right</div>
<!-- Inner stick -->
<div id="inner-stick"></div>
</div>
<script>
// JavaScript for handling control stick movement
var controlContainer = document.getElementById('control-container');
var innerStick = document.getElementById('inner-stick');
// Variables to store the initial position and touch/mouse state
var initialX, initialY, isTouched = false;
// Event listeners for touch events
innerStick.addEventListener('touchstart', handleTouchStart);
innerStick.addEventListener('touchmove', handleTouchMove);
innerStick.addEventListener('touchend', handleTouchEnd);
// Event listeners for mouse events
innerStick.addEventListener('mousedown', handleMouseDown);
window.addEventListener('mousemove', handleMouseMove);
window.addEventListener('mouseup', handleMouseUp);
// Touch event handlers
function handleTouchStart(event) {
isTouched = true;
var touch = event.touches[0];
initialX = touch.clientX - controlContainer.offsetLeft;
initialY = touch.clientY - controlContainer.offsetTop;
}
function handleTouchMove(event) {
if (!isTouched) return;
var touch = event.touches[0];
var currentX = touch.clientX - controlContainer.offsetLeft;
var currentY = touch.clientY - controlContainer.offsetTop;
moveInnerStick(currentX, currentY);
sendCommandBasedOnSector(currentX, currentY);
event.preventDefault();
if (event.touches.length == 0) {
resetInnerStickPosition();
}
}
function handleTouchEnd() {
isTouched = false;
resetInnerStickPosition();
}
// Mouse event handlers
function handleMouseDown(event) {
isTouched = true;
initialX = event.clientX - controlContainer.offsetLeft;
initialY = event.clientY - controlContainer.offsetTop;
}
function handleMouseMove(event) {
if (!isTouched) return;
var currentX = event.clientX - controlContainer.offsetLeft;
var currentY = event.clientY - controlContainer.offsetTop;
moveInnerStick(currentX, currentY);
sendCommandBasedOnSector(currentX, currentY);
if (!event.buttons) {
resetInnerStickPosition();
}
}
function handleMouseUp() {
isTouched = false;
resetInnerStickPosition();
}
// Function to move the inner stick
function moveInnerStick(x, y) {
var deltaX = x - initialX;
var deltaY = y - initialY;
// Ensure the inner stick stays within the bounds of the container
var distance = Math.min(
Math.hypot(deltaX, deltaY),
controlContainer.clientWidth / 2 - innerStick.clientWidth / 2
);
var angle = Math.atan2(deltaY, deltaX);
var newX = Math.cos(angle) * distance + controlContainer.clientWidth / 2;
var newY = Math.sin(angle) * distance + controlContainer.clientHeight / 2;
innerStick.style.left = newX + 'px';
innerStick.style.top = newY + 'px';
}
// Function to reset the inner stick to the center
function resetInnerStickPosition() {
innerStick.style.left = '50%';
innerStick.style.top = '50%';
sendCommand('/move/stop');
}
var lastcommand;
// Function to send a command (replace with actual command logic)
function sendCommand(command) {
if (lastcommand !== command) {
lastcommand = command;
console.log('Command Sent:', command);
// Vollständige URL zum Flask-Server
var url = 'http://192.168.4.1:5000' + command; // Bitte die IP-Adresse und Portnummer anpassen
// AJAX-Anfrage erstellen
var xhr = new XMLHttpRequest();
xhr.open('POST', url, true); // URL anpassen, um sie an Ihren Server anzupassen
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
console.log('Command successfully sent to server:' + command);
} else {
console.error('Failed to send command to server.');
}
}
};
xhr.send();
}
}
// ich hab dich gaaaaaanz dolle lieb bubu, ich bin super stolz auf dich, du machst das echt super duper toll
// Function to log the inner stick position to the console
function sendCommandBasedOnSector(x, y) {
var deltaX = x - controlContainer.clientWidth / 2;
var deltaY = y - controlContainer.clientHeight / 2;
// Calculate the angle of the inner stick
var angle = Math.atan2(deltaY, deltaX);
var angleDeg = (angle * 180) / Math.PI;
// Convert negative angles to positive for simplicity
if (angleDeg < 0) {
angleDeg += 360;
}
// Determine the sector based on the angle
var sector = Math.floor((angleDeg + 22.5) / 45) % 8;
// Send a command based on the sector
switch (sector) {
case 0: // Right
sendCommand('/move/right');
break;
case 1: // Back-Right
sendCommand('/move/back-right');
break;
case 2: // Back
sendCommand('/move/back');
break;
case 3: // Back-Left
sendCommand('/move/back-left');
break;
case 4: // Left
sendCommand('/move/left');
break;
case 5: // Front-Left
sendCommand('/move/front-left');
break;
case 6: // Forward
sendCommand('/move/Front');
break;
case 7: // Front-Right
sendCommand('/move/front-right');
break;
}
}
</script>
</body>
</html>

0
js/app.js Normal file
View File

0
js/vendor/.gitkeep vendored Normal file
View File

24
package.json Normal file
View File

@ -0,0 +1,24 @@
{
"name": " ",
"version": "0.0.1",
"description": "",
"private": true,
"keywords": [
""
],
"license": "",
"author": "",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack serve --open --config webpack.config.dev.js",
"build": "webpack --config webpack.config.prod.js"
},
"devDependencies": {
"copy-webpack-plugin": "^11.0.0",
"html-webpack-plugin": "^5.5.3",
"webpack": "^5.88.2",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1",
"webpack-merge": "^5.9.0"
}
}

5
robots.txt Normal file
View File

@ -0,0 +1,5 @@
# www.robotstxt.org/
# Allow crawling of all content
User-agent: *
Disallow:

12
site.webmanifest Normal file
View File

@ -0,0 +1,12 @@
{
"short_name": "",
"name": "",
"icons": [{
"src": "icon.png",
"type": "image/png",
"sizes": "192x192"
}],
"start_url": "/?utm_source=homescreen",
"background_color": "#fafafa",
"theme_color": "#fafafa"
}

12
webpack.common.js Normal file
View File

@ -0,0 +1,12 @@
const path = require('path');
module.exports = {
entry: {
app: './js/app.js',
},
output: {
path: path.resolve(__dirname, 'dist'),
clean: true,
filename: './js/app.js',
},
};

13
webpack.config.dev.js Normal file
View File

@ -0,0 +1,13 @@
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
devServer: {
liveReload: true,
hot: true,
open: true,
static: ['./'],
},
});

26
webpack.config.prod.js Normal file
View File

@ -0,0 +1,26 @@
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
module.exports = merge(common, {
mode: 'production',
plugins: [
new HtmlWebpackPlugin({
template: './index.html',
}),
new CopyPlugin({
patterns: [
{ from: 'img', to: 'img' },
{ from: 'css', to: 'css' },
{ from: 'js/vendor', to: 'js/vendor' },
{ from: 'icon.svg', to: 'icon.svg' },
{ from: 'favicon.ico', to: 'favicon.ico' },
{ from: 'robots.txt', to: 'robots.txt' },
{ from: 'icon.png', to: 'icon.png' },
{ from: '404.html', to: '404.html' },
{ from: 'site.webmanifest', to: 'site.webmanifest' },
],
}),
],
});