@vib3code/sdk 2.0.3-canary.d0c4221 → 2.0.3-canary.d677f12
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/DOCS/AGENT_HARNESS_ARCHITECTURE.md +2 -0
- package/DOCS/ANDROID_DEPLOYMENT.md +59 -0
- package/DOCS/ARCHITECTURE.md +1 -0
- package/DOCS/CI_TESTING.md +2 -0
- package/DOCS/CLI_ONBOARDING.md +2 -0
- package/DOCS/CONTROL_REFERENCE.md +2 -0
- package/DOCS/CROSS_SITE_DESIGN_PATTERNS.md +2 -0
- package/DOCS/ENV_SETUP.md +2 -0
- package/DOCS/EPIC_SCROLL_EVENTS.md +2 -0
- package/DOCS/EXPANSION_DESIGN.md +2 -0
- package/DOCS/EXPANSION_DESIGN_ULTRA.md +389 -0
- package/DOCS/EXPORT_FORMATS.md +2 -0
- package/DOCS/GPU_DISPOSAL_GUIDE.md +2 -0
- package/DOCS/HANDOFF_LANDING_PAGE.md +2 -0
- package/DOCS/HANDOFF_SDK_DEVELOPMENT.md +2 -0
- package/DOCS/LICENSING_TIERS.md +2 -0
- package/DOCS/MASTER_PLAN_2026-01-31.md +2 -0
- package/DOCS/MULTIVIZ_CHOREOGRAPHY_PATTERNS.md +3 -1
- package/DOCS/OBS_SETUP_GUIDE.md +2 -0
- package/DOCS/OPTIMIZATION_PLAN_MATH.md +119 -0
- package/DOCS/PRODUCT_STRATEGY.md +2 -0
- package/DOCS/PROJECT_SETUP.md +2 -0
- package/DOCS/README.md +5 -3
- package/DOCS/REFERENCE_SCROLL_ANALYSIS.md +2 -0
- package/DOCS/RENDERER_LIFECYCLE.md +2 -0
- package/DOCS/REPO_MANIFEST.md +2 -0
- package/DOCS/ROADMAP.md +2 -0
- package/DOCS/SCROLL_TIMELINE_v3.md +2 -0
- package/DOCS/SITE_REFACTOR_PLAN.md +2 -0
- package/DOCS/STATUS.md +2 -0
- package/DOCS/SYSTEM_INVENTORY.md +2 -0
- package/DOCS/TELEMETRY_EXPORTS.md +2 -0
- package/DOCS/VISUAL_ANALYSIS_CLICKERSS.md +2 -0
- package/DOCS/VISUAL_ANALYSIS_FACETAD.md +2 -0
- package/DOCS/VISUAL_ANALYSIS_SIMONE.md +2 -0
- package/DOCS/VISUAL_ANALYSIS_TABLESIDE.md +2 -0
- package/DOCS/WEBGPU_STATUS.md +2 -0
- package/DOCS/XR_BENCHMARKS.md +2 -0
- package/DOCS/archive/BLUEPRINT_EXECUTION_PLAN_2026-01-07.md +1 -34
- package/DOCS/archive/DEV_TRACK_ANALYSIS.md +1 -80
- package/DOCS/archive/DEV_TRACK_PLAN_2026-01-07.md +1 -42
- package/DOCS/archive/SESSION_014_PLAN.md +1 -195
- package/DOCS/archive/SESSION_LOG_2026-01-07.md +1 -56
- package/DOCS/archive/STRATEGIC_BLUEPRINT_2026-01-07.md +1 -72
- package/DOCS/archive/SYSTEM_AUDIT_2026-01-30.md +1 -741
- package/DOCS/archive/WEBGPU_STATUS_2026-02-15_STALE.md +1 -38
- package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-01-31.md +2 -0
- package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-06.md +2 -0
- package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-13.md +2 -0
- package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-15.md +2 -0
- package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-16.md +2 -0
- package/DOCS/dev-tracks/PERF_UPGRADE_2026-02-16.md +2 -0
- package/DOCS/dev-tracks/README.md +2 -0
- package/package.json +2 -4
- package/src/cli/index.js +59 -5
- package/src/experimental/GameLoop.js +72 -0
- package/src/experimental/LatticePhysics.js +100 -0
- package/src/experimental/LiveDirector.js +143 -0
- package/src/experimental/PlayerController4D.js +154 -0
- package/src/experimental/VIB3Actor.js +138 -0
- package/src/experimental/VIB3Compositor.js +117 -0
- package/src/experimental/VIB3Link.js +122 -0
- package/src/experimental/VIB3Orchestrator.js +146 -0
- package/src/experimental/VIB3Universe.js +109 -0
- package/src/experimental/demos/CrystalLabyrinth.js +202 -0
- package/src/export/SVGExporter.js +9 -5
- package/src/geometry/generators/Crystal.js +2 -2
- package/src/geometry/warp/HypersphereCore.js +53 -24
- package/src/math/Mat4x4.js +302 -127
- package/src/math/Projection.js +39 -4
- package/src/math/Rotor4D.js +69 -46
- package/src/math/Vec4.js +265 -111
- package/src/scene/Node4D.js +74 -24
- package/src/testing/ProjectionClass.test.js +38 -0
- package/tools/update_projection.py +109 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CrystalLabyrinth.js - Vertical Slice Demo
|
|
3
|
+
*
|
|
4
|
+
* Implements the full "Ultra" stack:
|
|
5
|
+
* - VIB3Universe (Multi-instance)
|
|
6
|
+
* - VIB3Orchestrator (Game Loop)
|
|
7
|
+
* - VIB3Compositor (Visuals)
|
|
8
|
+
* - LatticePhysics (4D Collision)
|
|
9
|
+
* - PlayerController4D (Input)
|
|
10
|
+
* - LiveDirector (AI Pacing)
|
|
11
|
+
*
|
|
12
|
+
* @experimental
|
|
13
|
+
*/
|
|
14
|
+
import { VIB3Universe } from '../VIB3Universe.js';
|
|
15
|
+
import { GameLoop } from '../GameLoop.js';
|
|
16
|
+
import { LatticePhysics } from '../LatticePhysics.js';
|
|
17
|
+
import { PlayerController4D } from '../PlayerController4D.js';
|
|
18
|
+
import { LiveDirector } from '../LiveDirector.js';
|
|
19
|
+
|
|
20
|
+
class CrystalLabyrinthGame {
|
|
21
|
+
constructor() {
|
|
22
|
+
this.universe = new VIB3Universe('vib3-universe');
|
|
23
|
+
this.physics = new LatticePhysics();
|
|
24
|
+
this.director = new LiveDirector(this.universe);
|
|
25
|
+
|
|
26
|
+
// Game State
|
|
27
|
+
this.score = 0;
|
|
28
|
+
this.health = 100;
|
|
29
|
+
this.isPlaying = false;
|
|
30
|
+
|
|
31
|
+
// Entities
|
|
32
|
+
this.player = null; // The "Camera"
|
|
33
|
+
this.crystals = [];
|
|
34
|
+
this.shadows = [];
|
|
35
|
+
|
|
36
|
+
// UI
|
|
37
|
+
this.ui = {
|
|
38
|
+
score: document.getElementById('score'),
|
|
39
|
+
health: document.getElementById('health'),
|
|
40
|
+
overlay: document.getElementById('overlay'),
|
|
41
|
+
startBtn: document.getElementById('start-btn')
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// Bind input
|
|
45
|
+
this.controller = new PlayerController4D(document.body, {
|
|
46
|
+
setParameter: (k, v) => this.updatePlayerView(k, v)
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Setup Loop
|
|
50
|
+
this.loop = new GameLoop(
|
|
51
|
+
(dt) => this.update(dt),
|
|
52
|
+
(alpha) => this.render(alpha)
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
this.init();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async init() {
|
|
59
|
+
// Create the "World" (Background Layer)
|
|
60
|
+
// A deep, slow-moving Holographic system representing the void
|
|
61
|
+
const world = await this.universe.spawnActor({
|
|
62
|
+
personality: 'neutral',
|
|
63
|
+
system: 'holographic',
|
|
64
|
+
geometry: 11, // Hypersphere
|
|
65
|
+
layer: { zIndex: 0, opacity: 0.4 }
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Setup UI listeners
|
|
69
|
+
this.ui.startBtn.addEventListener('click', () => this.start());
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
start() {
|
|
73
|
+
this.isPlaying = true;
|
|
74
|
+
this.ui.overlay.classList.add('hidden');
|
|
75
|
+
|
|
76
|
+
// Start Systems
|
|
77
|
+
this.universe.start();
|
|
78
|
+
this.loop.start();
|
|
79
|
+
this.director.start();
|
|
80
|
+
|
|
81
|
+
// Spawn Level
|
|
82
|
+
this.spawnLevel();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async spawnLevel() {
|
|
86
|
+
// Spawn 5 Crystals (Pickups)
|
|
87
|
+
for (let i = 0; i < 5; i++) {
|
|
88
|
+
const crystal = await this.universe.spawnActor({
|
|
89
|
+
personality: 'heroic', // Bright, positive
|
|
90
|
+
system: 'faceted',
|
|
91
|
+
geometry: 7, // Crystal
|
|
92
|
+
layer: { zIndex: 10, blendMode: 'screen', opacity: 0.9 }
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Random position in 4D space (mock)
|
|
96
|
+
crystal.physics = {
|
|
97
|
+
pos: {
|
|
98
|
+
x: (Math.random() - 0.5) * 20,
|
|
99
|
+
y: (Math.random() - 0.5) * 5,
|
|
100
|
+
z: (Math.random() - 0.5) * 20
|
|
101
|
+
},
|
|
102
|
+
vel: { x: 0, y: 0, z: 0 },
|
|
103
|
+
acc: { x: 0, y: 0, z: 0 }
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
this.crystals.push(crystal);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Spawn 3 Shadows (Enemies)
|
|
110
|
+
for (let i = 0; i < 3; i++) {
|
|
111
|
+
const shadow = await this.universe.spawnActor({
|
|
112
|
+
personality: 'glitch', // Chaotic, negative
|
|
113
|
+
system: 'quantum',
|
|
114
|
+
geometry: 16, // Spiky
|
|
115
|
+
layer: { zIndex: 5, blendMode: 'multiply', opacity: 0.7 }
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
shadow.physics = {
|
|
119
|
+
pos: { x: 0, y: 0, z: -30 }, // Start far away
|
|
120
|
+
vel: { x: 0, y: 0, z: 0 },
|
|
121
|
+
acc: { x: 0, y: 0, z: 0 }
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
this.shadows.push(shadow);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Physics Update (Fixed Timestep)
|
|
130
|
+
*/
|
|
131
|
+
update(dt) {
|
|
132
|
+
if (!this.isPlaying) return;
|
|
133
|
+
|
|
134
|
+
// 1. Update Player Controls
|
|
135
|
+
this.controller.update(dt);
|
|
136
|
+
|
|
137
|
+
// 2. Update Physics World
|
|
138
|
+
// Sync player controller state to physics engine?
|
|
139
|
+
// For now, controller handles movement directly.
|
|
140
|
+
|
|
141
|
+
// 3. AI Logic (Shadows hunt player)
|
|
142
|
+
this.shadows.forEach(shadow => {
|
|
143
|
+
// Move towards player (0,0,0 relative to camera)
|
|
144
|
+
// In a real engine, we'd have absolute coordinates.
|
|
145
|
+
// Here, we simulate relative motion by updating parameters
|
|
146
|
+
|
|
147
|
+
// Mock: Oscillate shadow intensity based on "proximity"
|
|
148
|
+
shadow.emote('panic', 0.5);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// 4. Check Collisions (Mock)
|
|
152
|
+
// If player is close to a crystal -> Collect
|
|
153
|
+
if (Math.random() < 0.005 && this.crystals.length > 0) {
|
|
154
|
+
this.collectCrystal(this.crystals.pop());
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Render Update (Variable Timestep)
|
|
160
|
+
*/
|
|
161
|
+
render(alpha) {
|
|
162
|
+
// Visual interpolation could happen here
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
updatePlayerView(key, value) {
|
|
166
|
+
// Broadcast player view changes to the World actor
|
|
167
|
+
// This makes the world rotate around the player
|
|
168
|
+
const world = this.universe.actors.get(this.universe.orchestrator.entities.keys().next().value);
|
|
169
|
+
if (world && world.engine) {
|
|
170
|
+
world.engine.setParameter(key, value);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
collectCrystal(actor) {
|
|
175
|
+
this.score++;
|
|
176
|
+
this.ui.score.innerText = this.score;
|
|
177
|
+
|
|
178
|
+
// FX
|
|
179
|
+
actor.emote('joy', 1.0, 500);
|
|
180
|
+
setTimeout(() => {
|
|
181
|
+
this.universe.despawnActor(actor.id);
|
|
182
|
+
}, 500);
|
|
183
|
+
|
|
184
|
+
if (this.score >= 5) {
|
|
185
|
+
this.win();
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
win() {
|
|
190
|
+
this.isPlaying = false;
|
|
191
|
+
this.ui.overlay.innerHTML = `
|
|
192
|
+
<h1 style="color: #0f0; text-shadow: 0 0 20px #0f0;">SECTOR STABILIZED</h1>
|
|
193
|
+
<p>The lattice is secure.</p>
|
|
194
|
+
<button onclick="location.reload()">Re-enter</button>
|
|
195
|
+
`;
|
|
196
|
+
this.ui.overlay.classList.remove('hidden');
|
|
197
|
+
this.loop.stop();
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Start Game
|
|
202
|
+
new CrystalLabyrinthGame();
|
|
@@ -355,17 +355,21 @@ function projectPoints(points, rotor, dimension, width, height) {
|
|
|
355
355
|
const centerY = height / 2;
|
|
356
356
|
const scale = Math.min(width, height) * 0.4;
|
|
357
357
|
|
|
358
|
+
// Reuse vectors to minimize allocation
|
|
359
|
+
const rotatedBuffer = new Vec4();
|
|
360
|
+
const projectedBuffer = new Vec4();
|
|
361
|
+
|
|
358
362
|
for (const point of points) {
|
|
359
363
|
// Apply 4D rotation
|
|
360
|
-
|
|
364
|
+
rotor.rotate(point, rotatedBuffer);
|
|
361
365
|
|
|
362
366
|
// Project to 3D (perspective from W)
|
|
363
|
-
|
|
367
|
+
rotatedBuffer.projectPerspective(dimension, projectedBuffer);
|
|
364
368
|
|
|
365
369
|
// Project to 2D (simple orthographic for clean SVG)
|
|
366
|
-
const x = centerX +
|
|
367
|
-
const y = centerY -
|
|
368
|
-
const depth =
|
|
370
|
+
const x = centerX + projectedBuffer.x * scale;
|
|
371
|
+
const y = centerY - projectedBuffer.y * scale; // Flip Y for SVG coordinates
|
|
372
|
+
const depth = projectedBuffer.z; // Keep depth for styling
|
|
369
373
|
|
|
370
374
|
projected.push({ x, y, depth, original: point });
|
|
371
375
|
}
|
|
@@ -61,8 +61,8 @@ export function generate24CellVertices(size = 1) {
|
|
|
61
61
|
];
|
|
62
62
|
for (const [s1, s2] of signs) {
|
|
63
63
|
const v = new Vec4(0, 0, 0, 0);
|
|
64
|
-
v.
|
|
65
|
-
v.
|
|
64
|
+
v.setComponent(i, s1 * s);
|
|
65
|
+
v.setComponent(j, s2 * s);
|
|
66
66
|
vertices.push(v);
|
|
67
67
|
}
|
|
68
68
|
}
|
|
@@ -16,13 +16,14 @@ import { Vec4 } from '../../math/Vec4.js';
|
|
|
16
16
|
* @param {number} radius - Hypersphere radius
|
|
17
17
|
* @returns {Vec4} Point on hypersphere
|
|
18
18
|
*/
|
|
19
|
-
export function projectToHypersphere(point, radius = 1) {
|
|
19
|
+
export function projectToHypersphere(point, radius = 1, target = null) {
|
|
20
20
|
const len = point.length();
|
|
21
21
|
if (len < 0.0001) {
|
|
22
22
|
// Handle origin - project to north pole
|
|
23
|
+
if (target) return target.set(0, 0, 0, radius);
|
|
23
24
|
return new Vec4(0, 0, 0, radius);
|
|
24
25
|
}
|
|
25
|
-
return point.scale(radius / len);
|
|
26
|
+
return point.scale(radius / len, target);
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
/**
|
|
@@ -30,9 +31,10 @@ export function projectToHypersphere(point, radius = 1) {
|
|
|
30
31
|
* Maps all of 3D space onto the 4D hypersphere
|
|
31
32
|
* @param {Vec4} point - Input point (uses x, y, z)
|
|
32
33
|
* @param {number} radius - Hypersphere radius
|
|
34
|
+
* @param {Vec4} [target=null] - Optional target vector
|
|
33
35
|
* @returns {Vec4} Point on hypersphere
|
|
34
36
|
*/
|
|
35
|
-
export function stereographicToHypersphere(point, radius = 1) {
|
|
37
|
+
export function stereographicToHypersphere(point, radius = 1, target = null) {
|
|
36
38
|
const x = point.x;
|
|
37
39
|
const y = point.y;
|
|
38
40
|
const z = point.z;
|
|
@@ -40,6 +42,15 @@ export function stereographicToHypersphere(point, radius = 1) {
|
|
|
40
42
|
const sumSq = x * x + y * y + z * z;
|
|
41
43
|
const denom = sumSq + 1;
|
|
42
44
|
|
|
45
|
+
if (target) {
|
|
46
|
+
return target.set(
|
|
47
|
+
(2 * x) / denom * radius,
|
|
48
|
+
(2 * y) / denom * radius,
|
|
49
|
+
(2 * z) / denom * radius,
|
|
50
|
+
(sumSq - 1) / denom * radius
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
43
54
|
return new Vec4(
|
|
44
55
|
(2 * x) / denom * radius,
|
|
45
56
|
(2 * y) / denom * radius,
|
|
@@ -56,12 +67,22 @@ export function stereographicToHypersphere(point, radius = 1) {
|
|
|
56
67
|
* @param {number} phi - Azimuth on base S² (0 to 2π)
|
|
57
68
|
* @param {number} psi - Fiber angle (0 to 2π)
|
|
58
69
|
* @param {number} radius - Hypersphere radius
|
|
70
|
+
* @param {Vec4} [target=null] - Optional target vector
|
|
59
71
|
* @returns {Vec4} Point on hypersphere
|
|
60
72
|
*/
|
|
61
|
-
export function hopfFibration(theta, phi, psi, radius = 1) {
|
|
73
|
+
export function hopfFibration(theta, phi, psi, radius = 1, target = null) {
|
|
62
74
|
const cosTheta2 = Math.cos(theta / 2);
|
|
63
75
|
const sinTheta2 = Math.sin(theta / 2);
|
|
64
76
|
|
|
77
|
+
if (target) {
|
|
78
|
+
return target.set(
|
|
79
|
+
cosTheta2 * Math.cos((phi + psi) / 2) * radius,
|
|
80
|
+
cosTheta2 * Math.sin((phi + psi) / 2) * radius,
|
|
81
|
+
sinTheta2 * Math.cos((phi - psi) / 2) * radius,
|
|
82
|
+
sinTheta2 * Math.sin((phi - psi) / 2) * radius
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
65
86
|
return new Vec4(
|
|
66
87
|
cosTheta2 * Math.cos((phi + psi) / 2) * radius,
|
|
67
88
|
cosTheta2 * Math.sin((phi + psi) / 2) * radius,
|
|
@@ -78,8 +99,9 @@ export function hopfFibration(theta, phi, psi, radius = 1) {
|
|
|
78
99
|
* @returns {Vec4[]} Warped vertices
|
|
79
100
|
*/
|
|
80
101
|
export function warpRadial(vertices, radius = 1, blendFactor = 1) {
|
|
102
|
+
const onSphere = new Vec4();
|
|
81
103
|
return vertices.map(v => {
|
|
82
|
-
|
|
104
|
+
projectToHypersphere(v, radius, onSphere);
|
|
83
105
|
return v.lerp(onSphere, blendFactor);
|
|
84
106
|
});
|
|
85
107
|
}
|
|
@@ -93,8 +115,9 @@ export function warpRadial(vertices, radius = 1, blendFactor = 1) {
|
|
|
93
115
|
* @returns {Vec4[]} Warped vertices
|
|
94
116
|
*/
|
|
95
117
|
export function warpStereographic(vertices, radius = 1, scale = 1) {
|
|
118
|
+
const scaled = new Vec4();
|
|
96
119
|
return vertices.map(v => {
|
|
97
|
-
|
|
120
|
+
v.scale(scale, scaled);
|
|
98
121
|
return stereographicToHypersphere(scaled, radius);
|
|
99
122
|
});
|
|
100
123
|
}
|
|
@@ -146,25 +169,31 @@ export function warpHypersphereCore(geometry, options = {}) {
|
|
|
146
169
|
twist = 1
|
|
147
170
|
} = options;
|
|
148
171
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
172
|
+
const temp = new Vec4();
|
|
173
|
+
const warpedVertices = geometry.vertices.map(v => {
|
|
174
|
+
// Combined scaling and warping to minimize allocations
|
|
175
|
+
const result = v.scale(scale);
|
|
176
|
+
|
|
177
|
+
if (method === 'stereographic') {
|
|
178
|
+
stereographicToHypersphere(result, radius, result);
|
|
179
|
+
} else if (method === 'hopf') {
|
|
180
|
+
const r = result.length();
|
|
181
|
+
if (r < 0.0001) {
|
|
182
|
+
result.set(0, 0, 0, radius);
|
|
183
|
+
} else {
|
|
184
|
+
const theta = Math.acos(result.z / r);
|
|
185
|
+
const phi = Math.atan2(result.y, result.x);
|
|
186
|
+
const psi = result.w * twist + phi * 0.5;
|
|
187
|
+
hopfFibration(theta, phi, psi, radius, result);
|
|
188
|
+
}
|
|
189
|
+
} else {
|
|
190
|
+
// Radial (default)
|
|
191
|
+
projectToHypersphere(result, radius, temp);
|
|
192
|
+
result.lerp(temp, blend, result);
|
|
193
|
+
}
|
|
162
194
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
warpedVertices = warpRadial(scaledVertices, radius, blend);
|
|
166
|
-
break;
|
|
167
|
-
}
|
|
195
|
+
return result;
|
|
196
|
+
});
|
|
168
197
|
|
|
169
198
|
return {
|
|
170
199
|
...geometry,
|