Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,12 @@ npm run preview
## Deployment

Production will deploy from the tested `main` branch to the Arca Computer Cloudflare account after the company zone is attached and the first deployment is verified. The Vercel deployment remains the live rollback target until that cutover passes.

## Motion

The homepage (`src/pages/index.astro`) and the company deck (`src/pages/deck.astro`, served at `/deck`) share one motion engine: `public/motion.css` plus the scripts below. Each page keeps its own stylesheet. Both pages are fully readable without JavaScript. A one-line inline script in `src/layouts/BaseLayout.astro` adds `html.js`, and every hidden-until-revealed rule in `public/styles.css` is scoped to that class and to `prefers-reduced-motion: no-preference`.

- `src/scripts/motion.ts` — scroll reveals, condensed masthead + progress line, active nav, pointer highlights, magnetic buttons, metric counters, and the self-drawing signal map.
- `src/scripts/signal-board.ts` — the hero canvas (procedural traces with travelling pulses). It pauses off-screen and when the tab is hidden, and renders one static frame under reduced motion.

Print styles force every reveal visible and hide the canvas, so the deck still exports cleanly to PDF. To test the reduced-motion path, emulate `prefers-reduced-motion: reduce` in DevTools (Rendering panel) and reload.
3 changes: 2 additions & 1 deletion astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ import sitemap from '@astrojs/sitemap';
export default defineConfig({
site: 'https://arca.computer',
output: 'static',
integrations: [sitemap({ customPages: ['https://arca.computer/deck'] })],
trailingSlash: 'never',
integrations: [sitemap()],
});
25 changes: 0 additions & 25 deletions public/deck/deck.js

This file was deleted.

57 changes: 50 additions & 7 deletions public/deck/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ a:focus-visible, [tabindex="-1"]:focus-visible { outline: 2px solid var(--signal
}
.rail a:hover, .rail a[aria-current="true"] { color: var(--signal); border-color: var(--line-strong); background: var(--signal-soft); }

main { scroll-snap-type: y proximity; }
main { position: relative; z-index: 1; scroll-snap-type: y proximity; }
main:focus { outline: none; }
.slide {
position: relative; min-height: 100svh; display: grid; align-items: center;
Expand Down Expand Up @@ -281,14 +281,57 @@ h2 { max-width: 900px; font-size: clamp(48px, 6.7vw, 90px); line-height: .95; }
.proof-links { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
* { transition-duration: .01ms !important; animation-duration: .01ms !important; }
}

@media print {
.deck-header, .rail, .grain, .skip-link { display: none; }
.deck-header, .rail, .grain, .skip-link, .signal-board { display: none; }
body { background: var(--ink); }
.slide { min-height: 100vh; break-after: page; padding: 52px; }
.slide:last-child { break-after: auto; }
}

/* Deck motion: entrance choreography and cover diagram (engine in /motion.css). */
.deck-header::after {
position: absolute; right: 0; bottom: -1px; left: 0; height: 1px; content: "";
background: var(--signal); transform: scaleX(var(--progress, 0)); transform-origin: left;
}
.deck-header.is-condensed { background: rgba(13,20,18,.9); }

h1 .line { display: block; overflow: hidden; padding: .08em 0 .18em; margin: -.08em 0 -.18em; }
h1 .line > span { display: block; }

.metrics strong { font-variant-numeric: tabular-nums; }
.range-grid a.glow { --glow: var(--bronze-rgb); }
.system-loop li { transition: background .3s var(--ease-out); }
.system-loop li:hover { background: rgba(17,27,24,.7); }
.launchpad-grid article { transition: background .3s var(--ease-out); }
.launchpad-grid article:hover { background: rgba(17,27,24,.75); }

.cover-diagram span { transition: opacity .6s var(--ease-out), translate .6s var(--ease-out); }
.cover-diagram .signal-packet { fill: #dbfff5; stroke: none; transition: opacity .8s ease 3.4s; }
.cover-diagram[data-draw] path { transition-delay: .9s; }
.cover-diagram.is-drawn circle:nth-of-type(1) { transition-delay: 1s; }
.cover-diagram.is-drawn circle:nth-of-type(2) { transition-delay: 1.4s; }
.cover-diagram.is-drawn circle:nth-of-type(3) { transition-delay: 1.8s; }
.cover-diagram.is-drawn circle:nth-of-type(4) { transition-delay: 2.2s; }
.cover-diagram.is-drawn circle:nth-of-type(5) { transition-delay: 2.6s; }
.cover-diagram.is-drawn circle:nth-of-type(6) { transition-delay: 3s; }
.cover-diagram.is-drawn span:nth-of-type(1) { transition-delay: 1s; }
.cover-diagram.is-drawn span:nth-of-type(2) { transition-delay: 1.4s; }
.cover-diagram.is-drawn span:nth-of-type(3) { transition-delay: 1.8s; }
.cover-diagram.is-drawn span:nth-of-type(4) { transition-delay: 2.2s; }
.cover-diagram.is-drawn span:nth-of-type(5) { transition-delay: 2.6s; }
.cover-diagram.is-drawn span:nth-of-type(6) { transition-delay: 3s; }

@media (prefers-reduced-motion: no-preference) {
html.js .deck-header { animation: fade-down .8s var(--ease-out) backwards; }
html.js .rail { animation: board-in 1s var(--ease-out) .6s backwards; }
html.js .cover .kicker { animation: fade-up .7s var(--ease-out) .12s backwards; }
html.js .cover h1 .line > span { animation: rise 1s var(--ease-out) .2s backwards; }
html.js .cover h1 .line-2 > span { animation-delay: .3s; }
html.js .cover .lead { animation: fade-up .8s var(--ease-out) .48s backwards; }
html.js .cover-index p { animation: fade-up .8s var(--ease-out) backwards; animation-delay: calc(.6s + var(--i, 0) * 80ms); }
html.js .cover-index p:nth-child(2) { --i: 1; }
html.js .cover-index p:nth-child(3) { --i: 2; }
html.js .cover-index p:nth-child(4) { --i: 3; }
html.js .cover-diagram { animation: fade-up .9s var(--ease-out) .8s backwards; }
html.js .cover-diagram:not(.is-drawn) span { opacity: 0; translate: 0 6px; }
}
247 changes: 247 additions & 0 deletions public/motion.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
/* Shared motion layer for arca.computer pages. Loaded after each page's own stylesheet. */

:root {
--signal-rgb: 104, 219, 195;
--bronze-rgb: 192, 139, 84;
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
--ease-io: cubic-bezier(0.65, 0, 0.35, 1);
--t-micro: 180ms;
--t-reveal: 800ms;
}

/* Decorative canvas layer behind the first screen. */
.signal-board {
position: absolute;
inset: 0 0 auto;
z-index: 0;
height: min(100vh, 920px);
overflow: hidden;
pointer-events: none;
-webkit-mask-image:
linear-gradient(90deg, rgba(0, 0, 0, 0.16) 0%, rgba(0, 0, 0, 0.4) 34%, #000 60%),
linear-gradient(180deg, #000 58%, transparent 100%);
-webkit-mask-composite: source-in;
mask-image:
linear-gradient(90deg, rgba(0, 0, 0, 0.16) 0%, rgba(0, 0, 0, 0.4) 34%, #000 60%),
linear-gradient(180deg, #000 58%, transparent 100%);
mask-composite: intersect;
}

.signal-board canvas {
display: block;
width: 100%;
height: 100%;
}

/* Magnetic buttons (class added by motion.ts). */
.button.is-magnetic {
transition:
border-color var(--t-micro) ease,
background var(--t-micro) ease,
color var(--t-micro) ease,
transform 0.4s var(--ease-out);
}

.button.is-magnetic.is-returning {
transition-duration: var(--t-micro), var(--t-micro), var(--t-micro), 0.6s;
transition-timing-function: ease, ease, ease, var(--ease-spring);
}

/* Self-drawing diagrams: any [data-draw] container with SVG paths and circles. */
[data-draw] path {
transition: stroke-dashoffset 2.2s var(--ease-io);
}

[data-draw] circle {
transition: opacity 0.5s var(--ease-out);
}

/* Pointer-follow highlight and border glow on .glow cards. */
@media (hover: hover) and (pointer: fine) {
.glow {
position: relative;
isolation: isolate;
}

.glow::before {
position: absolute;
inset: 0;
z-index: -1;
content: "";
pointer-events: none;
opacity: 0;
background: radial-gradient(
380px circle at var(--mx, 50%) var(--my, 50%),
rgba(var(--glow, var(--signal-rgb)), 0.11),
transparent 62%
);
transition: opacity 0.4s var(--ease-out);
}

.glow::after {
position: absolute;
inset: -1px;
z-index: 2;
padding: 1px;
content: "";
pointer-events: none;
opacity: 0;
background: radial-gradient(
320px circle at var(--mx, 50%) var(--my, 50%),
rgba(var(--glow, var(--signal-rgb)), 0.8),
transparent 60%
);
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
-webkit-mask-composite: xor;
mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
mask-composite: exclude;
transition: opacity 0.4s var(--ease-out);
}

.glow:hover::before,
.glow:hover::after {
opacity: 1;
}
}

@media (max-width: 760px) {
.signal-board {
height: min(100vh, 760px);
opacity: 0.6;
-webkit-mask-image: linear-gradient(180deg, #000 55%, transparent 100%);
-webkit-mask-composite: source-over;
mask-image: linear-gradient(180deg, #000 55%, transparent 100%);
mask-composite: add;
}
}

@keyframes pulse {
50% {
opacity: 0.42;
filter: drop-shadow(0 0 2px var(--signal));
}
}

@keyframes fade-down {
from {
opacity: 0;
transform: translateY(-12px);
}
to {
opacity: 1;
transform: none;
}
}

@keyframes fade-up {
from {
opacity: 0;
transform: translateY(16px);
}
to {
opacity: 1;
transform: none;
}
}

@keyframes rise {
from {
transform: translateY(112%);
}
to {
transform: none;
}
}

@keyframes board-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}

@media (prefers-reduced-motion: no-preference) {
html.js .signal-board {
animation: board-in 2s var(--ease-out) 0.35s backwards;
}

/* Scroll reveals: hidden only when the motion script can run. */
html.js [data-reveal]:not(.is-done),
html.js [data-reveal-stagger] > :not(.is-done) {
opacity: 0;
transform: translateY(26px);
filter: blur(5px);
transition:
opacity var(--t-reveal) var(--ease-out),
transform var(--t-reveal) var(--ease-out),
filter var(--t-reveal) var(--ease-out);
transition-delay: calc(var(--i, 0) * 70ms);
}

html.js [data-reveal].is-in:not(.is-done),
html.js [data-reveal-stagger] > .is-in:not(.is-done) {
opacity: 1;
transform: none;
filter: none;
}

/* Diagram nodes stay hidden until the line has drawn itself. */
html.js [data-draw]:not(.is-drawn) circle {
opacity: 0;
}
}

@media (prefers-reduced-motion: reduce) {
html {
scroll-behavior: auto;
}

.signal-packet {
display: none;
}

.signal-board {
opacity: 0.7;
}

*,
*::before,
*::after {
scroll-behavior: auto !important;
transition-duration: 0.15s !important;
transition-delay: 0s !important;
animation-duration: 0.01ms !important;
animation-delay: 0s !important;
animation-iteration-count: 1 !important;
}
}

@media print {
.signal-board,
.signal-packet {
display: none;
}

html.js [data-reveal],
html.js [data-reveal-stagger] > *,
html.js [data-draw] circle {
opacity: 1 !important;
transform: none !important;
filter: none !important;
}

[data-draw] path {
stroke-dasharray: none !important;
stroke-dashoffset: 0 !important;
}

*,
*::before,
*::after {
animation: none !important;
transition: none !important;
}
}
Loading