CALCULAGAMES STUDIO
Code Workspace
Write JavaScript, run it, and see what happens.
Sign in or sign up to save to your library. Anyone can test code here.
Connect a coding agent
Bring your own assistant to this sandbox project. Its code changes arrive as proposals for you to review.
Terms of Service · Agent privacy · Help & support
Save an adult library project to connect an agent.
Connect through MCP
Add this remote MCP server in your assistant’s connector settings. Choose CalculaGames sign-in when prompted, then authorize one adult project.
For ChatGPT and Claude, use a custom MCP connector where your account supports it. For Gemini, use an MCP-capable client such as Gemini CLI. Availability depends on the assistant and account; a chat message alone does not establish a connection.
Connection guide & API reference ↗Or use a project token
For clients with an Authorization header setting. Tokens expire after 30 days and can be disconnected below. Put credentials in your client’s protected settings, not in chat or project code.
Open this panel to check your adult project connection.
Connected agents
Proposed code changes
Review the source before applying. Applying does not run the code or save it to your library.
Code editor
Your editor starts blank. Test code freely; saving requires a verified account.
Game preview
Untitled project
Write code on the left, then press Test game.
About this game
Add a full description in Project details to introduce your game and explain how to play.
LEARN AS YOU BUILD
Workspace reference
The canvas and CalculaGames helpers are ready inside your preview.
Canvas and drawing
canvas is the 800 × 600 HTML canvas. ctx is its 2D drawing context. The top-left corner is (0, 0).
ctx.fillStyle = "#148eb0"; ctx.fillRect(100, 100, 140, 90); ctx.beginPath(); ctx.arc(400, 300, 35, 0, Math.PI * 2); ctx.fill();
For WebGL, use GL.init(canvas) before accessing ctx or creating a 2D context. A canvas can use one context type at a time.
Mouse, touch, and animation
mouseX and mouseY are pointer coordinates on the canvas; cursorX, cursorY, and mouseDown come from cursor.js. Position updates as the pointer moves.
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "#1a91ac";
ctx.beginPath();
ctx.arc(mouseX, mouseY, 20, 0, Math.PI * 2);
ctx.fill();
requestAnimationFrame(draw);
}
draw();Press Stop test or Test game again to reset the preview.
2D helpers · SVGHelper.js
Call SVGHelper.createContext() first. Its draw method starts an animation loop.
SVGHelper.createContext();
SVGHelper.draw(() => {
SVGHelper.background_color("white");
SVGHelper.ellipse(cursorX, cursorY, 20, 20, "#169da3", true);
SVGHelper.text("Hello!", 400, 80, 24, "#12485a");
});Other helpers include line, rect, triangle, quad, arc, image, translate, rotate, and scale.
Buttons · buttons.js
Positions use proportions of the preview container: 0.5 is halfway across or down. A button appears over the canvas.
const start = new Button({
x: 0.5, y: 0.8, label: "Start",
onPress: () => console.log("Started!")
});
start.createButton();Methods include setLabel, setPosition, setStyle, hide, show, and destroy.
Fields and menus
Field creates an input over the canvas. Menu and Label are available from menus.js.
const nameField = new Field({
x: 0.5, y: 0.5, label: "Player nickname",
onSubmit: value => console.log(value)
});
nameField.createField();Fields also have getValue(), setValue(value), hide(), show(), and destroy().
WebGL and other helpers
WGLHelper.js supplies GL, Mat4, Mat5, Vec3, Vec4, Camera, Mesh, Scene, and more.
GL.init(canvas); GL.clear(0.1, 0.6, 0.8, 1);
gameHelper.js adds discreetGameLoop({step, draw, stepTime}) and snapToGrid(x, y, stepX, stepY). All seven files in JS_INFRASTRUCTURE are loaded for each run.
Full documentation
Syntax, working examples, and the complete public helper reference from all seven JS_INFRASTRUCTURE files. Expand a topic below; use your browser’s Find to locate a method.
Start here · JavaScript syntax
Paste JavaScript directly into the editor; do not add HTML or <script> tags. Names are case-sensitive: Button and button differ. Run one example at a time in a new project. These helpers are ordinary JavaScript, already loaded before your code.
| Syntax | How to use it |
|---|---|
const speed = 3; | A binding you do not reassign. An object stored in const can still change its properties. |
let score = 0; score += 1; | A variable whose value changes. |
const player = {x: 100, y: 200}; | An object; read or change player.x. |
const points = [10, 20, 30]; | An array; first item is points[0]. Use points.length for its size. |
function move(x) { return x + 2; } | A function; call move(10) to obtain 12. |
onPress: button => { score += 1; } | A callback: pass a function for the helper to call later. |
if (score >= 10) { /* ... */ } | A condition. Use === for equality, && for AND, || for OR, ! for NOT. |
for (let i = 0; i < 5; i++) { /* ... */ } | Repeat a bounded number of times. An endless while loop freezes the preview. |
new Button({x: 0.5, y: 0.8, label: "Go"}) | Construct an instance using an options object. Call its creation method to display it. |
// comment | Notes ignored by JavaScript. Strings use quotes; booleans are true and false. |
Math.PI; Math.random(); Math.sin(angle); | Built-in math. Random returns a number from 0 inclusive to 1 exclusive. Trigonometry uses radians. |
Canvas, input, testing & saving
| Syntax | How to use it |
|---|---|
canvas | The preview’s HTML canvas, initially 800 × 600. Read canvas.width and canvas.height; WebGL resizing can change them. |
ctx | Lazy access to canvas.getContext("2d"). Use either 2D or WebGL on a canvas, not both. |
mouseX, mouseY | Read-only current pointer position in canvas pixels; updated on pointer move and press, including touch. Initially 0. |
cursorX, cursorY | Legacy cursor.js coordinates in canvas pixels, updated on mouse move / touch move. Touch start alone does not update these coordinates. |
mouseDown | Legacy mouse/touch held flag. Mouse release outside the canvas clears it. Prefer pointer events for custom touch controls. |
trackCursor(canvas) | Already called by cursor.js for gameCanvas. Calling again on the same canvas adds duplicate listeners. |
requestAnimationFrame(draw) | Schedule a drawing callback for the next animation frame; its time argument is milliseconds. |
console.log(value) | Print diagnostics to the editor output. Thrown errors also appear below the preview. |
Ctrl / ⌘ + Enter | Test game. Each run creates a fresh isolated preview, resetting variables, UI elements and loops. |
Test game page / Save & view game | Test opens an unsaved game page. Save & view saves to your eligible account/profile library before opening the game page. |
Anyone can test. Saving requires a verified account; child profiles also require confirmed parental permission. Title, brief description, and full description belong to the project. New project starts blank. Stop test removes the running preview.
The preview blocks network requests and external scripts, fonts, and remote images. Use self-contained code and data: or blob: image URLs. Normal page access, account data, and local storage are unavailable to the sandbox. No imports are needed for the seven bundled helpers.
Native 2D drawing & keyboard input
| Syntax | How to use it |
|---|---|
ctx.fillStyle = "#168eac" | Set a CSS fill color. |
ctx.fillRect(x, y, width, height) | Draw a filled rectangle from its top-left corner. |
ctx.clearRect(0, 0, canvas.width, canvas.height) | Erase the frame before redrawing. |
ctx.beginPath(); ctx.arc(x, y, radius, start, end); ctx.fill(); | Draw a filled circle with end = Math.PI * 2. Use ctx.stroke() for an outline. |
ctx.save(); ctx.restore(); | Save and restore styles, transforms, and clipping. |
window.addEventListener("keydown", event => { ... }) | Read event.key or event.code. Click the preview first so keyboard events reach it. Use keyup to clear held keys. |
let x = 100;
const keys = new Set();
window.addEventListener("keydown", e => { keys.add(e.key); if(e.key.startsWith("Arrow")) e.preventDefault(); });
window.addEventListener("keyup", e => keys.delete(e.key));
window.addEventListener("blur", () => keys.clear());
let last = performance.now();
function draw(now) {
const dt = Math.min((now - last) / 1000, 0.05);
last = now;
if (keys.has("ArrowRight")) x += 180 * dt;
if (keys.has("ArrowLeft")) x -= 180 * dt;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "#168eac";
ctx.fillRect(x, 260, 60, 60);
requestAnimationFrame(draw);
}
requestAnimationFrame(draw);2D helper · SVGHelper.js
Despite the filename, this helper draws into a Canvas 2D context, not SVG markup. Every method below has the SVGHelper. prefix. Coordinates and widths are canvas pixels; positive y points down. Shape fill defaults to false. Styles and transforms can persist between calls.
| Syntax | How to use it |
|---|---|
SVGHelper.createContext() | Initialize the 2D context; returns the native context. Call before any other drawing helper. |
SVGHelper.background_color(color) | Fill the entire canvas with a CSS color. |
SVGHelper.line(x1, y1, x2, y2, color = "black", width = 1) | Stroke a segment. |
SVGHelper.ellipse(x, y, rx, ry, color = "black", fill = false, strokeWidth = 1) | Center and two radii. Set fill to true for a solid ellipse. |
SVGHelper.rect(x, y, w, h, color = "black", fill = false) | Rectangle anchored at its top-left corner. |
SVGHelper.triangle(x1, y1, x2, y2, x3, y3, color = "black", fill = false) | Three vertices; closes the path. |
SVGHelper.quad(x1, y1, x2, y2, x3, y3, x4, y4, color = "black", fill = false) | Four vertices in perimeter order. |
SVGHelper.arc(x, y, rad, start, end, color = "black", width = 1) | Stroke a circular arc; angles in radians. |
SVGHelper.text(str, x, y, size = 16, color = "black", font = "Arial", align = "center") | Draw text, vertically centered at y. Size is pixels; align can be left, center, or right. |
SVGHelper.image(img, x, y, size, mode = "width", vertAlign = "center", horzAlign = "center", angle = 0, pivotOffset = null) | Draw a loaded Image, maintaining aspect ratio. mode width sizes the width; use height for height. Vertical: top/center/bottom; horizontal: left/center/right. angle is radians. Optional pivotOffset is {x,y}, rotated with angle. |
SVGHelper.save() / restore() | Save/restore the underlying context state. |
SVGHelper.translate(x, y) | Move the drawing origin by pixels. |
SVGHelper.rotate(angle) | Rotate around the current origin, in radians. |
SVGHelper.scale(sx, sy) | Scale subsequent coordinates. Pass both axes. |
SVGHelper.clipRect(x, y, w, h) | Clip subsequent drawing to a rectangle. Wrap with save/restore. |
SVGHelper.draw(callback) | Start an animation loop calling callback with no arguments. Start only once; use Stop test to reset. |
SVGHelper.createContext();
SVGHelper.draw(() => {
SVGHelper.background_color("#ecfbff");
SVGHelper.ellipse(mouseX, mouseY, 24, 24, "#168eac", true);
SVGHelper.text("Follow the pointer", 400, 60, 24, "#16506c");
});SVGHelper.createContext();
const picture = new Image();
picture.onload = () => SVGHelper.image(picture, 400, 300, 160);
picture.src = "data:image/svg+xml," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80"><circle cx="40" cy="40" r="35" fill="skyblue"/></svg>');Fields · fields.js
| Syntax | How to use it |
|---|---|
new Field({x, y, label = "", value = "", onSubmit, onChange, style = {}}) | Centered fractional position, like Button. Text input and an OK button. Use a made-up nickname or game value rather than personal information. |
field.createField() | Create the overlay. onChange(value, field) runs on input; onSubmit(value, field) runs when OK is clicked. |
field.getValue() / setValue(value) | Read/set the stored value. setValue does not call onChange automatically. Input values are strings; use Number(value) when needed. |
field.hide() / show() / destroy() | Hide, show as flex, or remove. |
field.applyStyles(element) | Apply current style to an element. Supported keys: width, padding, background, color, border, borderRadius, gap. Use CSS units. The helper forces a centered column flex layout. |
field.domElement / inputElement | Created wrapper and native input, available after createField(). |
const amount = new Field({
x: 0.5, y: 0.5, label: "Number of stars", value: "5",
style: {width: "220px", padding: "16px", background: "#ddf7ff", borderRadius: "12px"},
onSubmit: value => console.log("Stars:", Number(value))
});
amount.createField();Game timing & grids · gameHelper.js
| Syntax | How to use it |
|---|---|
discreetGameLoop({step, draw, stepTime = 1000}) | Exact spelling is discreet. Fixed simulation step in milliseconds; step() can run multiple times to catch up, then draw() runs once per animation frame. Neither receives arguments. Keep stepTime positive. Start one loop per run. |
snapToGrid(x, y, stepX, stepY) | Returns {x,y} rounded to the closest grid intersection. Pass nonzero positive spacings. Does not mutate input or draw anything. |
let point = {x: 0, y: 0};
discreetGameLoop({
stepTime: 100,
step: () => { point = snapToGrid(mouseX, mouseY, 40, 40); },
draw: () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "#168eac";
ctx.fillRect(point.x, point.y, 20, 20);
}
});WebGL setup, shaders & rendering · WGLHelper.js
Initialize WebGL before reading ctx or calling SVGHelper.createContext(). WebGL is browser/device dependent. This library uses WebGL 1, flat color shaders and position-only meshes; it does not provide lighting, texture materials, physics, or a complete game engine.
| Syntax | How to use it |
|---|---|
GL.init(canvas) | Acquire WebGL context, resize viewport, return GL; throws if unavailable. GL.gl is the native context; GL.canvas, GL.width, GL.height expose current dimensions. |
GL.resize() | Match drawing buffer to displayed canvas size (CSS pixels), then update viewport. |
GL.clear(r, g, b, a) | Clear color and depth buffers. Color components use 0–1, not 0–255. |
GL.enableDepthTest() / disableDepthTest() | Enable/disable depth comparison. Enable for solid 3D scenes. |
GL.startRenderLoop(callback) / stopRenderLoop() | callback(time) receives animation-frame milliseconds; resize runs before it. Stop the current loop before starting another. |
GL.createShader(type, source) | Compile GLSL with GL.gl.VERTEX_SHADER or FRAGMENT_SHADER; returns shader or null and logs errors. |
GL.createProgram(vertexSource, fragmentSource) | Compile/link GLSL source strings; returns program or null. |
GL.createDefaultShaders() | Create the current model/view/projection color shader in GL.shaders.color. Call before constructing default RenderObjects. Earlier shader definition in the file is superseded by this one. |
GL.shaders.color | Contains program, attributes.position, and uniforms.model/view/projection/color. |
GL.render(scene, cameraArgument) | Calls scene.render(cameraArgument); see the controller adapter below. |
GL.startSceneLoop(scene, cameraArgument, callback) | Optional callback(time) updates objects before GL.render. Uses the same render loop; stop with GL.stopRenderLoop(). |
Current compatibility detail: RenderObject.draw reads cameraController.viewMatrix from its argument and camera.getProjectionMatrix() from a global named camera. A plain Camera instance does not supply viewMatrix. The example supplies both deliberately; use this pattern with the current library.
GL.init(canvas);
GL.enableDepthTest();
GL.createDefaultShaders();
const camera = new Camera({position: {x: 0, y: 0, z: 5}});
const view = {viewMatrix: camera.getViewMatrix()};
const scene = new Scene();
scene.clearColor = {r: 0.85, g: 0.96, b: 1, a: 1};
const cube = new RenderObject({mesh: Mesh.createCube(1.5), color: {r: 0.05, g: 0.55, b: 0.8, a: 1}});
scene.add(cube);
GL.startSceneLoop(scene, view, time => {
cube.transform.rotation.y = time * 0.001;
cube.transform.rotation.x = time * 0.0006;
view.viewMatrix = camera.getViewMatrix();
});Cameras, transforms, meshes & scenes
| Syntax | How to use it |
|---|---|
new Camera(options = {}) / Camera.create(options) | position:{x,y,z}, rotation:{x,y,z}; or x/y/z and rx/ry/rz. Defaults position/rotation 0, fov π/4 radians, near 0.1, far 1000. Looks down −Z at zero rotation. |
camera.getProjectionMatrix() / getViewMatrix() | Perspective from current GL aspect; inverse camera translation/rotation. |
camera.screenPointToRay(x, y) | Canvas-pixel coordinate to a Ray; current implementation applies X/Y rotation, not roll (Z rotation). |
new Ray(origin, direction) / ray.getPoint(distance) | Plain {x,y,z} vectors; direction is normalized. Returns point along ray. |
new Transform() | Mutable position/rotation {x,y,z}, scale {x:1,y:1,z:1}, parent, children, matrix. Angles radians. |
transform.setParent(parent) / getLocalMatrix() / updateMatrix() | Parent may be null. Local matrix is translation × Rz × Ry × Rx × scale. updateMatrix combines parent and recursively updates children; update roots before descendants. Avoid parenting cycles. |
new Mesh({mode: GL.gl.TRIANGLES}) | Create GPU buffers after GL.init. Other modes include GL.gl.LINES. |
mesh.uploadVertices(vertices) / uploadIndices(indices) | Flat XYZ numbers and optional 16-bit unsigned vertex indices. Keep indices within 0–65535 and existing vertices. |
mesh.bind(positionLocation) / draw() | Bind position attribute and issue native WebGL draw; normally handled by RenderObject. |
Mesh.createCube(size = 1) | Centered solid cube. |
Mesh.createPlane(width = 1, depth = 1) | Centered plane in XZ (y = 0). |
Mesh.createSphere(radius = 1, latBands = 16, lonBands = 16) | Solid sphere. Positive integer band counts; keep vertex count within index limits. |
new RenderObject({mesh, transform, shader, color, boundingRadius, onClick}) | Default transform is new Transform; shader is GL.shaders.color; color is {r:1,g:1,b:1,a:1}. boundingRadius defaults 1; selected starts false. |
object.draw(controller) / intersectsRay(ray) | Draw with current compatibility adapter; ray test returns a boolean for a bounding sphere, not exact triangle intersection. Update transform matrices first. Radius does not automatically follow mesh size/scale. |
new Scene() / scene.add(object) / remove(object) / clear() | Maintain scene.objects; add returns the object. clear removes membership, not GPU resources. scene.clearColor defaults opaque black. |
scene.render(controller) | Clear buffers then draw each object; does not choose or update a camera controller for you. |
GL.createCameraController(options = {}) | Returns position, forward, up, rotation quaternion, viewMatrix and setFrame(position, rotation). Current options argument is unused. No mouse orbit listeners are installed. |
controller.setFrame(position, rotation) | Supply {x,y,z} position and normalized {x,y,z,w} quaternion; recomputes viewMatrix. Keep global camera projection and picking state consistent with your controller. |
Vector & matrix syntax · 3D and 4D
Vec3 uses {x,y,z}; Vec4 uses {x,y,z,w}. Operations return new values. Mat4 is 16 numbers for homogeneous 3D; Mat5 is 25 numbers for homogeneous 4D. Matrix arrays are column-major. In Vec4, w is a fourth spatial coordinate when used with Mat5; in Mat4.multiplyVec4 it is the homogeneous coordinate.
| Syntax | How to use it |
|---|---|
Mat4.identity() | Return a new identity Float32Array. |
Mat4.transpose(m) | Return the transpose. |
Mat4.multiply(a, b) | Return a × b; column-major storage. Rightmost transform acts first. |
Mat4.multiplyVec4(m, v) | Multiply a 4×4 matrix by {x,y,z,w}; use w=1 for a point or 0 for a direction. |
Mat4.translation(x, y, z) | 3D translation matrix. |
Mat4.scale(x, y, z) | Vector: multiply each component by s. Matrix: independent axis scales. |
Mat4.rotationX(angle) | Rotation matrix in the named axis/plane, angle in radians. |
Mat4.rotationY(angle) | Rotation matrix in the named axis/plane, angle in radians. |
Mat4.rotationZ(angle) | Rotation matrix in the named axis/plane, angle in radians. |
Mat4.perspective(fov, aspect, near, far) | Perspective matrix. fov in radians; aspect = width / height, 0 < near < far. |
Mat5.identity() | Return a new identity Float32Array. |
Mat5.multiply(a, b) | Return a × b; column-major storage. Rightmost transform acts first. |
Mat5.transformVec4(matrix, vector) | Transform a 4D {x,y,z,w} point using a 5×5 homogeneous matrix. |
Mat5.rotationXY(angle) | Rotation matrix in the named axis/plane, angle in radians. |
Mat5.rotationXZ(angle) | Rotation matrix in the named axis/plane, angle in radians. |
Mat5.rotationXW(angle) | Rotation matrix in the named axis/plane, angle in radians. |
Mat5.rotationYZ(angle) | Rotation matrix in the named axis/plane, angle in radians. |
Mat5.rotationYW(angle) | Rotation matrix in the named axis/plane, angle in radians. |
Mat5.rotationZW(angle) | Rotation matrix in the named axis/plane, angle in radians. |
Vec3.create(x = 0, y = 0, z = 0) | Return a plain vector object with named components. |
Vec3.add(a, b) | Return component-wise a + b. |
Vec3.subtract(a, b) | Return component-wise a − b. |
Vec3.scale(v, s) | Vector: multiply each component by s. Matrix: independent axis scales. |
Vec3.dot(a, b) | Return scalar dot product. |
Vec3.length(v) | Return Euclidean magnitude. |
Vec3.normalize(v) | Return unit vector (zero input returns a zero vector). |
Vec4.create(x = 0, y = 0, z = 0, w = 0) | Return a plain vector object with named components. |
Vec4.add(a, b) | Return component-wise a + b. |
Vec4.subtract(a, b) | Return component-wise a − b. |
Vec4.scale(v, s) | Vector: multiply each component by s. Matrix: independent axis scales. |
Vec4.dot(a, b) | Return scalar dot product. |
Vec4.length(v) | Return Euclidean magnitude. |
Vec4.normalize(v) | Return unit vector (zero input returns a zero vector). |
const velocity = Vec3.create(1, 2, 0);
const next = Vec3.add(Vec3.create(0, 0, 0), Vec3.scale(velocity, 0.5));
console.log(next); // {x: 0.5, y: 1, z: 0}
const rotated = Mat5.transformVec4(Mat5.rotationXW(Math.PI / 4), Vec4.create(1, 0, 0, 0));
console.log(rotated);4D projection & tesseracts
| Syntax | How to use it |
|---|---|
GL.project4Dto3D(point, distance = 4) | Project {x,y,z,w} into {x,y,z} using distance / (distance − w). Keep distance away from point.w to avoid singularities. |
GL.transformVertices4D(vertices, matrix) | Array of 4D point objects → new array of transformed 4D points. |
GL.projectVertices4D(vertices, distance = 4) | Array of 4D points → flat [x,y,z,...] 3D vertex data. |
Mesh.createTesseract(size = 1) | Wireframe 4D hypercube projected to 3D. Creates vertices4D, edges and cells metadata, plus updateTesseract. |
mesh.updateTesseract(rotationMatrix = Mat5.identity(), projectionDistance = 4) | Reproject original 4D vertices and upload line vertices. Call each animation frame to change its 4D orientation. cells contains axis, side, vertex indices and random colors; the default wireframe shader does not draw those cell colors. |
To adapt the cube example, use Mesh.createTesseract(1.5) and call cube.mesh.updateTesseract(Mat5.rotationXW(time * 0.001), 4) inside its callback. This is geometric projection, not a 4D physics engine.
Picking, quaternion utilities & current limitations
GL.enablePicking(scene, camera, canvas) installs mouse/touch press handlers and expects scene.pick(camera,x,y). The current Scene class does not implement pick, so this convenience function needs your own scene.pick implementation. It is not a ready-to-use picker. For a simple custom selector, use rays and bounding spheres:
// Add after the WebGL cube example. This chooses the first hit,
// not the nearest object; adapt for overlapping objects.
canvas.addEventListener("pointerdown", () => {
const ray = camera.screenPointToRay(mouseX, mouseY);
for (const object of scene.objects) object.transform.updateMatrix();
const hit = scene.objects.find(object => object.intersectsRay(ray));
for (const object of scene.objects) object.selected = object === hit;
if (hit && hit.onClick) hit.onClick(hit);
console.log(hit ? "Object selected" : "No hit");
});| Syntax | How to use it |
|---|---|
normalize(v) / cross(a, b) / dot(a, b) | Global 3D utilities. cross returns the cross product; normalize returns a zero vector for zero input. |
quatFromBasis(forward, up) | Construct a {x,y,z,w} orientation quaternion from nonzero, nonparallel direction vectors. |
quatFromAxisAngle(axis, angle) | Quaternion from a nonzero 3D axis and radians. |
quatMultiply(a, b) | Compose quaternions; order matters. |
quatRotate(q, v) | Rotate a 3D vector by a unit quaternion. |
matFromQuat(q) | Convert a unit quaternion to a column-major 4×4 Float32Array. |
Rendering currently depends on the global camera/controller adapter explained above. Picking is approximate, has no built-in nearest-hit sorting, and does not automatically change an object’s color when selected. No automatic disposal API exists for Mesh; use Stop test to reset the preview.
Troubleshooting & choosing a helper
| Syntax | How to use it |
|---|---|
Blank canvas | Check error output. Drawing runs only after Test game. In 2D, initialize SVGHelper before using it. In WebGL, initialize GL, shaders, camera/controller and scene. |
Context is null / WebGL cannot start | A previous 2D context may own the canvas. Test again and use only WebGL calls in that run. Device support also varies. |
A control does not appear | Call createButton(), createField(), or menu.create(). Positions for UI controls are 0–1 fractions, not pixel values. |
Animation speeds up after starting again | Do not start extra animation loops inside draw callbacks. Use a single loop per run. |
A picture or fetch fails | Remote network/image loading is blocked by the isolated preview. Use embedded data/blob images. |
buttons is not defined on resize | Declare var buttons = [] and register buttons you want repositioned. |
A tap draws at an old location | Use mouseX/mouseY for the workspace’s pointer coordinates; cursorX/cursorY only update on legacy movement events. |
Choosing an approach | Use ctx for native 2D; SVGHelper for concise 2D shapes; Button/Field/Menu for HTML overlays; GL + Mesh + Scene for 3D; Mat5 and tesseracts for 4D projection. |
Run executes in an isolated preview. Save to library requires a verified account. Guest code stays only in the current editor and is not saved.