=== WHAT'S BEEN DONE (Recent) === MCP Pipeline Factory: - 38 MCP servers tracked across 7 pipeline stages - 31 servers at Stage 16 (Website Built) — ready to deploy - All 30 production servers patched to 100/100 protocol compliance - Built complete testing infra: mcp-jest, mcp-validator, mcp-add, MCP Inspector - 702 auto-generated test cases ready for live API testing - Autonomous pipeline operator system w/ 7 Discord channels + cron jobs - Dashboard live at 192.168.0.25:8888 (drag-drop kanban) CloseBot MCP: - 119 tools, 4,656 lines TypeScript, compiles clean - 14 modules (8 tool groups + 6 UI apps) GHL MCP: - Stage 11 (Edge Case Testing) — 42 failing tests identified Sub-agent _meta Labels: - All 643 tools across 5 MCPs tagged (GHL, Google Ads, Meta Ads, Google Console, Twilio) OpenClaw Upwork Launch: - 15 graphics, 6 mockups, 2 PDFs, 90-sec Remotion video - 3-tier pricing: $2,499 / $7,499 / $24,999 - First $20k deal closed + $2k/mo retainer (hospice) Other: - Surya Blender animation scripts (7 tracks) - Clawdbot architecture deep dive doc - Pipeline state.json updates === TO-DO (Open Items) === BLOCKERS: - [ ] GHL MCP: Fix 42 failing edge case tests (Stage 11) - [ ] Expired Anthropic API key in localbosses-app .env.local - [ ] Testing strategy decision: structural vs live API vs hybrid NEEDS API KEYS (can't progress without): - [ ] Meta Ads MCP — needs META_ADS_API_KEY for Stage 8→9 - [ ] Twilio MCP — needs TWILIO_API_KEY for Stage 8→9 - [ ] CloseBot MCP — needs CLOSEBOT_API_KEY for live testing - [ ] 702 test cases across all servers need live API credentials PIPELINE ADVANCEMENT: - [ ] Stage 7→8: CloseBot + Google Console need design approval - [ ] Stage 6→7: 22 servers need UI apps built - [ ] Stage 5→6: 5 servers need core tools built (FreshBooks, Gusto, Jobber, Keap, Lightspeed) - [ ] Stage 1→5: 3 new MCPs need scaffolding (Compliance GRC, HR People Ops, Product Analytics) PENDING REVIEW: - [ ] Jake review OpenClaw video + gallery → finalize Upwork listing - [ ] LocalBosses UI redesign (Steve Jobs critique delivered, recs available) QUEUED PROJECTS: - [ ] SongSense AI music analysis product (architecture done, build not started) - [ ] 8-Week Agent Study Plan execution (curriculum posted, Week 1 not started)
171 lines
5.6 KiB
Python
171 lines
5.6 KiB
Python
"""
|
|
Track 02: U SAVED ME - Particles Coalescing into Sacred Geometry (Icosahedron)
|
|
"""
|
|
|
|
import bpy
|
|
import math
|
|
import random
|
|
import sys
|
|
import os
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
from utils import *
|
|
|
|
|
|
def get_icosahedron_vertices(scale=2.5):
|
|
"""Get icosahedron vertex positions."""
|
|
phi = (1 + math.sqrt(5)) / 2 # Golden ratio
|
|
|
|
verts = [
|
|
[0, 1, phi], [0, -1, phi], [0, 1, -phi], [0, -1, -phi],
|
|
[1, phi, 0], [-1, phi, 0], [1, -phi, 0], [-1, -phi, 0],
|
|
[phi, 0, 1], [-phi, 0, 1], [phi, 0, -1], [-phi, 0, -1]
|
|
]
|
|
|
|
# Normalize and scale
|
|
result = []
|
|
for v in verts:
|
|
norm = math.sqrt(sum(x*x for x in v))
|
|
result.append([x / norm * scale for x in v])
|
|
|
|
return result
|
|
|
|
|
|
def get_icosahedron_edges():
|
|
"""Get icosahedron edge pairs."""
|
|
return [
|
|
(0, 1), (0, 4), (0, 5), (0, 8), (0, 9),
|
|
(1, 6), (1, 7), (1, 8), (1, 9),
|
|
(2, 3), (2, 4), (2, 5), (2, 10), (2, 11),
|
|
(3, 6), (3, 7), (3, 10), (3, 11),
|
|
(4, 5), (4, 8), (4, 10),
|
|
(5, 9), (5, 11),
|
|
(6, 7), (6, 8), (6, 10),
|
|
(7, 9), (7, 11),
|
|
(8, 10), (9, 11)
|
|
]
|
|
|
|
|
|
def create_sacred_geometry_animation():
|
|
"""Create the full Track 02 animation."""
|
|
clear_scene()
|
|
setup_scene(background_color=(0.04, 0.08, 0.16, 1.0)) # Dark blue
|
|
|
|
# Create camera
|
|
camera = create_camera(location=(0, -12, 6), rotation=(1.1, 0, 0))
|
|
animate_camera_orbit(camera, center=(0, 0, 0), radius=12, height=5,
|
|
start_frame=1, end_frame=TOTAL_FRAMES, revolutions=0.4)
|
|
|
|
# Get target positions (icosahedron vertices)
|
|
target_positions = get_icosahedron_vertices(scale=2.5)
|
|
|
|
# Add midpoints for more particles
|
|
for i, v1 in enumerate(target_positions):
|
|
for v2 in target_positions[i+1:]:
|
|
mid = [(v1[j] + v2[j]) / 2 for j in range(3)]
|
|
norm = math.sqrt(sum(x*x for x in mid))
|
|
if norm > 0.5:
|
|
target_positions.append([x / norm * 2.5 for x in mid])
|
|
|
|
# Limit to 60 particles
|
|
target_positions = target_positions[:60]
|
|
|
|
# Create particles
|
|
particles = []
|
|
mat = create_emission_material("ParticleMat", COLORS["u_saved_me"], strength=3.0)
|
|
|
|
for i, target in enumerate(target_positions):
|
|
# Random start position (scattered)
|
|
start = [random.uniform(-8, 8) for _ in range(3)]
|
|
|
|
bpy.ops.mesh.primitive_ico_sphere_add(radius=0.12, subdivisions=2, location=start)
|
|
particle = bpy.context.active_object
|
|
particle.name = f"Particle_{i:03d}"
|
|
particle.data.materials.append(mat)
|
|
particles.append((particle, start, target))
|
|
|
|
# Animate particles coalescing
|
|
coalesce_start = 60
|
|
coalesce_end = 300
|
|
|
|
for particle, start, target in particles:
|
|
# Start position
|
|
keyframe_location(particle, 1, start)
|
|
keyframe_location(particle, coalesce_start, start)
|
|
|
|
# End position (at icosahedron vertex)
|
|
keyframe_location(particle, coalesce_end, target)
|
|
keyframe_location(particle, TOTAL_FRAMES - 30, target)
|
|
|
|
# Set easing
|
|
if particle.animation_data:
|
|
for fc in particle.animation_data.action.fcurves:
|
|
for kf in fc.keyframe_points:
|
|
kf.interpolation = 'BEZIER'
|
|
kf.easing = 'EASE_IN_OUT'
|
|
|
|
# Create edges after particles arrive
|
|
edges = []
|
|
edge_pairs = get_icosahedron_edges()
|
|
edge_mat = create_emission_material("EdgeMat", COLORS["u_saved_me"], strength=1.5)
|
|
|
|
verts = get_icosahedron_vertices(scale=2.5)
|
|
|
|
for i, (v1_idx, v2_idx) in enumerate(edge_pairs):
|
|
v1 = verts[v1_idx]
|
|
v2 = verts[v2_idx]
|
|
|
|
# Create curve for edge
|
|
curve_data = bpy.data.curves.new(name=f"Edge_{i}", type='CURVE')
|
|
curve_data.dimensions = '3D'
|
|
curve_data.bevel_depth = 0.02
|
|
|
|
spline = curve_data.splines.new('BEZIER')
|
|
spline.bezier_points.add(1)
|
|
spline.bezier_points[0].co = v1
|
|
spline.bezier_points[1].co = v2
|
|
|
|
curve_obj = bpy.data.objects.new(f"Edge_{i}", curve_data)
|
|
bpy.context.collection.objects.link(curve_obj)
|
|
curve_obj.data.materials.append(edge_mat)
|
|
|
|
# Animate edge appearance (bevel depth)
|
|
curve_data.bevel_depth = 0.0
|
|
curve_data.keyframe_insert(data_path="bevel_depth", frame=coalesce_end)
|
|
curve_data.keyframe_insert(data_path="bevel_depth", frame=coalesce_end + 30)
|
|
|
|
curve_data.bevel_depth = 0.02
|
|
curve_data.keyframe_insert(data_path="bevel_depth", frame=coalesce_end + 90)
|
|
|
|
edges.append(curve_obj)
|
|
|
|
# Pulse effect (scale all particles)
|
|
pulse_frames = [400, 450, 500, 550]
|
|
for frame in pulse_frames:
|
|
for particle, _, _ in particles:
|
|
keyframe_scale(particle, frame, 1.0)
|
|
keyframe_scale(particle, frame + 15, 1.4)
|
|
keyframe_scale(particle, frame + 30, 1.0)
|
|
|
|
return particles, edges
|
|
|
|
|
|
if __name__ == "__main__":
|
|
create_sacred_geometry_animation()
|
|
|
|
output_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
bpy.ops.wm.save_as_mainfile(filepath=os.path.join(output_dir, "exports", "track02_u_saved_me.blend"))
|
|
|
|
bpy.ops.export_scene.gltf(
|
|
filepath=os.path.join(output_dir, "exports", "track02_u_saved_me.gltf"),
|
|
export_animations=True,
|
|
export_format='GLTF_SEPARATE'
|
|
)
|
|
|
|
bpy.ops.wm.alembic_export(
|
|
filepath=os.path.join(output_dir, "exports", "track02_u_saved_me.abc"),
|
|
start=1, end=TOTAL_FRAMES
|
|
)
|
|
|
|
print("Track 02 - U Saved Me: Export complete!")
|