Physics Simulation - Balls Bouncing in Rotating Polygon
Objective: Generate a single, self-contained HTML file demonstrating a robust physics simulation of multiple balls bouncing within a rotating regular polygon container using the HTML Canvas API.

Core Requirements:

Rendering: Use the HTML <canvas> element and its 2D rendering context (getContext('2d')) for all visual output.

HTML Structure:

Include a <canvas> element (id="simulationCanvas").

Include a <div> (id="controls") to hold user input elements.

Include a <div> (id="message") to display status messages.

CSS Styling (Embedded <style> tag):

Style the body with a pleasant background (e.g., a linear gradient) and center the content vertically and horizontally. Prevent page scrollbars. Use a common sans-serif font.

Style the #simulationCanvas: Give it a background color (e.g., semi-transparent white), rounded corners, a subtle box-shadow, and make it responsive (e.g., width: 80%; max-width: 800px; aspect-ratio: 4/3;). Set the cursor to grab and grabbing when active.

Style the #controls area: Use flexbox or grid for layout, center items, add padding, rounded corners, a semi-transparent background, and a subtle shadow. Ensure controls wrap nicely on smaller screens. Style labels and inputs for clarity and aesthetics (padding, borders, rounded corners).

Style the buttons (#resetButton, #applyButton) with clear background colors, text color, padding, rounded corners, and hover/active states.

JavaScript Logic:

Initialization (initializeSimulation):

Get references to canvas, context, and all control elements.

Read initial parameter values from the HTML controls.

Implement robust ball placement: Randomly position the specified numberOfBalls inside the polygon's initial state (rotation 0). Ensure balls do not overlap with each other initially. Use a maximum attempt limit and implement a fallback placement strategy (e.g., near the center, non-overlapping) if random placement fails repeatedly.

Assign each ball a random initial velocity (small magnitude) and a distinct color (e.g., using hsl).

Reset the polygonRotationAngle to 0.

Start the gameLoop.

Drawing (drawPolygon, drawBalls):

drawPolygon: Draw a regular polygon centered on the canvas with numberOfSides sides, using polygonSize (as radius/apothem) and the current polygonRotationAngle. Style the outline (color, line width ~3px).

drawBalls: Draw each ball as a filled circle with its assigned color and radius. Implement a subtle shadow effect for the balls (e.g., using ctx.shadowColor, shadowBlur, shadowOffsetX/Y). Ensure shadows are drawn correctly without interfering with ball colors.

Main Loop (gameLoop):

Use requestAnimationFrame for smooth animation.

Implement Physics Sub-stepping: Define a constant physicsIterations (e.g., 8-10). Inside the gameLoop, run a loop physicsIterations times, calling a dedicated physics update function (updatePhysicsStep) in each iteration. Calculate the time delta dt for each sub-step (dt = 1 / physicsIterations).

Update the polygonRotationAngle based on polygonRotationSpeed once per full frame (outside the sub-step loop).

Clear the canvas (clearRect).

Call drawPolygon and drawBalls.

Physics Update (updatePhysicsStep(dt)):

Gravity: Apply constant downward acceleration (gravity) to each ball's vy, scaled by dt.

Position Update: Update each ball's x and y based on its vx and vy, scaled by dt.

Ball-Ball Collisions:

Iterate through all unique pairs of balls.

Detect collisions (distance < sum of radii).

Position Correction: If colliding, push balls apart along the collision normal so they no longer overlap. Apply a correction factor slightly greater than 0.5 (e.g., 0.55) to prevent sticking.

Velocity Update: Calculate and apply new velocities based on 2D elastic collision formulas, using the restitution coefficient. Only apply velocity changes if balls are moving towards each other.

Ball-Polygon Collisions (Robust):

Iterate through each ball and each edge of the polygon (using the polygonRotationAngle consistent for the frame or sub-step).

For each edge, find the closest point on the edge segment (including vertices) to the ball's center.

Detect collision (distance from ball center to closest point < ball radius).

Position Correction: If colliding, calculate the collision normal (from closest point to ball center). Push the ball out along the normal to resolve the overlap. Apply a correction factor slightly greater than 1.0 (e.g., polygonCollisionCorrection = 1.01) for more robust containment.

Velocity Update: Reflect the ball's velocity based on the collision normal and the restitution coefficient. Only apply reflection if the ball's velocity component along the normal is directed towards the boundary.

Crucially: This logic must reliably prevent balls from passing through ("tunneling") the polygon boundaries, especially at the vertices, even when the polygon is rotating. The sub-stepping is the primary mechanism for this.

Event Handling:

Add event listeners to 'Reset' and 'Apply' buttons to call functions that update parameters from inputs and call initializeSimulation.

Add a resize event listener to the window. This listener should resize the canvas (maintaining aspect ratio), and then call applyChanges() or initializeSimulation() to restart the simulation correctly in the new dimensions.

Mouse Interaction: Implement mousedown, mousemove, and mouseup/mouseleave listeners on the canvas to allow users to click and drag balls. When a ball is being dragged, disable its physics updates (gravity, velocity changes, collision response) and set its position directly based on mouse movement. Restore physics when the mouse is released. Change the cursor style (grab/grabbing) appropriately.

Customizable Parameters (via HTML Inputs):

numberOfSides (Integer, Default: 5, Min: 3, Max: 12)

numberOfBalls (Integer, Default: 10, Min: 1, Max: 50)

ballRadius (Number, Default: 10, Min: 5, Max: 20)

polygonSize (Number, Default: 150, Min: 50, Max: 400)

polygonRotationSpeed (Number, Default: 0.01, Step: 0.001, Represents rad/frame)

gravity (Number, Default: 0.1, Step: 0.01, Represents px/step^2)
restitution (Number, Default: 0.8, Min: 0, Max: 1, Step: 0.01)

Output: A single, self-contained .html file.

Code Quality: Include clear and thorough comments in the JavaScript code, explaining the setup, drawing logic, physics calculations (especially sub-stepping, collision detection, position correction, and velocity updates for both collision types), and event handling