+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
- reflections
-
-
- |
-
-
- projections
-
-
-
-
- 2025
-
-
-
- coming soon
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ reflections
+
+ |
+
+ projections
+
+
+ coming soon 2026
+
+
+
+
+
-
+
+
+
);
}
diff --git a/apps/hype/src/assets/RPREC.gif b/apps/hype/src/assets/RPREC.gif
deleted file mode 100644
index a62f3f1c..00000000
Binary files a/apps/hype/src/assets/RPREC.gif and /dev/null differ
diff --git a/apps/hype/src/assets/rplogo.svg b/apps/hype/src/assets/rplogo.svg
new file mode 100644
index 00000000..43ef9a30
--- /dev/null
+++ b/apps/hype/src/assets/rplogo.svg
@@ -0,0 +1,22 @@
+
\ No newline at end of file
diff --git a/apps/hype/src/customTheme.ts b/apps/hype/src/customTheme.ts
deleted file mode 100644
index 11272564..00000000
--- a/apps/hype/src/customTheme.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { extendTheme, ThemeConfig } from "@chakra-ui/react";
-
-const config: ThemeConfig = {
- initialColorMode: "light",
- useSystemColorMode: false
-};
-
-export const customTheme = extendTheme({ config });
diff --git a/apps/hype/src/index.css b/apps/hype/src/index.css
deleted file mode 100644
index 2ce62ef9..00000000
--- a/apps/hype/src/index.css
+++ /dev/null
@@ -1,69 +0,0 @@
-:root {
- font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
- line-height: 1.5;
- font-weight: 400;
-
- color-scheme: light dark;
- color: rgba(255, 255, 255, 0.87);
- background-color: #242424;
-
- font-synthesis: none;
- text-rendering: optimizeLegibility;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
-}
-
-a {
- font-weight: 500;
- color: #646cff;
- text-decoration: inherit;
-}
-a:hover {
- color: #535bf2;
-}
-
-body {
- margin: 0;
- display: flex;
- place-items: center;
- min-width: 320px;
- min-height: 100vh;
- background-color: black;
-}
-
-h1 {
- font-size: 3.2em;
- line-height: 1.1;
-}
-
-button {
- border-radius: 8px;
- border: 1px solid transparent;
- padding: 0.6em 1.2em;
- font-size: 1em;
- font-weight: 500;
- font-family: inherit;
- background-color: #1a1a1a;
- cursor: pointer;
- transition: border-color 0.25s;
-}
-button:hover {
- border-color: #646cff;
-}
-button:focus,
-button:focus-visible {
- outline: 4px auto -webkit-focus-ring-color;
-}
-
-@media (prefers-color-scheme: light) {
- :root {
- color: #213547;
- background-color: #ffffff;
- }
- a:hover {
- color: #747bff;
- }
- button {
- background-color: #f9f9f9;
- }
-}
diff --git a/apps/hype/src/main.tsx b/apps/hype/src/main.tsx
index 0869d9d9..b1d48616 100644
--- a/apps/hype/src/main.tsx
+++ b/apps/hype/src/main.tsx
@@ -1,14 +1,10 @@
import React from "react";
import ReactDOM from "react-dom/client";
-import { ChakraProvider } from "@chakra-ui/react";
import App from "./App.tsx";
-
-import { customTheme } from "./customTheme.ts";
+import "./App.css";
ReactDOM.createRoot(document.getElementById("root")!).render(
-
-
-
+
);
diff --git a/apps/hype/src/skyline.ts b/apps/hype/src/skyline.ts
new file mode 100644
index 00000000..3cb78c92
--- /dev/null
+++ b/apps/hype/src/skyline.ts
@@ -0,0 +1,265 @@
+export interface WindowData {
+ ox: number;
+ oy: number;
+ size: number;
+ on: boolean;
+ brightness: number;
+ burstGroup: number;
+ isStraggler: boolean;
+ stragglerDelay: number;
+ sparkleSpeed: number;
+ sparkleOffset: number;
+}
+
+export interface BuildingData {
+ x: number;
+ w: number;
+ h: number;
+ windows: WindowData[];
+}
+
+let _seed = 2026;
+export function seededRandom() {
+ _seed |= 0;
+ _seed = (_seed + 0x6d2b79f5) | 0;
+ let t = Math.imul(_seed ^ (_seed >>> 15), 1 | _seed);
+ t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
+ return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
+}
+
+export function rand(min: number, max: number) {
+ return seededRandom() * (max - min) + min;
+}
+
+export function buildSkylineData(): BuildingData[] {
+ _seed = 2026;
+ const vw = window.innerWidth;
+ const isMobile = vw < 768;
+ const isSmall = vw < 480;
+
+ const maxH = isSmall ? 400 : isMobile ? 600 : 900;
+ const minH = isSmall ? 80 : isMobile ? 120 : 160;
+ const maxW = isSmall ? 35 : isMobile ? 50 : 75;
+ const minW = isSmall ? 18 : isMobile ? 25 : 35;
+ const gap = isSmall ? 3 : 4;
+
+ const avgWidth = (maxW + minW) / 2 + gap;
+ const count = Math.ceil(vw / avgWidth) + 2;
+
+ const winSize = isSmall ? 4 : 6;
+ const winGapX = isSmall ? 12 : 14;
+ const winGapY = isSmall ? 18 : 22;
+
+ const buildings: BuildingData[] = [];
+ const totalEstWidth = count * avgWidth;
+ const startX = Math.max(0, (vw - totalEstWidth) / 2);
+ let x = startX;
+
+ for (let i = 0; i < count; i++) {
+ const normalizedPos = i / (count - 1);
+ const distFromCenter = Math.abs(normalizedPos - 0.5) * 2;
+
+ const heightCap = 0.25 + distFromCenter * 0.75;
+ const effectiveMaxH = maxH * heightCap;
+
+ const h = Math.floor(rand(minH, Math.max(minH, effectiveMaxH)));
+ const w = Math.floor(rand(minW, maxW));
+
+ const windows: WindowData[] = [];
+ const cols = Math.floor((w - 8) / winGapX);
+ const rows = Math.floor((h - 14) / winGapY);
+
+ for (let r = 0; r < rows; r++) {
+ for (let c = 0; c < cols; c++) {
+ if (seededRandom() > 0.3) continue;
+
+ const burstGroup = Math.floor(seededRandom() * 3);
+ const isStraggler = seededRandom() < 0.04;
+
+ windows.push({
+ ox: 5 + c * winGapX,
+ oy: 10 + r * winGapY,
+ size: winSize,
+ on: false,
+ brightness: rand(0.3, 0.8),
+ burstGroup,
+ isStraggler,
+ stragglerDelay: isStraggler ? rand(1.5, 4.0) : 0,
+ sparkleSpeed: rand(0.8, 2.0),
+ sparkleOffset: rand(0, Math.PI * 2)
+ });
+ }
+ }
+
+ buildings.push({ x, w, h, windows });
+ x += w + gap;
+ }
+
+ return buildings;
+}
+
+function interpolateColor(t: number) {
+ const r = Math.floor(0 + t * (184 - 0));
+ const g = Math.floor(100 + t * (41 - 100));
+ const b = Math.floor(255 + t * (221 - 255));
+ return `${r}, ${g}, ${b}`;
+}
+
+export function resizeSkylineCanvas(canvas: HTMLCanvasElement) {
+ const vw = window.innerWidth;
+ const vh = window.innerHeight;
+ const canvasH = Math.floor(vh * 0.9);
+ const dpr = Math.min(window.devicePixelRatio || 1, 2);
+
+ const targetW = Math.floor(vw * dpr);
+ const targetH = Math.floor(canvasH * dpr);
+
+ if (canvas.width !== targetW || canvas.height !== targetH) {
+ canvas.width = targetW;
+ canvas.height = targetH;
+ canvas.style.width = vw + "px";
+ canvas.style.height = canvasH + "px";
+ const ctx = canvas.getContext("2d");
+ if (ctx) {
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
+ ctx.scale(dpr, dpr);
+ }
+ }
+}
+
+export function drawSkyline(
+ canvas: HTMLCanvasElement,
+ buildings: BuildingData[],
+ elapsed: number = 0
+) {
+ const ctx = canvas.getContext("2d");
+ if (!ctx) return;
+
+ const vw = canvas.clientWidth;
+ const vh = canvas.clientHeight;
+
+ ctx.clearRect(0, 0, vw, vh);
+
+ const bgColor = "#0a0a0a";
+
+ for (const b of buildings) {
+ const by = vh - b.h;
+
+ ctx.fillStyle = bgColor;
+ ctx.fillRect(b.x, by, b.w, b.h);
+
+ ctx.strokeStyle = "rgba(158, 25, 191, 0.24)";
+ ctx.lineWidth = 1;
+
+ ctx.beginPath();
+ ctx.moveTo(b.x + 0.5, by);
+ ctx.lineTo(b.x + 0.5, vh);
+ ctx.stroke();
+
+ ctx.beginPath();
+ ctx.moveTo(b.x + b.w - 0.5, by);
+ ctx.lineTo(b.x + b.w - 0.5, vh);
+ ctx.stroke();
+
+ ctx.beginPath();
+ ctx.moveTo(b.x, by + 0.5);
+ ctx.lineTo(b.x + b.w, by + 0.5);
+ ctx.stroke();
+
+ for (const win of b.windows) {
+ if (!win.on) continue;
+ const wx = b.x + win.ox;
+ const wy = by + win.oy;
+
+ const sinVal =
+ (Math.sin(elapsed * win.sparkleSpeed + win.sparkleOffset) + 1) / 2;
+ const sparkle = Math.pow(sinVal, 10);
+ const t = (Math.sin(elapsed * 0.3 + win.sparkleOffset) + 1) / 2;
+ const rgb = interpolateColor(t);
+ const alpha = win.brightness * (0.1 + sparkle * 0.9);
+
+ ctx.fillStyle = `rgba(${rgb}, ${alpha})`;
+ ctx.fillRect(wx, wy, win.size, win.size);
+
+ if (alpha > 0.8) {
+ ctx.fillStyle = `rgba(${rgb}, 0.2)`;
+ ctx.fillRect(wx - 1, wy - 1, win.size + 2, win.size + 2);
+ }
+ }
+ }
+}
+
+export function animateWindowsOn(
+ canvas: HTMLCanvasElement,
+ buildings: BuildingData[]
+) {
+ const burstStartTimes = [0.3, 0.8, 1.4];
+ const flickerDuration = 0.2;
+ const startTime = performance.now();
+ const burstState = [0, 0, 0];
+ let rafId: number;
+
+ function frame() {
+ resizeSkylineCanvas(canvas);
+ const now = performance.now();
+ const elapsed = (now - startTime) / 1000;
+
+ for (let g = 0; g < 3; g++) {
+ if (burstState[g] === 2) continue;
+
+ if (burstState[g] === 0 && elapsed >= burstStartTimes[g]) {
+ burstState[g] = 1;
+ }
+
+ if (burstState[g] === 1) {
+ const flickerElapsed = elapsed - burstStartTimes[g];
+ const flickerProgress = flickerElapsed / flickerDuration;
+
+ if (flickerProgress >= 1) {
+ burstState[g] = 2;
+ for (const b of buildings) {
+ for (const win of b.windows) {
+ if (!win.isStraggler && win.burstGroup === g) win.on = true;
+ }
+ }
+ } else {
+ const step = Math.floor(flickerProgress * 5);
+ const isOn = step % 2 === 0;
+ for (const b of buildings) {
+ for (const win of b.windows) {
+ if (!win.isStraggler && win.burstGroup === g) win.on = isOn;
+ }
+ }
+ }
+ }
+ }
+
+ for (const b of buildings) {
+ for (const win of b.windows) {
+ if (!win.isStraggler) continue;
+ if (win.on) continue;
+
+ if (elapsed >= win.stragglerDelay) {
+ const flickerElapsed = elapsed - win.stragglerDelay;
+ const flickerProgress = flickerElapsed / 0.12;
+
+ if (flickerProgress >= 1) {
+ win.on = true;
+ } else {
+ const step = Math.floor(flickerProgress * 3);
+ win.on = step % 2 === 0;
+ }
+ }
+ }
+ }
+
+ drawSkyline(canvas, buildings, elapsed);
+
+ rafId = requestAnimationFrame(frame);
+ }
+
+ rafId = requestAnimationFrame(frame);
+ return () => {
+ if (rafId) cancelAnimationFrame(rafId);
+ };
+}
diff --git a/apps/hype/src/vite-env.d.ts b/apps/hype/src/vite-env.d.ts
index 11f02fe2..e69de29b 100644
--- a/apps/hype/src/vite-env.d.ts
+++ b/apps/hype/src/vite-env.d.ts
@@ -1 +0,0 @@
-///
diff --git a/apps/hype/vite.config.ts b/apps/hype/vite.config.ts
index 2a288a53..51719cb0 100644
--- a/apps/hype/vite.config.ts
+++ b/apps/hype/vite.config.ts
@@ -2,10 +2,10 @@ import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc";
import { resolve } from "path";
-// https://vitejs.dev/config/
export default defineConfig({
server: {
- port: 3004
+ port: 3004,
+ allowedHosts: true
},
plugins: [react()],
envDir: resolve(__dirname, "../.."),
diff --git a/yarn.lock b/yarn.lock
index fc48b8bb..5fcaca3a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -941,14 +941,14 @@ __metadata:
languageName: node
linkType: hard
-"@fontsource/nunito@npm:^5.0.18, @fontsource/nunito@npm:^5.2.5":
+"@fontsource/nunito@npm:^5.0.18":
version: 5.2.6
resolution: "@fontsource/nunito@npm:5.2.6"
checksum: 10c0/ddda7b88529ebae5922749970c16acc755352624c07ffa8ea7dcacdf4ed680a1e67c4b79c758083134e2197f1dd1933125fead28903f235b37d6c8b1232b317c
languageName: node
linkType: hard
-"@fontsource/roboto-slab@npm:^5.0.20, @fontsource/roboto-slab@npm:^5.2.5":
+"@fontsource/roboto-slab@npm:^5.0.20":
version: 5.2.7
resolution: "@fontsource/roboto-slab@npm:5.2.7"
checksum: 10c0/072184b265fe78091980fbd67ba93c0e587aa533677f66be692d9128bc53532ca54fec13bc41d436af166ee424399886f5c8785dbabbfdb39f557bd8806cc16e
@@ -1371,12 +1371,6 @@ __metadata:
version: 0.0.0-use.local
resolution: "@rp/hype@workspace:apps/hype"
dependencies:
- "@chakra-ui/icons": "npm:^2.1.1"
- "@chakra-ui/react": "npm:^2.8.2"
- "@emotion/react": "npm:^11.11.4"
- "@emotion/styled": "npm:^11.11.0"
- "@fontsource/nunito": "npm:^5.2.5"
- "@fontsource/roboto-slab": "npm:^5.2.5"
"@rp/shared": "npm:*"
"@types/node": "npm:^20.12.7"
"@types/react": "npm:^18.2.66"
@@ -1384,10 +1378,6 @@ __metadata:
"@types/react-dom": "npm:^18.2.22"
"@vitejs/plugin-react": "npm:^4.3.4"
"@vitejs/plugin-react-swc": "npm:^3.5.0"
- axios: "npm:^1.6.8"
- chakra-react-select: "npm:^5.0.5"
- formik: "npm:^2.4.6"
- framer-motion: "npm:11.3.23"
react: "npm:^18.2.0"
react-dom: "npm:^18.2.0"
react-router-dom: "npm:7.8.1"