figureone 1.9.0 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/llms-full.txt CHANGED
@@ -115,6 +115,8 @@ Path to figure element(s) within a collection. Supports multiple formats:
115
115
  | loadColor | TypeColor | `[0, 0, 1, 0.5]` | Color while loading |
116
116
  | onLoad | () => void | | Callback after load |
117
117
 
118
+ A `texture` on the `gl` primitive can be recolored by region with one or more masks — see OBJ_TextureMask under OBJ_GenericGL.
119
+
118
120
  ### OBJ_FigurePrimitive (base for all primitives)
119
121
 
120
122
  | Property | Type | Default | Description |
@@ -365,12 +367,47 @@ Extends OBJ_Generic (without drawType).
365
367
  | attributes | OBJ_GLAttribute[] | | Shader attributes |
366
368
  | uniforms | OBJ_GLUniform[] | | Shader uniforms |
367
369
  | texture | OBJ_Texture | | Texture |
370
+ | mask | OBJ_TextureMask | | Single mask to recolor regions of `texture` |
371
+ | masks | OBJ_TextureMask[] | | Multiple masks (each adds 4 recolorable regions) |
372
+ | tints | (TypeColor \| null)[] | | Recolor per region; mask `m` uses `tints[4m]`…`tints[4m+3]` for its r,g,b,a channels (`null` = leave region unchanged) |
368
373
  | dimension | `2` \| `3` | `2` | Coordinate dimensions |
369
374
  | light | `'directional'` \| `'point'` \| null | null | Lighting |
370
375
  | vertices | number[] \| object | | Vertex data |
371
376
  | colors | number[] \| object | | Per-vertex colors |
372
377
  | normals | number[] \| object | | Normal vectors |
373
378
 
379
+ A texture can be recolored by region using one or more masks. A mask shares the base texture's coordinates (same dimensions, aligned to the base image); each of its r, g, b, a channels marks a region. Mask `m` is recolored by `tints[4m]` (r), `tints[4m + 1]` (g), `tints[4m + 2]` (b), `tints[4m + 3]` (a); unmasked pixels keep the base texture's color. A single mask costs one extra texture fetch and four mixes; each additional mask adds one fetch and four mixes.
380
+
381
+ ### OBJ_TextureMask
382
+
383
+ | Property | Type | Default | Description |
384
+ |---|---|---|---|
385
+ | src | string | | URL of the mask image |
386
+ | loadColor | TypeColor | `[0, 0, 0, 0]` | Color shown while the mask loads (transparent = nothing recolored until loaded) |
387
+
388
+ ```js
389
+ // Recolor three regions of a texture with one mask. The mask image's red,
390
+ // green and blue channels mark the regions tinted by tints 0, 1 and 2.
391
+ figure.add({
392
+ make: 'gl',
393
+ vertices: [-0.8, -0.8, 0.8, -0.8, -0.8, 0.8, 0.8, -0.8, 0.8, 0.8, -0.8, 0.8],
394
+ texture: { src: './image.png', coords: [0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1] },
395
+ mask: { src: './mask.png' },
396
+ tints: [[1, 0, 0, 1], [0, 0.6, 0, 1], [0, 0, 1, 1]],
397
+ });
398
+
399
+ // Two masks: mask 0 uses tints 0-3, mask 1 uses tints 4-7.
400
+ figure.add({
401
+ make: 'gl',
402
+ // ...vertices, texture...
403
+ masks: [{ src: './mask.png' }, { src: './mask1.png' }],
404
+ tints: [
405
+ [1, 0, 0, 1], [0, 0.6, 0, 1], [0, 0, 1, 1], null, // mask 0
406
+ [0.6, 0, 0.8, 1], // mask 1
407
+ ],
408
+ });
409
+ ```
410
+
374
411
  ### OBJ_Morph (`make: 'morph'`)
375
412
 
376
413
  Morphable shape with multiple point arrays that can be animated between.
@@ -523,6 +560,39 @@ const points = Fig.surfaceGrid({
523
560
  figure.add({ make: 'surface', points, color: [1, 0, 0, 1], normals: 'curve' });
524
561
  ```
525
562
 
563
+ ### OBJ_RotateControl (`make: 'rotateControl'`)
564
+
565
+ Rotates a 3D element with drag gestures. Produces the same on-screen motion as
566
+ `cameraControl`, but rotates the object instead of orbiting the camera — so the
567
+ world-fixed lights shade the object differently as it turns.
568
+
569
+ | Property | Type | Default | Description |
570
+ |---|---|---|---|
571
+ | left | number | `0` | Screen left (0-1) |
572
+ | bottom | number | `0` | Screen bottom (0-1) |
573
+ | width | number | `1` | Width (0-1) |
574
+ | height | number | `1` | Height (0-1) |
575
+ | axis | TypeParsablePoint | `[0, 1, 0]` | Vertical axis |
576
+ | controlElement | FigureElement \| string | | Element to rotate (required; must not be an ancestor of the control) |
577
+ | sensitivity | number | `5` | Overall sensitivity |
578
+ | xSensitivity | number | `1` | Horizontal sensitivity (0 = no azimuth) |
579
+ | ySensitivity | number | `1` | Vertical sensitivity (0 = no elevation) |
580
+ | back | boolean | `false` | If true, other touchable elements are touched first (object rotates only on empty-space drags) |
581
+
582
+ ```js
583
+ const figure = new Fig.Figure({
584
+ scene: {
585
+ style: 'orthographic',
586
+ near: 0.1,
587
+ far: 10,
588
+ camera: { position: [1, 0.6, 1.5], lookAt: [0, 0, 0], up: [0, 1, 0] },
589
+ light: { directional: [0.7, 0.5, 1], ambient: 0.4 },
590
+ },
591
+ });
592
+ const cube = figure.add({ make: 'cube', side: 0.6, color: [1, 0, 0, 1], light: 'directional' });
593
+ figure.add({ make: 'rotateControl', controlElement: cube });
594
+ ```
595
+
526
596
  ---
527
597
 
528
598
  ## 5. Collections
package/llms.txt CHANGED
@@ -63,6 +63,7 @@ Other `Fig.Figure` options: `textStyle` (`'italic'` default | `'normal'` — def
63
63
  | `prism` | 3D prism |
64
64
  | `revolve` | 3D surface of revolution |
65
65
  | `cameraControl` | Enables 3D camera rotation via drag |
66
+ | `rotateControl` | Rotates a 3D element via drag (object turns, camera/light fixed); set `controlElement` |
66
67
 
67
68
  Shorthand `make: 'polygon'` is equivalent to `make: 'primitives.polygon'`.
68
69
 
@@ -97,6 +98,16 @@ figure.add({
97
98
  make: 'rectangle', width: 1.8, height: 1.2,
98
99
  texture: { src: 'image.jpg', mapTo: [-0.9, -0.6, 1.8, 1.2] },
99
100
  });
101
+
102
+ // Recolor regions of a texture with masks (gl primitive). Each mask's r,g,b,a
103
+ // channels mark regions; mask m is tinted by tints[4m]..tints[4m+3].
104
+ figure.add({
105
+ make: 'gl',
106
+ vertices: [-0.8, -0.8, 0.8, -0.8, -0.8, 0.8, 0.8, -0.8, 0.8, 0.8, -0.8, 0.8],
107
+ texture: { src: 'image.png', coords: [0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1] },
108
+ masks: [{ src: 'mask.png' }, { src: 'mask1.png' }],
109
+ tints: [[1, 0, 0, 1], [0, 0.6, 0, 1], [0, 0, 1, 1], null, [0.6, 0, 0.8, 1]],
110
+ });
100
111
  ```
101
112
 
102
113
  ### Element Properties
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "figureone",
3
- "version": "1.9.0",
3
+ "version": "1.10.0",
4
4
  "description": "Draw, animate and interact with shapes, text, plots and equations in Javascript. Create interactive slide shows, and interactive videos.",
5
5
  "main": "index.js",
6
6
  "types": "types/index.d.ts",
@@ -2,6 +2,7 @@ import type { TypeGLBufferUsage } from '../DrawingObjects/GLObject/GLObject';
2
2
  import type { CPY_Step } from '../geometries/copy/copy';
3
3
  import type { TypeParsablePoint } from '../../tools/geometry/Point';
4
4
  import type Scene from '../../tools/geometry/scene';
5
+ import type { FigureElement } from '../Element';
5
6
  import type { TypeColor } from '../../tools/types';
6
7
  import type { TypeParsableLine } from '../../tools/geometry/Line';
7
8
  import type { OBJ_Line3Arrow } from '../../tools/d3/line3';
@@ -1103,3 +1104,94 @@ export type OBJ_CameraControl = {
1103
1104
  ySensitivity?: number;
1104
1105
  back?: boolean;
1105
1106
  } & OBJ_FigurePrimitive;
1107
+ /**
1108
+ * Rotate control definition object that extends {@link OBJ_FigurePrimitive}.
1109
+ *
1110
+ * A rotate control is a transparent rectangle that uses touch and drag gestures
1111
+ * to rotate a 3D element. It produces the same on-screen motion as
1112
+ * {@link OBJ_CameraControl}, but rotates the *object* rather than orbiting the
1113
+ * camera. Because the scene lights are fixed in world space, the object's faces
1114
+ * are shaded differently as it turns (with `cameraControl` the shading stays
1115
+ * fixed relative to the object).
1116
+ *
1117
+ * Left/right movements rotate the object around the vertical `axis` (azimuth),
1118
+ * while up/down movements change its elevation relative to that axis.
1119
+ *
1120
+ * The transparent rectangle is positioned relative to the 2D HTML canvas. The
1121
+ * `left`, `bottom`, `width` and `height` properties are numbers from 0 to 1
1122
+ * representing a percentage of the screen width and height. For the rectangle to
1123
+ * cover the entire screen use `left: 0`, `bottom: 0`, `width: 1`, `height: 1`
1124
+ * (the defaults).
1125
+ *
1126
+ * Set `controlElement` (by name or reference) to the element to rotate. This is
1127
+ * required - it must not be an ancestor of the control (e.g. its parent
1128
+ * collection), otherwise rotating it would corrupt the control's own gesture
1129
+ * coordinates. With no `controlElement` the control does nothing. The element
1130
+ * should be centered on its scene's camera `lookAt` point so that it spins in
1131
+ * place.
1132
+ *
1133
+ * @property {number} [left] screen left position to place the control rectangle.
1134
+ * 0 is the left edge, while 1 is the right edge (`0`).
1135
+ * @property {number} [bottom] screen bottom position to place the control
1136
+ * rectangle. 0 is the bottom edge, while 1 is the top edge (`0`).
1137
+ * @property {number} [width] width of control rectangle. 1 is the full width of
1138
+ * the drawing canvas (`1`).
1139
+ * @property {number} [height] height of control rectangle. 1 is the full height
1140
+ * of the drawing canvas (`1`).
1141
+ * @property {TypeParsablePoint} [axis] axis to keep vertical as the object is
1142
+ * rotated. The axis vector and scene.camera.up vector should be in the same
1143
+ * plane (`[0, 1, 0]`)
1144
+ * @property {FigureElement | string} [controlElement] element to rotate (by name
1145
+ * or reference). Required; must not be an ancestor of the control. With no value
1146
+ * the control does nothing.
1147
+ * @property {number} [sensitivity] sensitivity of object rotation relative to
1148
+ * user movement where larger numbers result in more rotation for the same
1149
+ * movement (`5`)
1150
+ * @property {number} [xSensitivity] sensitivity to a horizontal user movement.
1151
+ * Setting this to 0 will mean the object does not rotate azimuthally (`1`)
1152
+ * @property {number} [ySensitivity] sensitivity to a vertical user movement.
1153
+ * Setting this to 0 will mean the elevation does not change (`1`)
1154
+ * @property {boolean} [back] if `false` (the default) the control captures all
1155
+ * drags, so dragging the object (or anywhere) rotates it. If `true`, all 2D and
1156
+ * 3D objects that can be touched are touched before the rotate control, so the
1157
+ * object only rotates when dragging empty space - use this when other elements
1158
+ * also need to be interactive (`false`)
1159
+ *
1160
+ * @example
1161
+ * // Cube that can be rotated by dragging anywhere on the figure.
1162
+ * // Set the 3D scene in the constructor so figure.scene and
1163
+ * // figure.elements.scene are wired consistently.
1164
+ * const figure = new Fig.Figure({
1165
+ * scene: {
1166
+ * style: 'orthographic',
1167
+ * near: 0.1,
1168
+ * far: 10,
1169
+ * camera: { position: [1, 0.6, 1.5], lookAt: [0, 0, 0], up: [0, 1, 0] },
1170
+ * light: { directional: [0.7, 0.5, 1], ambient: 0.4 },
1171
+ * },
1172
+ * });
1173
+ *
1174
+ * const cube = figure.add({
1175
+ * make: 'cube',
1176
+ * side: 0.6,
1177
+ * color: [1, 0, 0, 1],
1178
+ * light: 'directional',
1179
+ * });
1180
+ *
1181
+ * figure.add({ make: 'rotateControl', controlElement: cube });
1182
+ *
1183
+ * @interface
1184
+ * @group Interactivity
1185
+ */
1186
+ export type OBJ_RotateControl = {
1187
+ left?: number;
1188
+ bottom?: number;
1189
+ width?: number;
1190
+ height?: number;
1191
+ axis?: TypeParsablePoint;
1192
+ controlElement?: FigureElement | string;
1193
+ sensitivity?: number;
1194
+ xSensitivity?: number;
1195
+ ySensitivity?: number;
1196
+ back?: boolean;
1197
+ } & OBJ_FigurePrimitive;
@@ -13,7 +13,7 @@ import FigureElementPrimitiveGesture from './FigureElementPrimitiveGesture';
13
13
  import type { OBJ_Gesture } from './FigureElementPrimitiveGesture';
14
14
  import type { OBJ_LineStyleSimple, OBJ_GenericGL, OBJ_Morph, OBJ_Text } from './FigurePrimitiveTypes';
15
15
  import type { OBJ_Generic, OBJ_Polyline, OBJ_Polygon, OBJ_Polygon_Defined, OBJ_Star, OBJ_Rectangle, OBJ_Ellipse, OBJ_Arc, OBJ_Triangle, OBJ_Line, OBJ_Grid, OBJ_Arrow } from './FigurePrimitiveTypes2D';
16
- import type { OBJ_Generic3, OBJ_Sphere, OBJ_Cube, OBJ_Cylinder, OBJ_Cone, OBJ_Revolve, OBJ_Surface, OBJ_Line3, OBJ_CameraControl, OBJ_Prism } from './FigurePrimitiveTypes3D';
16
+ import type { OBJ_Generic3, OBJ_Sphere, OBJ_Cube, OBJ_Cylinder, OBJ_Cone, OBJ_Revolve, OBJ_Surface, OBJ_Line3, OBJ_CameraControl, OBJ_RotateControl, OBJ_Prism } from './FigurePrimitiveTypes3D';
17
17
  type OBJ_PolyLineTris = OBJ_LineStyleSimple & {
18
18
  drawBorderBuffer: number | Array<Array<Point>>;
19
19
  };
@@ -106,6 +106,18 @@ export default class FigurePrimitives {
106
106
  * @see {@link OBJ_CameraControl} for options and examples.
107
107
  */
108
108
  cameraControl(...options: Array<OBJ_CameraControl>): any;
109
+ /**
110
+ * {@link FigureElementPrimitive} that rotates a 3D element with touch and drag
111
+ * gestures.
112
+ *
113
+ * This produces the same on-screen motion as {@link OBJ_CameraControl}, but
114
+ * rotates the *object* instead of orbiting the camera. As the scene's lights
115
+ * are fixed in world space, the object's faces are shaded differently as it
116
+ * turns (with `cameraControl` the shading stays fixed relative to the object).
117
+ *
118
+ * @see {@link OBJ_RotateControl} for options and examples.
119
+ */
120
+ rotateControl(...options: Array<OBJ_RotateControl>): any;
109
121
  /**
110
122
  * {@link FigureElementPrimitive} that draws an ellipse.
111
123
  * @see {@link OBJ_Ellipse} for options and examples.