"Compilation error: 'function' does not name a type; did you mean 'union'?"

Whenever i try to upload my code im getting this error

C:\Users\MercuryWoman\Desktop\esp32car\esp32car.ino:105:1: error: 'function' does not name a type; did you mean 'union'?
105 | function sendCommand(x, y) {
| ^~~~~~~~
| union
exit status 1

Compilation error: 'function' does not name a type; did you mean 'union'?

#include <WiFi.h>
#include <WebServer.h>
#include <WebSocketsServer.h>
#include <SparkFun_TB6612.h>

// ================= MOTOR PINS =================
#define AIN1 40
#define AIN2 39
#define PWMA 38
#define BIN1 42
#define BIN2 2
#define PWMB 1
#define STBY 41

Motor rightMotor1(AIN1, AIN2, PWMA, 1, STBY);
Motor rightMotor2(BIN1, BIN2, PWMB, 1, STBY);

#define LAIN1 16
#define LAIN2 15
#define LPWMA 17
#define LBIN1 6
#define LBIN2 5
#define LPWMB 4
#define LSTBY 7

Motor leftMotor1(LAIN1, LAIN2, LPWMA, 1, LSTBY);
Motor leftMotor2(LBIN1, LBIN2, LPWMB, 1, LSTBY);

// ================= WIFI =================
const char* ssid = "ESP32_Car";
const char* password = "12345678";

// ================= SERVERS =================
WebServer server(80);            // HTTP server for page
WebSocketsServer webSocket(81);  // WebSocket server for control

// ================= MOTOR CONTROL =================
void driveMotors(int x, int y) {
  int maxSpeed = 255;
  int leftMotorSpeed  = constrain(y + x, -maxSpeed, maxSpeed);
  int rightMotorSpeed = constrain(y - x, -maxSpeed, maxSpeed);

  leftMotor1.drive(leftMotorSpeed);
  leftMotor2.drive(leftMotorSpeed);
  rightMotor1.drive(rightMotorSpeed);
  rightMotor2.drive(rightMotorSpeed);
}

// ================= WEBSOCKET EVENT =================
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
  if(type == WStype_TEXT) {
    String data = String((char*)payload);
    int comma = data.indexOf(',');
    if(comma > 0) {
      int x = data.substring(0, comma).toInt();
      int y = data.substring(comma + 1).toInt();
      driveMotors(x, y);
    }
  }
}

// ================= HTML PAGE =================
const char* htmlPage = R"HTML(
<!DOCTYPE html>
<html>
<head>
  <title>ESP32 Joystick Control</title>
  <style>
    body { font-family: Arial; text-align: center; margin-top: 50px; }
    #joystickContainer {
      position: relative;
      width: 200px;
      height: 200px;
      margin: auto;
      background: #ddd;
      border-radius: 50%;
      touch-action: none;
    }
    #joystick {
      position: absolute;
      width: 80px;
      height: 80px;
      background: #666;
      border-radius: 50%;
      top: 60px;
      left: 60px;
      touch-action: none;
    }
  </style>
</head>
<body>
<h1>ESP32 Joystick Control</h1>
<div id="joystickContainer">
  <div id="joystick"></div>
</div>

<script>
let ws = new WebSocket("ws://" + location.hostname + ":81/");
let joystick = document.getElementById('joystick');
let container = document.getElementById('joystickContainer');
let centerX = container.offsetWidth / 2;
let centerY = container.offsetHeight / 2;
let maxRange = 80; // max joystick movement in px

function sendCommand(x, y) {
  let motorX = Math.round((x / maxRange) * 255);
  let motorY = Math.round((-y / maxRange) * 255);
  if(ws.readyState === WebSocket.OPEN) {
    ws.send(motorX + "," + motorY);
  }
}

let dragging = false;
joystick.addEventListener('pointerdown', () => { dragging = true; });
document.addEventListener('pointerup', () => { 
  dragging = false; 
  joystick.style.left = (centerX - joystick.offsetWidth/2) + 'px';
  joystick.style.top = (centerY - joystick.offsetHeight/2) + 'px';
  sendCommand(0, 0);
});
document.addEventListener('pointermove', (e) => {
  if(!dragging) return;
  let rect = container.getBoundingClientRect();
  let x = e.clientX - rect.left - centerX;
  let y = e.clientY - rect.top - centerY;

  let dist = Math.sqrt(x*x + y*y);
  if(dist > maxRange) {
    x = x / dist * maxRange;
    y = y / dist * maxRange;
  }

  joystick.style.left = (centerX + x - joystick.offsetWidth/2) + 'px';
  joystick.style.top = (centerY + y - joystick.offsetHeight/2) + 'px';

  sendCommand(x, y);
});
</script>
</body>
</html>
)HTML";

// ================= SETUP =================
void setup() {
  Serial.begin(115200);

  // WiFi AP
  WiFi.softAP(ssid, password);
  Serial.print("AP IP address: ");
  Serial.println(WiFi.softAPIP());

  // Serve webpage
  server.on("/", []() {
    server.send(200, "text/html", htmlPage);
  });
  server.begin();

  // WebSocket
  webSocket.begin();
  webSocket.onEvent(webSocketEvent);
}

// ================= LOOP =================
void loop() {
  server.handleClient();
  webSocket.loop();
}

Put your HTML in an include file (e.g. myPage.h) and include it with `#include "myPage.h". It might solve your problem, not sure.

let maxRange = 80; // max joystick movement in px

Is this a valid HTML line, bearing in mind that // is used for comments in C++ whereas that is not how you add comments to HTML ?

nope it just breaks its entirely

Reducing things to a MRE:

void setup() {
}

void loop() {
}

const char* htmlPage = R"HTML(
");
function sendCommand(x, y) {}
)HTML";

Fails with the same error.

(and Geany picks up 'sendCommand' as a function)

This works.

void setup() {
}

void loop() {
}

const char* htmlPage = R""(
");
function sendCommand(x, y) {}
)"";

yup found something similar for the fixthe fix

Interestingly, this compiles:

const char* htmlPage = R"HTML(
");
function sendCommand(x, y) {}
)HTML";

void setup() {
}

void loop() {
}

Leading me to wonder if the problem isn't the behind the scenes work the Arduino ecosystem does to add prototypes for functions in the .ino file. It's not quite understanding how raw strings work, it appears.