From 7969bdb70689d31dda460f97a9f3be29f7b2411e Mon Sep 17 00:00:00 2001 From: Orion Reed Date: Mon, 2 Dec 2024 17:53:03 -0500 Subject: [PATCH 1/4] update types --- package.json | 5 +- src/common/Vector.ts | 107 ++++++++++++++++++++++++++++++++++++++++ src/common/Vector2.ts | 17 ------- src/common/types.ts | 1 + src/common/utils.ts | 42 ++++++---------- src/folk-connection.ts | 8 +-- src/folk-hull.ts | 30 +++++------ src/folk-llm.ts | 6 ++- src/folk-rope.ts | 14 +++--- src/folk-shape.ts | 16 +++--- src/folk-spreadsheet.ts | 4 +- src/folk-timer.ts | 2 +- src/folk-weather.ts | 7 +-- src/folk-xanadu.ts | 8 +-- 14 files changed, 175 insertions(+), 92 deletions(-) create mode 100644 src/common/Vector.ts delete mode 100644 src/common/Vector2.ts create mode 100644 src/common/types.ts diff --git a/package.json b/package.json index 6548770..4cecbf6 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,9 @@ "type": "module", "scripts": { "dev": "vite", - "build": "vite build --base=/folk-canvas", - "preview": "vite build && vite preview" + "build": "tsc --noEmit && vite build --base=/folk-canvas", + "preview": "tsc --noEmit && vite build && vite preview", + "types": "tsc --noEmit" }, "dependencies": { "@babel/parser": "^7.26.2", diff --git a/src/common/Vector.ts b/src/common/Vector.ts new file mode 100644 index 0000000..de8a691 --- /dev/null +++ b/src/common/Vector.ts @@ -0,0 +1,107 @@ +import type { Point } from './types.ts'; + +export class Vector { + /** + * Creates a zero vector (0,0) + * @returns {Point} A point representing a zero vector + */ + static zero(): Point { + return { x: 0, y: 0 }; + } + + /** + * Subtracts vector b from vector a + * @param {Point} a - The first vector + * @param {Point} b - The vector to subtract + * @returns {Point} The resulting vector + */ + static sub(a: Point, b: Point): Point { + return { x: a.x - b.x, y: a.y - b.y }; + } + + /** + * Adds two vectors together + * @param {Point} a - The first vector + * @param {Point} b - The second vector + * @returns {Point} The sum of the two vectors + */ + static add(a: Point, b: Point): Point { + return { x: a.x + b.x, y: a.y + b.y }; + } + + /** + * Multiplies two vectors component-wise + * @param {Point} a - The first vector + * @param {Point} b - The second vector + * @returns {Point} The component-wise product of the two vectors + */ + static mult(a: Point, b: Point): Point { + return { x: a.x * b.x, y: a.y * b.y }; + } + + /** + * Scales a vector by a scalar value + * @param {Point} v - The vector to scale + * @param {number} scaleFactor - The scaling factor + * @returns {Point} The scaled vector + */ + static scale(v: Point, scaleFactor: number): Point { + return { x: v.x * scaleFactor, y: v.y * scaleFactor }; + } + + /** + * Calculates the magnitude (length) of a vector + * @param {Point} v - The vector + * @returns {number} The magnitude of the vector + */ + static mag(v: Point): number { + return Math.hypot(v.x, v.y); + } + + /** + * Returns a normalized (unit) vector in the same direction + * @param {Point} v - The vector to normalize + * @returns {Point} The normalized vector + */ + static normalized(v: Point): Point { + const magnitude = Vector.mag(v); + return magnitude === 0 ? Vector.zero() : { x: v.x / magnitude, y: v.y / magnitude }; + } + + /** + * Calculates the Euclidean distance between two points + * @param {Point} a - The first point + * @param {Point} b - The second point + * @returns {number} The distance between the points + */ + static distance(a: Point, b: Point): number { + return Math.hypot(a.x - b.x, a.y - b.y); + } + + /** + * Calculates the squared distance between two points + * Useful for performance when comparing distances + * @param {Point} a - The first point + * @param {Point} b - The second point + * @returns {number} The squared distance between the points + */ + static distanceSquared(a: Point, b: Point): number { + const dx = a.x - b.x; + const dy = a.y - b.y; + return dx * dx + dy * dy; + } + + /** + * Linearly interpolates between two points + * @param {Point} a - The starting point + * @param {Point} b - The ending point + * @param {number} t - The interpolation parameter (0-1) + * @returns {Point} The interpolated point + */ + static lerp(a: Point, b: Point, t: number): Point { + return { + x: a.x + (b.x - a.x) * t, + y: a.y + (b.y - a.y) * t, + }; + } +} diff --git a/src/common/Vector2.ts b/src/common/Vector2.ts deleted file mode 100644 index c163d33..0000000 --- a/src/common/Vector2.ts +++ /dev/null @@ -1,17 +0,0 @@ -export type Vector2 = { x: number; y: number }; - -export class Vector { - static zero: () => Vector2 = () => ({ x: 0, y: 0 }); - static sub: (a: Vector2, b: Vector2) => Vector2 = (a, b) => ({ x: a.x - b.x, y: a.y - b.y }); - static add: (a: Vector2, b: Vector2) => Vector2 = (a, b) => ({ x: a.x + b.x, y: a.y + b.y }); - static mult: (a: Vector2, b: Vector2) => Vector2 = (a, b) => ({ x: a.x * b.x, y: a.y * b.y }); - static scale: (v: Vector2, scaleFactor: number) => Vector2 = (v, scaleFactor) => ({ - x: v.x * scaleFactor, - y: v.y * scaleFactor, - }); - static mag: (v: Vector2) => number = (v) => Math.sqrt(v.x * v.x + v.y * v.y); - static normalized: (v: Vector2) => Vector2 = (v) => { - const mag = Vector.mag(v); - return mag === 0 ? Vector.zero() : { x: v.x / mag, y: v.y / mag }; - }; -} diff --git a/src/common/types.ts b/src/common/types.ts new file mode 100644 index 0000000..5816552 --- /dev/null +++ b/src/common/types.ts @@ -0,0 +1 @@ +export type Point = { x: number; y: number }; diff --git a/src/common/utils.ts b/src/common/utils.ts index f760975..82cdcc4 100644 --- a/src/common/utils.ts +++ b/src/common/utils.ts @@ -1,35 +1,21 @@ // Adopted from: https://github.com/pshihn/bezier-points/blob/master/src/index.ts -export type Point = [number, number]; - -export interface Vertex { - x: number; - y: number; -} - -// distance between 2 points -function distance(p1: Point, p2: Point): number { - return Math.sqrt(distanceSq(p1, p2)); -} - -// distance between 2 points squared -function distanceSq(p1: Point, p2: Point): number { - return Math.pow(p1[0] - p2[0], 2) + Math.pow(p1[1] - p2[1], 2); -} +import type { Point } from './types.ts'; +import { Vector } from './Vector.ts'; // Distance squared from a point p to the line segment vw function distanceToSegmentSq(p: Point, v: Point, w: Point): number { - const l2 = distanceSq(v, w); + const l2 = Vector.distanceSquared(v, w); if (l2 === 0) { - return distanceSq(p, v); + return Vector.distanceSquared(p, v); } - let t = ((p[0] - v[0]) * (w[0] - v[0]) + (p[1] - v[1]) * (w[1] - v[1])) / l2; + let t = ((p.x - v.x) * (w.x - v.x) + (p.y - v.y) * (w.y - v.y)) / l2; t = Math.max(0, Math.min(1, t)); - return distanceSq(p, lerp(v, w, t)); + return Vector.distanceSquared(p, Vector.lerp(v, w, t)); } function lerp(a: Point, b: Point, t: number): Point { - return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t]; + return { x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t }; } // Adapted from https://seant23.wordpress.com/2010/11/12/offset-bezier-curves/ @@ -39,13 +25,13 @@ function flatness(points: readonly Point[], offset: number): number { const p3 = points[offset + 2]; const p4 = points[offset + 3]; - let ux = 3 * p2[0] - 2 * p1[0] - p4[0]; + let ux = 3 * p2.x - 2 * p1.x - p4.x; ux *= ux; - let uy = 3 * p2[1] - 2 * p1[1] - p4[1]; + let uy = 3 * p2.y - 2 * p1.y - p4.y; uy *= uy; - let vx = 3 * p3[0] - 2 * p4[0] - p1[0]; + let vx = 3 * p3.x - 2 * p4.x - p1.x; vx *= vx; - let vy = 3 * p3[1] - 2 * p4[1] - p1[1]; + let vy = 3 * p3.y - 2 * p4.y - p1.y; vy *= vy; if (ux < vx) { @@ -69,7 +55,7 @@ function getPointsOnBezierCurveWithSplitting( if (flatness(points, offset) < tolerance) { const p0 = points[offset + 0]; if (outPoints.length) { - const d = distance(outPoints[outPoints.length - 1], p0); + const d = Vector.distance(outPoints[outPoints.length - 1], p0); if (d > 1) { outPoints.push(p0); } @@ -176,7 +162,7 @@ export function getSvgPathFromStroke(stroke: number[][]): string { return d.join(' '); } -export function verticesToPolygon(vertices: Vertex[]): string { +export function verticesToPolygon(vertices: Point[]): string { if (vertices.length === 0) return ''; return `polygon(${vertices.map((vertex) => `${vertex.x}px ${vertex.y}px`).join(', ')})`; @@ -184,7 +170,7 @@ export function verticesToPolygon(vertices: Vertex[]): string { const vertexRegex = /(?-?([0-9]*[.])?[0-9]+),\s*(?-?([0-9]*[.])?[0-9]+)/; -export function parseVertex(str: string): Vertex | null { +export function parseVertex(str: string): Point | null { const results = vertexRegex.exec(str); if (results === null) return null; diff --git a/src/folk-connection.ts b/src/folk-connection.ts index 5602616..f896cb4 100644 --- a/src/folk-connection.ts +++ b/src/folk-connection.ts @@ -73,10 +73,10 @@ export class FolkConnection extends AbstractArrow { ) as Arrow; const points = pointsOnBezierCurves([ - [sx, sy], - [cx, cy], - [ex, ey], - [ex, ey], + { x: sx, y: sy }, + { x: cx, y: cy }, + { x: ex, y: ey }, + { x: ex, y: ey }, ]); const stroke = getStroke(points, this.#options); diff --git a/src/folk-hull.ts b/src/folk-hull.ts index c16e1c7..6f27bd1 100644 --- a/src/folk-hull.ts +++ b/src/folk-hull.ts @@ -1,6 +1,6 @@ import { FolkSet } from './folk-set'; -import { Vertex, verticesToPolygon } from './common/utils'; - +import { verticesToPolygon } from './common/utils'; +import type { Point } from './common/types'; declare global { interface HTMLElementTagNameMap { 'folk-hull': FolkHull; @@ -10,9 +10,9 @@ declare global { export class FolkHull extends FolkSet { static tagName = 'folk-hull'; - #hull: Vertex[] = []; + #hull: Point[] = []; - get hull(): ReadonlyArray { + get hull(): ReadonlyArray { return this.#hull; } @@ -50,7 +50,7 @@ export class FolkHull extends FolkSet { * If not, see . */ -function comparePoints(a: Vertex, b: Vertex): number { +function comparePoints(a: Point, b: Point): number { if (a.x < b.x) return -1; if (a.x > b.x) return 1; if (a.y < b.y) return -1; @@ -58,8 +58,8 @@ function comparePoints(a: Vertex, b: Vertex): number { return 0; } -export function makeHull(rects: DOMRectReadOnly[]): Vertex[] { - const points: Vertex[] = rects +export function makeHull(rects: DOMRectReadOnly[]): Point[] { + const points: Point[] = rects .flatMap((rect) => [ { x: rect.left, y: rect.top }, { x: rect.right, y: rect.top }, @@ -74,12 +74,12 @@ export function makeHull(rects: DOMRectReadOnly[]): Vertex[] { // as per the mathematical convention, instead of "down" as per the computer // graphics convention. This doesn't affect the correctness of the result. - const upperHull: Array = []; + const upperHull: Array = []; for (let i = 0; i < points.length; i++) { - const p: Vertex = points[i]; + const p: Point = points[i]; while (upperHull.length >= 2) { - const q: Vertex = upperHull[upperHull.length - 1]; - const r: Vertex = upperHull[upperHull.length - 2]; + const q: Point = upperHull[upperHull.length - 1]; + const r: Point = upperHull[upperHull.length - 2]; if ((q.x - r.x) * (p.y - r.y) >= (q.y - r.y) * (p.x - r.x)) upperHull.pop(); else break; } @@ -87,12 +87,12 @@ export function makeHull(rects: DOMRectReadOnly[]): Vertex[] { } upperHull.pop(); - const lowerHull: Array = []; + const lowerHull: Array = []; for (let i = points.length - 1; i >= 0; i--) { - const p: Vertex = points[i]; + const p: Point = points[i]; while (lowerHull.length >= 2) { - const q: Vertex = lowerHull[lowerHull.length - 1]; - const r: Vertex = lowerHull[lowerHull.length - 2]; + const q: Point = lowerHull[lowerHull.length - 1]; + const r: Point = lowerHull[lowerHull.length - 2]; if ((q.x - r.x) * (p.y - r.y) >= (q.y - r.y) * (p.x - r.x)) lowerHull.pop(); else break; } diff --git a/src/folk-llm.ts b/src/folk-llm.ts index 8d33e9a..1dd48b7 100644 --- a/src/folk-llm.ts +++ b/src/folk-llm.ts @@ -24,9 +24,11 @@ export class FolkLLM extends HTMLElement { this.#update(new Set(['systemPrompt', 'prompt'])); } - #session; + #session: any; - #isModelReady = window?.ai.languageModel.capabilities().then((capabilities) => capabilities.available === 'readily'); + #isModelReady = window?.ai.languageModel + .capabilities() + .then((capabilities: any) => capabilities.available === 'readily'); #systemPrompt: Prompt = this.getAttribute('system-prompt') || ''; get systemPrompt() { diff --git a/src/folk-rope.ts b/src/folk-rope.ts index cfac83a..611efc0 100644 --- a/src/folk-rope.ts +++ b/src/folk-rope.ts @@ -1,18 +1,18 @@ // This is a rewrite of https://github.com/guerrillacontra/html5-es6-physics-rope -import { Vector, type Vector2 } from './common/Vector2.ts'; +import { Vector } from './common/Vector.ts'; +import type { Point } from './common/types.ts'; import { AbstractArrow } from './abstract-arrow.ts'; -import { Vertex } from './common/utils.ts'; const lerp = (first: number, second: number, percentage: number) => first + (second - first) * percentage; // Each rope part is one of these uses a high precision variant of Störmer–Verlet integration to keep the simulation consistent otherwise it would "explode"! interface RopePoint { - pos: Vertex; + pos: Point; distanceToNextPoint: number; isFixed: boolean; - oldPos: Vertex; - velocity: Vertex; + oldPos: Point; + velocity: Point; mass: number; damping: number; prev: RopePoint | null; @@ -162,7 +162,7 @@ export class FolkRope extends AbstractArrow { } } - #generatePoints(start: Vertex, end: Vertex) { + #generatePoints(start: Point, end: Point) { const delta = Vector.sub(end, start); const len = Vector.mag(delta); const resolution = 5; @@ -202,7 +202,7 @@ export class FolkRope extends AbstractArrow { return points; } - #integratePoint(point: RopePoint, gravity: Vector2) { + #integratePoint(point: RopePoint, gravity: Point) { if (!point.isFixed) { point.velocity = Vector.sub(point.pos, point.oldPos); point.oldPos = { ...point.pos }; diff --git a/src/folk-shape.ts b/src/folk-shape.ts index 1d5606a..69b078d 100644 --- a/src/folk-shape.ts +++ b/src/folk-shape.ts @@ -1,6 +1,6 @@ import { css, html } from './common/tags'; import { ResizeObserverManager } from './common/resize-observer'; -import type { Vector2 } from './common/Vector2'; +import type { Point } from './common/types'; const resizeObserver = new ResizeObserverManager(); @@ -11,13 +11,13 @@ type RotatedDOMRect = DOMRect & { rotation: number; // Returns the center point in worldspace coordinates - center(): Vector2; + center(): Point; // Returns the four corners in worldspace coordinates, in clockwise order - corners(): [Vector2, Vector2, Vector2, Vector2]; + corners(): [Point, Point, Point, Point]; // Returns all the vertices in worldspace coordinates - vertices(): Vector2[]; + vertices(): Point[]; }; export type MoveEventDetail = { movementX: number; movementY: number }; @@ -311,18 +311,18 @@ export class FolkShape extends HTMLElement { bottom: y + height, rotation, - center(): Vector2 { + center(): Point { return { x: this.x + this.width / 2, y: this.y + this.height / 2, }; }, - vertices(): Vector2[] { + vertices(): Point[] { // TODO: Implement return []; }, - corners(): [Vector2, Vector2, Vector2, Vector2] { + corners(): [Point, Point, Point, Point] { const center = this.center(); const cos = Math.cos(radians); const sin = Math.sin(radians); @@ -331,7 +331,7 @@ export class FolkShape extends HTMLElement { const halfHeight = this.height / 2; // Helper to rotate a point around the center - const rotatePoint = (dx: number, dy: number): Vector2 => ({ + const rotatePoint = (dx: number, dy: number): Point => ({ x: center.x + dx * cos - dy * sin, y: center.y + dx * sin + dy * cos, }); diff --git a/src/folk-spreadsheet.ts b/src/folk-spreadsheet.ts index 34c2f96..f81199f 100644 --- a/src/folk-spreadsheet.ts +++ b/src/folk-spreadsheet.ts @@ -160,7 +160,7 @@ export class FolkSpreadsheet extends HTMLElement { #shadow = this.attachShadow({ mode: 'open' }); - #textarea; + #textarea: HTMLTextAreaElement | null = null; #editedCell: FolkSpreadSheetCell | null = null; @@ -315,6 +315,7 @@ export class FolkSpreadsheet extends HTMLElement { } #focusTextarea(cell: FolkSpreadSheetCell) { + if (this.#textarea === null) return; this.#editedCell = cell; const gridColumn = getColumnIndex(cell.column) + 2; const gridRow = cell.row + 1; @@ -327,6 +328,7 @@ export class FolkSpreadsheet extends HTMLElement { #resetTextarea() { if (this.#editedCell === null) return; + if (this.#textarea === null) return; this.#textarea.style.setProperty('--text-column', '0'); this.#textarea.style.setProperty('--text-row', '0'); this.#editedCell.expression = this.#textarea.value; diff --git a/src/folk-timer.ts b/src/folk-timer.ts index 32abbdc..c97cb2f 100644 --- a/src/folk-timer.ts +++ b/src/folk-timer.ts @@ -12,7 +12,7 @@ export class FolkTimer extends HTMLElement { } #timeMs = 0; - #timeoutId = -1; + #timeoutId: NodeJS.Timeout | -1 = -1; #intervalMs = 100; diff --git a/src/folk-weather.ts b/src/folk-weather.ts index a9b279f..1377e0d 100644 --- a/src/folk-weather.ts +++ b/src/folk-weather.ts @@ -19,7 +19,7 @@ export class FolkWeather extends HTMLElement { static observedAttributes = ['coordinates']; - #coordinates = [0, 0] as const; + #coordinates: readonly [number, number] = [0, 0]; #results: Weather | null = null; get coordinates() { @@ -30,9 +30,10 @@ export class FolkWeather extends HTMLElement { this.setAttribute('coordinates', coordinates.join(', ')); } - attributeChangedCallback(name, oldValue, newValue) { + attributeChangedCallback(name: string, oldValue: string, newValue: string) { if (name === 'coordinates') { - this.#coordinates = newValue.split(',').map((str) => Number(str)) || [0, 0]; + const [lat = 0, long = 0] = newValue.split(',').map((str) => Number(str)); + this.#coordinates = [lat, long] as const; this.fetchWeather(this.#coordinates); } } diff --git a/src/folk-xanadu.ts b/src/folk-xanadu.ts index a1dc11f..df063e6 100644 --- a/src/folk-xanadu.ts +++ b/src/folk-xanadu.ts @@ -1,6 +1,6 @@ import { AbstractArrow } from './abstract-arrow.js'; -import { Vertex, verticesToPolygon } from './common/utils.js'; - +import { verticesToPolygon } from './common/utils.js'; +import type { Point } from './common/types.js'; export class FolkXanadu extends AbstractArrow { static tagName = 'folk-xanadu'; @@ -47,7 +47,7 @@ export class FolkXanadu extends AbstractArrow { } // The order that vertices are returned is significant -function computeInlineVertices(rects: DOMRect[]): Vertex[] { +function computeInlineVertices(rects: DOMRect[]): Point[] { rects = rects.map((rect) => DOMRectReadOnly.fromRect({ height: Math.round(rect.height), @@ -68,7 +68,7 @@ function computeInlineVertices(rects: DOMRect[]): Vertex[] { ]; } - const vertices: Vertex[] = []; + const vertices: Point[] = []; if (rects[1].left < rects[0].left) { vertices.push({ x: rects[1].left, y: rects[1].top }, { x: rects[0].left, y: rects[0].bottom }); From c7a3580f9fbaef5a425840383121e47486c30264 Mon Sep 17 00:00:00 2001 From: Orion Reed Date: Mon, 2 Dec 2024 18:07:01 -0500 Subject: [PATCH 2/4] add rotation utils --- src/common/Vector.ts | 31 +++++++++++++++++++++++++++++++ src/folk-shape.ts | 33 ++++++++++++--------------------- 2 files changed, 43 insertions(+), 21 deletions(-) diff --git a/src/common/Vector.ts b/src/common/Vector.ts index de8a691..58fb056 100644 --- a/src/common/Vector.ts +++ b/src/common/Vector.ts @@ -104,4 +104,35 @@ export class Vector { y: a.y + (b.y - a.y) * t, }; } + + /** + * Rotates a vector by a given angle (in radians) + * @param {Point} v - The vector to rotate + * @param {number} angle - The angle in radians + * @returns {Point} The rotated vector + */ + static rotate(v: Point, angle: number): Point { + const cos = Math.cos(angle); + const sin = Math.sin(angle); + return { + x: v.x * cos - v.y * sin, + y: v.x * sin + v.y * cos, + }; + } + + /** + * Rotates a point around a pivot point by a given angle (in radians) + * @param {Point} point - The point to rotate + * @param {Point} pivot - The point to rotate around + * @param {number} angle - The angle in radians + * @returns {Point} The rotated point + */ + static rotateAround(point: Point, pivot: Point, angle: number): Point { + // Translate to origin + const translated = Vector.sub(point, pivot); + // Rotate around origin + const rotated = Vector.rotate(translated, angle); + // Translate back + return Vector.add(rotated, pivot); + } } diff --git a/src/folk-shape.ts b/src/folk-shape.ts index 69b078d..41463e7 100644 --- a/src/folk-shape.ts +++ b/src/folk-shape.ts @@ -1,22 +1,23 @@ import { css, html } from './common/tags'; import { ResizeObserverManager } from './common/resize-observer'; import type { Point } from './common/types'; +import { Vector } from './common/Vector'; const resizeObserver = new ResizeObserverManager(); export type Shape = 'rectangle' | 'circle' | 'triangle'; type RotatedDOMRect = DOMRect & { - // In degrees + /** in degrees */ rotation: number; - // Returns the center point in worldspace coordinates + /** Returns the center point in worldspace coordinates */ center(): Point; - // Returns the four corners in worldspace coordinates, in clockwise order + /** Returns the four corners in worldspace coordinates, in clockwise order */ corners(): [Point, Point, Point, Point]; - // Returns all the vertices in worldspace coordinates + /** Returns all the vertices in worldspace coordinates */ vertices(): Point[]; }; export type MoveEventDetail = { movementX: number; movementY: number }; @@ -322,26 +323,16 @@ export class FolkShape extends HTMLElement { return []; }, - corners(): [Point, Point, Point, Point] { + corners() { const center = this.center(); - const cos = Math.cos(radians); - const sin = Math.sin(radians); + const radians = (this.rotation * Math.PI) / 180; + const { x, y, width, height } = this; - const halfWidth = this.width / 2; - const halfHeight = this.height / 2; - - // Helper to rotate a point around the center - const rotatePoint = (dx: number, dy: number): Point => ({ - x: center.x + dx * cos - dy * sin, - y: center.y + dx * sin + dy * cos, - }); - - // Return vertices in clockwise order: top-left, top-right, bottom-right, bottom-left return [ - rotatePoint(-halfWidth, -halfHeight), // Top-left - rotatePoint(halfWidth, -halfHeight), // Top-right - rotatePoint(halfWidth, halfHeight), // Bottom-right - rotatePoint(-halfWidth, halfHeight), // Bottom-left + Vector.rotateAround({ x, y }, center, radians), + Vector.rotateAround({ x: x + width, y }, center, radians), + Vector.rotateAround({ x: x + width, y: y + height }, center, radians), + Vector.rotateAround({ x, y: y + height }, center, radians), ]; }, From 792cf0683a98137dde2eb1fc71417e4b85e67418 Mon Sep 17 00:00:00 2001 From: Orion Reed Date: Mon, 2 Dec 2024 18:15:14 -0500 Subject: [PATCH 3/4] radians for rotation --- demo/shapes-in-a-canvas.html | 2 +- src/folk-shape.ts | 40 +++++++++++++++++------------------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/demo/shapes-in-a-canvas.html b/demo/shapes-in-a-canvas.html index 5b4b4b2..ede528a 100644 --- a/demo/shapes-in-a-canvas.html +++ b/demo/shapes-in-a-canvas.html @@ -23,7 +23,7 @@ - +