Skip to content

Commit 5859a5f

Browse files
authored
cleanup and animation (#4)
* test content update * cleanup js * infinity loop * animation * infinity loop * test three * clean
1 parent e47456d commit 5859a5f

File tree

9 files changed

+852
-72
lines changed

9 files changed

+852
-72
lines changed

docs/data/text-content.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@
2323
}
2424
],
2525
"hero": {
26-
"title": "Independent Capital for the Age of Acceleration",
27-
"subtitle": "The investment DAO engineered for centuries"
26+
"title": "THE PERPETUAL INVESTMENT DAO",
27+
"subtitle": "Independent Capital for the Age of Acceleration"
2828
},
2929
"about": {
3030
"title": "AI-Plus Strategy",
31-
"description": "Open Libra is a sovereign, on-chain investment endowment designed to survive and thrive across centuries.",
31+
"description": "Open Libra is an investment DAO, with its own blockchain, built to thrive in the Age of Acceleration.",
3232
"mission": "Our thesis is built on a foundational premise: all long-term institutions must correctly navigate the disruption AI will bring to every market."
3333
},
3434
"aboutHighlights": [

docs/index.html

Lines changed: 16 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -6,34 +6,13 @@
66
<meta name="viewport" content="width=device-width, initial-scale=1.0">
77
<title>Open Libra — The Future, Secured</title>
88
<link rel="icon" type="image/svg+xml" href="assets/logo.svg">
9-
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@200;300;400;500;600&family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
9+
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@200;300;400;500;600&family=Roboto:wght@300;400;500&family=Crimson+Text:ital@0;1&display=swap" rel="stylesheet">
1010
<script src="https://cdn.tailwindcss.com"></script>
11-
<script>
12-
// Suppress production warning for static sites
13-
if (window.tailwind && window.tailwind.config) {
14-
tailwind.config = {
15-
theme: {
16-
extend: {
17-
fontFamily: {
18-
display: ['Poppins', 'sans-serif'],
19-
body: ['Roboto', 'sans-serif'],
20-
},
21-
colors: {
22-
'brand-red': '#E75A5C',
23-
'brand-cream': '#FAF3E7',
24-
'brand-charcoal': '#4A3B3C',
25-
},
26-
},
27-
},
28-
}
29-
}
30-
</script>
11+
<script src="js/tailwind-config.js"></script>
12+
<script defer src="js/app.js"></script>
13+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.min.js"></script>
14+
<script defer src="js/infinity-loop-three.js"></script>
3115
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script>
32-
<script>
33-
document.addEventListener('alpine:init', () => {
34-
console.log('Alpine.js initialized successfully');
35-
});
36-
</script>
3716
<style>
3817
[x-cloak] {
3918
display: none !important;
@@ -55,45 +34,11 @@
5534
</style>
5635
</head>
5736

58-
<body class="min-h-screen bg-brand-red text-brand-cream flex flex-col justify-between fade-in" x-data="{ data: {}, mobileMenuOpen: false, loaded: false }"
59-
x-init="
60-
console.log('Fetching content...');
61-
fetch('data/text-content.json')
62-
.then(response => {
63-
if (!response.ok) throw new Error('Failed to load content');
64-
return response.json();
65-
})
66-
.then(json => {
67-
console.log('Content loaded successfully');
68-
data = json;
69-
loaded = true;
70-
$nextTick(() => $el.classList.add('show'));
71-
})
72-
.catch(error => {
73-
console.error('Error loading content:', error);
74-
data = {
75-
brand: { name: 'Open Libra' },
76-
navigation: [],
77-
hero: { title: 'Loading...', subtitle: '' },
78-
buttons: { faq: 'FAQ' },
79-
socialLinks: [],
80-
about: {},
81-
foundation: {},
82-
inventions: {},
83-
example: {},
84-
governance: {},
85-
documentation: {},
86-
cta: {},
87-
links: {}
88-
};
89-
loaded = true;
90-
$nextTick(() => $el.classList.add('show'));
91-
})
92-
" x-cloak>
37+
<body class="min-h-screen bg-brand-red text-brand-cream flex flex-col justify-between fade-in" x-data="app" x-cloak>
9338
<!-- Navigation -->
9439
<nav class="p-4 border-b border-opacity-20 border-brand-cream">
9540
<div class="container mx-auto flex justify-between items-center">
96-
<a href="#" class="text-xl md:text-2xl font-semibold tracking-wide font-display" x-text="data.brand?.name || 'Open Libra'"></a>
41+
<a href="#" class="text-xl md:text-2xl font-semibold tracking-wide font-display uppercase" x-text="data.brand?.name || 'Open Libra'"></a>
9742
<!-- Mobile menu button -->
9843
<button @click="mobileMenuOpen = !mobileMenuOpen" class="md:hidden p-2 focus:outline-none">
9944
<svg x-show="!mobileMenuOpen" class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -135,11 +80,15 @@
13580
</div>
13681
</div>
13782
</nav>
83+
84+
<!-- Particle Canvas -->
85+
<canvas id="particle-canvas" class="absolute inset-0 w-full h-full pointer-events-none opacity-40"></canvas>
13886
<!-- Hero Section -->
139-
<section class="container mx-auto px-4 py-12 md:py-24">
140-
<div class="max-w-5xl mx-auto">
141-
<h1 class="text-4xl md:text-7xl font-bold mb-6 tracking-wide leading-tight font-display" x-text="data.hero?.title || 'Loading...'"></h1>
142-
<p class="uppercase md:text-xl font-light opacity-90 max-w-3xl tracking-normal leading-relaxed font-body mb-8 md:mb-12" x-text="data.hero?.subtitle || ''"></p>
87+
<section class="container mx-auto px-4 py-12 md:py-24 relative overflow-hidden">
88+
89+
<div class="max-w-5xl mx-auto relative z-10">
90+
<h1 class="text-4xl md:text-7xl font-bold mb-6 tracking-wide opacity-95 leading-tight font-display" x-text="data.hero?.title || 'Loading...'"></h1>
91+
<p class="text-2xl md:text-6xl font-light opacity-95 max-w-3xl tracking-normal leading-relaxed font-serif mb-8 md:mb-12 italic" x-text="data.hero?.subtitle || ''"></p>
14392
<div class="flex flex-col gap-4 items-stretch md:items-start md:flex-row">
14493
<a href="faq.html" class="inline-block px-8 md:px-10 py-3 border border-brand-cream rounded-full text-base md:text-lg font-light tracking-wide font-body hover:bg-brand-cream hover:text-brand-red transition-colors duration-300 text-center" x-text="data.buttons?.faq || 'FAQ'"></a>
14594
</div>
@@ -207,9 +156,7 @@ <h3 class="text-lg md:text-xl font-semibold font-display mb-3" x-text="item.titl
207156
<div class="container mx-auto px-4">
208157
<div class="max-w-3xl mx-auto text-center">
209158
<h2 class="text-3xl md:text-4xl font-bold mb-6 font-display title-uppercase">Rethink Tokenomics</h2>
210-
<p class="text-lg md:text-xl font-light opacity-90 mb-8 md:mb-12 font-body">
211-
Open Libra is the only blockchain with 100% freely mined supply and 80% dedicated to long-term investment—no insiders, no pre-sale.<br>
212-
We design tokenomics for real economics and perpetual capital, not speculation.
159+
<p class="text-lg md:text-xl font-light opacity-90 mb-8 md:mb-12 font-body"> Open Libra is the only blockchain with 100% freely mined supply and 80% dedicated to long-term investment—no insiders, no pre-sale.<br> We design tokenomics for real economics and perpetual capital, not speculation.
213160
</p>
214161
<a href="tokenomics.html" class="inline-block px-8 md:px-10 py-3 bg-brand-red text-brand-cream rounded-full text-base md:text-lg font-light tracking-wide font-body hover:opacity-90 transition-opacity duration-300 text-center"> Learn More About Tokenomics </a>
215162
</div>

docs/js/app.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Alpine.js initialization and data loading
2+
document.addEventListener('alpine:init', () => {
3+
console.log('Alpine.js initialized successfully');
4+
5+
Alpine.data('app', () => ({
6+
data: {},
7+
mobileMenuOpen: false,
8+
loaded: false,
9+
10+
init() {
11+
console.log('Fetching content...');
12+
fetch('data/text-content.json')
13+
.then(response => {
14+
if (!response.ok) throw new Error('Failed to load content');
15+
return response.json();
16+
})
17+
.then(json => {
18+
console.log('Content loaded successfully');
19+
this.data = json;
20+
this.loaded = true;
21+
this.$nextTick(() => this.$el.classList.add('show'));
22+
})
23+
.catch(error => {
24+
console.error('Error loading content:', error);
25+
this.data = {
26+
brand: { name: 'Open Libra' },
27+
navigation: [],
28+
hero: { title: 'Loading...', subtitle: '' },
29+
buttons: { faq: 'FAQ' },
30+
socialLinks: [],
31+
about: {},
32+
foundation: {},
33+
inventions: {},
34+
example: {},
35+
governance: {},
36+
documentation: {},
37+
cta: {},
38+
links: {}
39+
};
40+
this.loaded = true;
41+
this.$nextTick(() => this.$el.classList.add('show'));
42+
});
43+
}
44+
}));
45+
});

docs/js/infinity-loop-three.js

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
// Infinity Loop Animation in Three.js for index.html
2+
3+
const PARTICLE_COUNT = 2000;
4+
const LOOP_SCALE = Math.max(window.innerWidth, window.innerHeight) * 0.6;
5+
6+
7+
8+
let renderer, scene, camera, points, geometry, positions, particles, sizes;
9+
10+
function initInfinityLoopThree() {
11+
scene = new THREE.Scene();
12+
camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
13+
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
14+
renderer.setClearColor(0x181825, 0); // transparent background
15+
renderer.setSize(window.innerWidth, window.innerHeight);
16+
// Update LOOP_SCALE for resize
17+
window.addEventListener('resize', () => {
18+
camera.aspect = window.innerWidth / window.innerHeight;
19+
camera.updateProjectionMatrix();
20+
renderer.setSize(window.innerWidth, window.innerHeight);
21+
// Make the loop always overflow the view
22+
LOOP_SCALE = Math.max(window.innerWidth, window.innerHeight) * 0.6;
23+
camera.position.z = 400;
24+
});
25+
const canvasEl = document.getElementById('particle-canvas');
26+
if (canvasEl) {
27+
canvasEl.replaceWith(renderer.domElement);
28+
} else {
29+
document.body.appendChild(renderer.domElement);
30+
}
31+
renderer.domElement.id = 'particle-canvas';
32+
renderer.domElement.style.position = 'absolute';
33+
renderer.domElement.style.top = '0';
34+
renderer.domElement.style.left = '0';
35+
renderer.domElement.style.width = '100vw';
36+
renderer.domElement.style.height = '100vh';
37+
renderer.domElement.style.pointerEvents = 'none';
38+
renderer.domElement.style.opacity = '0.4';
39+
renderer.domElement.style.zIndex = '10';
40+
41+
42+
geometry = new THREE.BufferGeometry();
43+
positions = new Float32Array(PARTICLE_COUNT * 3);
44+
const colors = new Float32Array(PARTICLE_COUNT * 3);
45+
sizes = new Float32Array(PARTICLE_COUNT);
46+
const color = new THREE.Color();
47+
48+
particles = [];
49+
for (let i = 0; i < PARTICLE_COUNT; i++) {
50+
const t = Math.random();
51+
// Ensure speed is always positive and not zero
52+
const speed = 0.00009 + Math.random() * 0.00002; // Slightly higher min speed
53+
const chaosAmplitude = Math.random() * 30 + 40;
54+
const chaosFrequency = Math.random() * 0.1 + 0.05;
55+
const chaosPhaseX = Math.random() * Math.PI * 2;
56+
const chaosPhaseY = Math.random() * Math.PI * 2;
57+
const size = Math.random() * 3 + 2; // Size between 2 and 5
58+
particles.push({ t, speed, chaosAmplitude, chaosFrequency, chaosPhaseX, chaosPhaseY, size });
59+
color.setHSL(0.62, 0.7, 0.95); // Soft white
60+
colors[i * 3] = color.r;
61+
colors[i * 3 + 1] = color.g;
62+
colors[i * 3 + 2] = color.b;
63+
sizes[i] = size;
64+
}
65+
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
66+
geometry.setAttribute('customColor', new THREE.BufferAttribute(colors, 3));
67+
geometry.setAttribute('size', new THREE.BufferAttribute(sizes, 1));
68+
69+
// Custom shader material for per-particle size
70+
const material = new THREE.ShaderMaterial({
71+
uniforms: {
72+
color: { value: new THREE.Color(0xffffff) },
73+
},
74+
vertexColors: true,
75+
transparent: true,
76+
depthTest: false,
77+
blending: THREE.AdditiveBlending,
78+
vertexShader: `
79+
attribute float size;
80+
attribute vec3 customColor;
81+
varying vec3 vColor;
82+
void main() {
83+
vColor = customColor;
84+
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
85+
gl_PointSize = size * (300.0 / -mvPosition.z);
86+
gl_Position = projectionMatrix * mvPosition;
87+
}
88+
`,
89+
fragmentShader: `
90+
varying vec3 vColor;
91+
void main() {
92+
float dist = length(gl_PointCoord - vec2(0.5));
93+
if (dist > 0.5) discard;
94+
gl_FragColor = vec4(vColor, 0.85 * (1.0 - dist * 1.5));
95+
}
96+
`
97+
});
98+
points = new THREE.Points(geometry, material);
99+
scene.add(points);
100+
101+
camera.position.z = 400;
102+
103+
animateInfinityLoop();
104+
}
105+
106+
function getInfinityPosition(t, time, particle) {
107+
const angle = t * Math.PI * 2;
108+
const denominator = 1 + Math.sin(angle) * Math.sin(angle);
109+
let x = (LOOP_SCALE * Math.cos(angle)) / denominator;
110+
let y = (LOOP_SCALE * Math.sin(angle) * Math.cos(angle)) / denominator;
111+
// Increase chaos for more dynamic movement
112+
const chaosX = Math.sin(time * particle.chaosFrequency + particle.chaosPhaseX) * (particle.chaosAmplitude * 0.7);
113+
const chaosY = Math.cos(time * particle.chaosFrequency + particle.chaosPhaseY) * (particle.chaosAmplitude * 0.7);
114+
// Remove synchronized turbulence for more natural chaos
115+
x += chaosX;
116+
y += chaosY;
117+
return [x, y, 0];
118+
}
119+
120+
function animateInfinityLoop() {
121+
requestAnimationFrame(animateInfinityLoop);
122+
const time = Date.now() * 0.001;
123+
for (let i = 0; i < PARTICLE_COUNT; i++) {
124+
const p = particles[i];
125+
p.t += p.speed;
126+
// Always move forward, wrap around if needed
127+
if (p.t > 1) p.t -= 1;
128+
// No negative drift, so no need to check p.t < 0
129+
const [x, y, z] = getInfinityPosition(p.t, time, p);
130+
positions[i * 3] = x;
131+
positions[i * 3 + 1] = y;
132+
positions[i * 3 + 2] = z;
133+
sizes[i] = p.size;
134+
}
135+
geometry.attributes.position.needsUpdate = true;
136+
geometry.attributes.size.needsUpdate = true;
137+
points.rotation.z += 0.001;
138+
renderer.render(scene, camera);
139+
}
140+
141+
window.addEventListener('resize', () => {
142+
if (!renderer || !camera) return;
143+
camera.aspect = window.innerWidth / window.innerHeight;
144+
camera.updateProjectionMatrix();
145+
renderer.setSize(window.innerWidth, window.innerHeight);
146+
camera.position.z = 400;
147+
});
148+
149+
// Initialize after Three.js is loaded
150+
initInfinityLoopThree();

0 commit comments

Comments
 (0)