From b848cc12b07e65d05ccffb0d94df31b531c009be Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 01:44:26 -0700 Subject: [PATCH 01/69] Lock final EN Hero copy in isolated preview --- hero-layered-25d-static-preview/index.html | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/hero-layered-25d-static-preview/index.html b/hero-layered-25d-static-preview/index.html index 7a698e49..0de901fd 100644 --- a/hero-layered-25d-static-preview/index.html +++ b/hero-layered-25d-static-preview/index.html @@ -28,22 +28,19 @@ - {% include header-system/header.html lang="en" current_page="home" locale_url="/ru/hero-a-plus-c-shape-preview/" variant="standard" %} + {% include header-system/header.html lang="en" current_page="home" locale_url="/ru/hero-layered-25d-static-preview/" variant="standard" %}

AI SYSTEMS · AUTOMATION · PREMIUM WEBSITES

-

- From first impression to follow-through — - one connected system. -

-

We build premium websites for service businesses and connect them with AI systems and automation. Customers can understand your services and reach out with the right information; you can respond faster and spend less time on repetitive work. You stay in control where judgment matters.

+

From first impression to result — one system.

+

We build premium websites for service businesses and connect them with AI and automation. Customers understand your services and reach out with the right information; you respond faster and spend less time on routine work. Key decisions stay with you.

- Request a Private Review + Request a Review

Briefly describe the challenge. We’ll recommend where to start.

From 38dee7b4da724222245355ac25e71bbd4576bc80 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 01:44:45 -0700 Subject: [PATCH 02/69] Lock final RU Hero copy in isolated preview --- ru/hero-layered-25d-static-preview/index.html | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 ru/hero-layered-25d-static-preview/index.html diff --git a/ru/hero-layered-25d-static-preview/index.html b/ru/hero-layered-25d-static-preview/index.html new file mode 100644 index 00000000..619afda4 --- /dev/null +++ b/ru/hero-layered-25d-static-preview/index.html @@ -0,0 +1,62 @@ +--- +permalink: /ru/hero-layered-25d-static-preview/ +--- + + + + + + + ProAI Expert — Layered 2.5D Static R1 RU + + + + + {% include hero-c-shape-r4-3/style.html %} + {% include hero-c-shape-r4-3/style-final.html %} + {% include hero-c-shape-r4-5/style.html %} + {% include hero-c-shape-r4-5/style-r2-registration.html %} + {% include hero-c-shape-r4-5/style-wire-cleanup.html %} + {% include hero-c-shape-r4-6/style-corrective.html %} + {% include hero-c-shape-r4-6/style-corrective-r5.html %} + + + + Перейти к содержимому + + + + {% include header-system/header.html lang="ru" current_page="home" locale_url="/hero-layered-25d-static-preview/" variant="standard" %} + +
+
+
+
+

AI-СИСТЕМЫ · АВТОМАТИЗАЦИЯ · ПРЕМИАЛЬНЫЕ САЙТЫ

+

От первого впечатления до результата — одна система.

+

Создаём премиальные сайты для компаний сферы услуг и соединяем их с AI и автоматизацией. Клиенту проще понять ваши услуги и обратиться с нужной информацией, вам — быстрее ответить и меньше заниматься рутиной. Ключевые решения — за вами.

+
+
+ + Запросить разбор + + +

Коротко опишите задачу. Мы предложим, с чего разумнее начать.

+
+ + Смотреть проекты + +
+

Штат Вашингтон Работаем по всей США EN / RU / UA

+
+ +
+
+
+ + + + + From 86837d04df788d826dc4d2ac206d9f53e6a43d12 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 01:56:38 -0700 Subject: [PATCH 03/69] Build Premium Core 2.0 Hero layout and responsive system --- assets/css/hero-premium-core-2.css | 473 +++++++++++++++++++++++++++++ 1 file changed, 473 insertions(+) create mode 100644 assets/css/hero-premium-core-2.css diff --git a/assets/css/hero-premium-core-2.css b/assets/css/hero-premium-core-2.css new file mode 100644 index 00000000..403092d2 --- /dev/null +++ b/assets/css/hero-premium-core-2.css @@ -0,0 +1,473 @@ +@font-face { + font-family: "InterVariable"; + src: url('/assets/fonts/inter-variable-latin.woff2') format('woff2'); + font-weight: 100 900; + font-style: normal; + font-display: swap; +} + +:root { + --core2-bg: #040607; + --core2-ink: #f4f7f8; + --core2-muted: rgba(230, 238, 241, 0.62); + --core2-soft: rgba(230, 238, 241, 0.36); + --core2-line: rgba(214, 233, 239, 0.13); + --core2-cyan: #72e6ff; + --core2-cyan-soft: rgba(114, 230, 255, 0.16); + --core2-max: 1600px; + --core2-header: 85px; +} + +* { box-sizing: border-box; } +html { background: var(--core2-bg); } +body.hero-core2-page { + margin: 0; + min-width: 320px; + min-height: 100vh; + overflow-x: hidden; + color: var(--core2-ink); + background: + radial-gradient(circle at 76% 46%, rgba(50, 132, 151, 0.09), transparent 31%), + radial-gradient(circle at 54% 18%, rgba(255, 255, 255, 0.025), transparent 28%), + linear-gradient(180deg, #050708 0%, #030405 100%); + font-family: "InterVariable", Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; +} + +body.hero-core2-page::before { + content: ""; + position: fixed; + inset: 0; + pointer-events: none; + z-index: 0; + opacity: .22; + background-image: + linear-gradient(rgba(255,255,255,.022) 1px, transparent 1px), + linear-gradient(90deg, rgba(255,255,255,.018) 1px, transparent 1px); + background-size: 78px 78px; + -webkit-mask-image: radial-gradient(circle at 72% 50%, black 0 20%, transparent 70%); + mask-image: radial-gradient(circle at 72% 50%, black 0 20%, transparent 70%); +} + +.hero-core2-page .site-header { z-index: 40; } + +.hero-core2-skip { + position: fixed; + top: 10px; + left: 12px; + z-index: 100; + transform: translateY(-150%); + padding: 10px 14px; + border-radius: 999px; + background: #fff; + color: #050607; + font: 700 12px/1 Inter, sans-serif; + text-decoration: none; +} +.hero-core2-skip:focus { transform: none; } + +.hero-core2 { + position: relative; + z-index: 1; + min-height: 100svh; + overflow: hidden; + isolation: isolate; +} + +.hero-core2::after { + content: ""; + position: absolute; + left: 47%; + right: -6%; + bottom: 5%; + height: 24%; + pointer-events: none; + background: radial-gradient(ellipse at center, rgba(0,0,0,.72), transparent 66%); + filter: blur(18px); + z-index: 0; +} + +.hero-core2__shell { + position: relative; + width: min(100%, var(--core2-max)); + min-height: 100svh; + margin: 0 auto; + padding: calc(var(--core2-header) + 48px) clamp(24px, 3vw, 52px) 48px; + display: grid; + grid-template-columns: minmax(0, .84fr) minmax(600px, 1.16fr); + align-items: center; + gap: clamp(24px, 3.6vw, 70px); +} + +.hero-core2__copy { + position: relative; + z-index: 8; + width: min(100%, 650px); + padding-bottom: 1vh; +} + +.hero-core2__eyebrow { + margin: 0 0 18px; + display: flex; + align-items: center; + gap: 12px; + color: rgba(174, 228, 241, .78); + font: 700 11px/1.3 "InterVariable", sans-serif; + letter-spacing: .18em; + text-transform: uppercase; +} +.hero-core2__eyebrow::before { + content: ""; + width: 34px; + height: 1px; + background: linear-gradient(90deg, rgba(114,230,255,.92), rgba(114,230,255,0)); + box-shadow: 0 0 16px rgba(114,230,255,.28); +} + +.hero-core2__title { + margin: 0; + max-width: 10.8ch; + color: #f5f8f9; + font-size: clamp(58px, 5.15vw, 84px); + line-height: .96; + font-weight: 760; + letter-spacing: -.062em; + text-wrap: balance; +} + +.hero-core2__lead { + margin: 27px 0 0; + max-width: 610px; + color: var(--core2-muted); + font-size: clamp(15.5px, 1.1vw, 18px); + line-height: 1.62; + font-weight: 390; +} + +.hero-core2__actions { + display: flex; + align-items: flex-start; + gap: 13px; + margin-top: 29px; + flex-wrap: wrap; +} + +.hero-core2__primary { display: grid; gap: 9px; } +.hero-core2__button { + min-height: 49px; + padding: 0 20px; + border-radius: 7px; + border: 1px solid rgba(255,255,255,.13); + display: inline-flex; + align-items: center; + justify-content: center; + gap: 12px; + color: #f5f8f9; + text-decoration: none; + font-size: 12px; + line-height: 1; + font-weight: 760; + letter-spacing: .045em; + text-transform: uppercase; + transition: transform .35s cubic-bezier(.2,.8,.2,1), border-color .35s ease, background .35s ease, box-shadow .35s ease; +} +.hero-core2__button:hover, +.hero-core2__button:focus-visible { transform: translateY(-2px); } +.hero-core2__button:focus-visible { outline: 2px solid rgba(114,230,255,.72); outline-offset: 3px; } +.hero-core2__button--primary { + color: #061013; + border-color: rgba(132, 236, 255, .92); + background: linear-gradient(180deg, #8eebff 0%, #62d5ef 100%); + box-shadow: 0 12px 36px rgba(50, 194, 225, .12), inset 0 1px rgba(255,255,255,.68); +} +.hero-core2__button--primary:hover, +.hero-core2__button--primary:focus-visible { + box-shadow: 0 16px 44px rgba(50, 194, 225, .22), inset 0 1px rgba(255,255,255,.74); +} +.hero-core2__button--secondary { + background: rgba(255,255,255,.025); + backdrop-filter: blur(12px); +} +.hero-core2__button--secondary:hover, +.hero-core2__button--secondary:focus-visible { + border-color: rgba(181,225,236,.35); + background: rgba(255,255,255,.05); +} + +.hero-core2__microcopy { + margin: 0; + width: min(280px, 74vw); + color: var(--core2-soft); + font-size: 11.5px; + line-height: 1.45; +} + +.hero-core2__accountability { + margin: 22px 0 0; + color: rgba(211, 226, 231, .43); + font-size: 10.5px; + line-height: 1.5; + font-weight: 560; + letter-spacing: .08em; + text-transform: uppercase; +} + +.hero-core2__visual { + position: relative; + z-index: 3; + height: min(76vh, 760px); + min-height: 610px; + margin-right: clamp(-38px, -2vw, -4px); + perspective: 1600px; +} + +.hero-core2__visual::before { + content: ""; + position: absolute; + inset: 7% 2% 2% 4%; + border-radius: 50%; + pointer-events: none; + background: + radial-gradient(circle at 47% 48%, rgba(90, 221, 246, .07), transparent 28%), + radial-gradient(circle at 61% 53%, rgba(255, 228, 190, .024), transparent 22%); + filter: blur(26px); +} + +.hero-core2__canvas { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + display: block; + opacity: 0; + transition: opacity 1.1s ease; + filter: saturate(.96) contrast(1.02); +} +.hero-core2--ready .hero-core2__canvas { opacity: 1; } + +.hero-core2__fallback { + position: absolute; + left: 50%; + top: 50%; + width: min(52vw, 470px); + aspect-ratio: 1.08; + transform: translate(-48%, -50%) rotate(-7deg); + opacity: .82; + transition: opacity .7s ease; +} +.hero-core2--ready .hero-core2__fallback { opacity: 0; } +.hero-core2__fallback::before, +.hero-core2__fallback::after, +.hero-core2__fallback span { + content: ""; + position: absolute; + border: 1px solid rgba(255,255,255,.13); + background: linear-gradient(135deg, rgba(60,68,72,.86), rgba(11,14,16,.88)); + box-shadow: inset 0 1px rgba(255,255,255,.12), 0 30px 90px rgba(0,0,0,.46); +} +.hero-core2__fallback::before { inset: 12% 12% 12% 12%; clip-path: polygon(0 8%, 72% 0, 100% 27%, 88% 100%, 28% 88%, 0 57%); } +.hero-core2__fallback::after { inset: 28% 26% 25% 34%; background: radial-gradient(circle at 45% 52%, rgba(91,224,250,.48), rgba(8,30,36,.86) 52%, rgba(6,10,12,.96) 73%); filter: drop-shadow(0 0 24px rgba(80,218,245,.2)); } +.hero-core2__fallback span { inset: 18% 50% 52% 6%; transform: rotate(-18deg); } + +.hero-core2__stage-list { + position: absolute; + inset: 0; + z-index: 7; + margin: 0; + padding: 0; + list-style: none; + pointer-events: none; +} + +.hero-core2__stage { + position: absolute; + pointer-events: auto; +} +.hero-core2__stage:nth-child(1) { left: 2%; top: 16%; } +.hero-core2__stage:nth-child(2) { left: 9%; bottom: 17%; } +.hero-core2__stage:nth-child(3) { right: 3%; top: 25%; } +.hero-core2__stage:nth-child(4) { right: 5%; bottom: 13%; } + +.hero-core2__stage-button { + position: relative; + display: grid; + grid-template-columns: auto auto; + grid-template-areas: "num label" "num line"; + align-items: center; + column-gap: 10px; + padding: 9px 0; + border: 0; + color: rgba(222,232,235,.52); + background: transparent; + cursor: pointer; + font: inherit; + text-align: left; + transition: color .45s ease, transform .45s cubic-bezier(.2,.8,.2,1); +} +.hero-core2__stage-button::after { + content: ""; + grid-area: line; + width: 74px; + height: 1px; + margin-top: 7px; + transform-origin: left center; + transform: scaleX(.38); + background: linear-gradient(90deg, rgba(208,227,233,.28), rgba(114,230,255,0)); + transition: transform .55s cubic-bezier(.2,.8,.2,1), background .45s ease, box-shadow .45s ease; +} +.hero-core2__stage-num { + grid-area: num; + color: rgba(180,202,208,.34); + font-size: 10px; + line-height: 1; + font-weight: 760; + letter-spacing: .14em; + transition: color .45s ease; +} +.hero-core2__stage-label { + grid-area: label; + font-size: 11px; + line-height: 1; + font-weight: 720; + letter-spacing: .14em; + text-transform: uppercase; +} +.hero-core2__stage.is-active .hero-core2__stage-button, +.hero-core2__stage-button:hover, +.hero-core2__stage-button:focus-visible { + color: rgba(241,250,252,.93); + transform: translateX(3px); +} +.hero-core2__stage.is-active .hero-core2__stage-button::after, +.hero-core2__stage-button:hover::after, +.hero-core2__stage-button:focus-visible::after { + transform: scaleX(1); + background: linear-gradient(90deg, rgba(114,230,255,.9), rgba(114,230,255,.04)); + box-shadow: 0 0 13px rgba(114,230,255,.24); +} +.hero-core2__stage.is-active .hero-core2__stage-num { color: rgba(114,230,255,.82); } +.hero-core2__stage-button:focus-visible { outline: 1px solid rgba(114,230,255,.46); outline-offset: 6px; border-radius: 2px; } + +.hero-core2__sr { + position: absolute !important; + width: 1px !important; + height: 1px !important; + padding: 0 !important; + margin: -1px !important; + overflow: hidden !important; + clip: rect(0,0,0,0) !important; + white-space: nowrap !important; + border: 0 !important; +} + +.hero-core2__status { + position: absolute; + right: 2%; + top: 5%; + z-index: 8; + color: rgba(198,219,225,.28); + font: 600 8.5px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace; + letter-spacing: .12em; + text-transform: uppercase; + pointer-events: none; +} +.hero-core2--ready .hero-core2__status::before { content: "SYSTEM / LIVE"; } +.hero-core2--fallback .hero-core2__status::before { content: "SYSTEM / FALLBACK"; } + +@media (max-width: 1220px) { + .hero-core2__shell { grid-template-columns: minmax(0, .9fr) minmax(500px, 1.1fr); gap: 18px; } + .hero-core2__title { font-size: clamp(52px, 5vw, 70px); } + .hero-core2__visual { min-height: 560px; } + .hero-core2__stage:nth-child(1) { left: 0; } + .hero-core2__stage:nth-child(3) { right: 0; } +} + +@media (max-width: 980px) { + :root { --core2-header: 72px; } + .hero-core2 { overflow: visible; } + .hero-core2__shell { + min-height: auto; + padding: calc(var(--core2-header) + 34px) 24px 34px; + grid-template-columns: 1fr; + gap: 18px; + } + .hero-core2__copy { width: min(100%, 720px); } + .hero-core2__title { max-width: 13ch; font-size: clamp(48px, 8vw, 70px); line-height: .98; } + .hero-core2__lead { max-width: 690px; } + .hero-core2__visual { + width: min(100%, 850px); + height: min(60vw, 590px); + min-height: 500px; + margin: -4px auto 0; + } +} + +@media (max-width: 700px) { + body.hero-core2-page::before { background-size: 58px 58px; opacity: .14; } + .hero-core2__shell { padding: calc(var(--core2-header) + 26px) 19px 24px; gap: 10px; } + .hero-core2__eyebrow { margin-bottom: 13px; font-size: 9.5px; letter-spacing: .14em; } + .hero-core2__eyebrow::before { width: 25px; } + .hero-core2__title { max-width: 14ch; font-size: clamp(42px, 12vw, 58px); letter-spacing: -.052em; } + .hero-core2__lead { margin-top: 19px; font-size: 15px; line-height: 1.55; } + .hero-core2__actions { margin-top: 22px; gap: 10px; } + .hero-core2__button { min-height: 46px; padding: 0 16px; font-size: 10.5px; } + .hero-core2__microcopy { max-width: 245px; font-size: 10.8px; } + .hero-core2__accountability { margin-top: 16px; font-size: 9px; letter-spacing: .055em; } + .hero-core2__visual { + height: 410px; + min-height: 410px; + width: calc(100% + 22px); + margin-left: -11px; + margin-right: -11px; + } + .hero-core2__visual::before { inset: 4% 0 0; } + .hero-core2__status { display: none; } + .hero-core2__stage-list { + inset: auto 4px 6px 4px; + display: grid; + grid-template-columns: repeat(4, minmax(0,1fr)); + gap: 5px; + } + .hero-core2__stage { position: static; min-width: 0; } + .hero-core2__stage-button { + width: 100%; + grid-template-columns: 1fr; + grid-template-areas: "num" "label" "line"; + gap: 4px; + padding: 8px 3px; + text-align: center; + justify-items: center; + } + .hero-core2__stage-button::after { width: 100%; max-width: 62px; transform-origin: center; margin-top: 2px; } + .hero-core2__stage-label { font-size: 8px; letter-spacing: .08em; white-space: nowrap; } + .hero-core2__stage-num { font-size: 8px; } + .hero-core2__stage.is-active .hero-core2__stage-button, + .hero-core2__stage-button:hover, + .hero-core2__stage-button:focus-visible { transform: translateY(-2px); } +} + +@media (max-width: 390px) { + .hero-core2__shell { padding-left: 16px; padding-right: 16px; } + .hero-core2__title { font-size: clamp(39px, 11.4vw, 48px); } + .hero-core2__lead { font-size: 14.5px; } + .hero-core2__actions { align-items: stretch; } + .hero-core2__button { min-height: 44px; } + .hero-core2__visual { height: 365px; min-height: 365px; } + .hero-core2__stage-label { font-size: 7.4px; } +} + +@media (max-height: 700px) and (min-width: 701px) { + .hero-core2__shell { padding-top: calc(var(--core2-header) + 24px); padding-bottom: 22px; } + .hero-core2__title { font-size: clamp(48px, 4.55vw, 68px); } + .hero-core2__lead { margin-top: 18px; font-size: 15px; } + .hero-core2__actions { margin-top: 20px; } + .hero-core2__accountability { margin-top: 15px; } + .hero-core2__visual { height: 68vh; min-height: 480px; } +} + +@media (prefers-reduced-motion: reduce) { + .hero-core2__canvas, + .hero-core2__fallback, + .hero-core2__button, + .hero-core2__stage-button, + .hero-core2__stage-button::after { transition-duration: .01ms !important; } +} From 2f52e9cd14511254068cd363db2d8e53e2e6659f Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 01:58:04 -0700 Subject: [PATCH 04/69] Build sculptural WebGL2 Core and signal-field motion --- assets/js/hero-premium-core-2.js | 590 +++++++++++++++++++++++++++++++ 1 file changed, 590 insertions(+) create mode 100644 assets/js/hero-premium-core-2.js diff --git a/assets/js/hero-premium-core-2.js b/assets/js/hero-premium-core-2.js new file mode 100644 index 00000000..b779cdf4 --- /dev/null +++ b/assets/js/hero-premium-core-2.js @@ -0,0 +1,590 @@ +(() => { + 'use strict'; + + const root = document.documentElement; + const canvas = document.querySelector('[data-hero-core2-canvas]'); + const visual = document.querySelector('[data-hero-core2-visual]'); + const stageItems = [...document.querySelectorAll('[data-hero-core2-stage]')]; + const stageButtons = [...document.querySelectorAll('[data-hero-core2-stage-button]')]; + if (!canvas || !visual) return; + + const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)'); + const coarsePointer = window.matchMedia('(pointer: coarse)'); + let motionReduced = reducedMotion.matches; + let activeStage = motionReduced ? 3 : 0; + let narrativeTimers = []; + let replayTimer = null; + let manualStageUntil = 0; + + const setActiveStage = (index, manual = false) => { + activeStage = Math.max(0, Math.min(3, index)); + stageItems.forEach((item, i) => item.classList.toggle('is-active', i === activeStage)); + stageButtons.forEach((button, i) => button.setAttribute('aria-current', i === activeStage ? 'step' : 'false')); + if (manual) manualStageUntil = performance.now() + 9000; + }; + + const clearNarrative = () => { + narrativeTimers.forEach(window.clearTimeout); + narrativeTimers = []; + if (replayTimer) window.clearInterval(replayTimer); + replayTimer = null; + }; + + const runNarrative = () => { + if (motionReduced) { + setActiveStage(3); + return; + } + narrativeTimers.forEach(window.clearTimeout); + narrativeTimers = []; + const beats = [[900, 0], [3200, 1], [5600, 2], [8100, 3]]; + beats.forEach(([delay, stage]) => { + narrativeTimers.push(window.setTimeout(() => { + if (performance.now() < manualStageUntil) return; + setActiveStage(stage); + }, delay)); + }); + }; + + const scheduleNarrative = () => { + clearNarrative(); + runNarrative(); + if (!motionReduced) { + replayTimer = window.setInterval(() => { + if (document.hidden || performance.now() < manualStageUntil) return; + runNarrative(); + }, 24000); + } + }; + + stageButtons.forEach((button, i) => { + button.addEventListener('mouseenter', () => setActiveStage(i, true)); + button.addEventListener('focus', () => setActiveStage(i, true)); + button.addEventListener('click', () => setActiveStage(i, true)); + }); + + setActiveStage(activeStage); + scheduleNarrative(); + + reducedMotion.addEventListener?.('change', (event) => { + motionReduced = event.matches; + scheduleNarrative(); + }); + + const gl = canvas.getContext('webgl2', { + alpha: true, + antialias: false, + depth: false, + stencil: false, + premultipliedAlpha: false, + preserveDrawingBuffer: false, + powerPreference: 'high-performance' + }); + + if (!gl) { + root.classList.add('hero-core2--fallback'); + return; + } + + const vertexSource = `#version 300 es + precision highp float; + const vec2 POS[3] = vec2[3]( + vec2(-1.0, -1.0), + vec2( 3.0, -1.0), + vec2(-1.0, 3.0) + ); + void main() { + gl_Position = vec4(POS[gl_VertexID], 0.0, 1.0); + } + `; + + const fragmentSource = `#version 300 es + precision highp float; + + uniform vec2 uResolution; + uniform vec2 uPointer; + uniform float uTime; + uniform float uStage; + uniform float uMotion; + uniform float uQuality; + + out vec4 outColor; + + mat2 rot(float a) { + float c = cos(a), s = sin(a); + return mat2(c, -s, s, c); + } + + float hash21(vec2 p) { + p = fract(p * vec2(123.34, 456.21)); + p += dot(p, p + 45.32); + return fract(p.x * p.y); + } + + float sdRoundBox(vec3 p, vec3 b, float r) { + vec3 q = abs(p) - b + r; + return min(max(q.x, max(q.y, q.z)), 0.0) + length(max(q, 0.0)) - r; + } + + float sdEllipsoid(vec3 p, vec3 r) { + float k0 = length(p / r); + float k1 = length(p / (r * r)); + return k0 * (k0 - 1.0) / max(k1, 0.0001); + } + + float sdPlane(vec3 p, vec3 n, float h) { + return dot(p, n) + h; + } + + float stageYaw() { + if (uStage < 0.5) return -0.12; + if (uStage < 1.5) return -0.035; + if (uStage < 2.5) return 0.075; + return 0.14; + } + + float stagePitch() { + if (uStage < 0.5) return 0.06; + if (uStage < 1.5) return 0.11; + if (uStage < 2.5) return 0.045; + return -0.025; + } + + vec3 objectSpace(vec3 p) { + p.y -= 0.015; + float driftY = uMotion * (0.055 * sin(uTime * 0.22) + 0.026 * sin(uTime * 0.071 + 1.7)); + float driftX = uMotion * (0.028 * sin(uTime * 0.17 + 0.8)); + float yaw = -0.22 + stageYaw() + driftY + uPointer.x * 0.055 * uMotion; + float pitch = 0.08 + stagePitch() + driftX - uPointer.y * 0.035 * uMotion; + p.xz = rot(-yaw) * p.xz; + p.yz = rot(-pitch) * p.yz; + return p; + } + + float innerDistanceFromObject(vec3 q) { + vec3 iq = q - vec3(0.11, -0.015, 0.035); + iq.xy = rot(0.10 + uMotion * 0.035 * sin(uTime * 0.31)) * iq.xy; + float d0 = sdEllipsoid(iq, vec3(0.49, 0.56, 0.34)); + vec3 iq2 = iq - vec3(0.07, 0.04, -0.02); + iq2.xz = rot(-0.42 - uMotion * uTime * 0.018) * iq2.xz; + float d1 = sdRoundBox(iq2, vec3(0.30, 0.40, 0.24), 0.19); + return min(d0, d1 + 0.035); + } + + vec2 mapScene(vec3 p) { + vec3 q = objectSpace(p); + vec2 res = vec2(1000.0, 0.0); + + vec3 a = q - vec3(-0.53, 0.02, 0.01); + a.xy = rot(-0.075) * a.xy; + float dA = sdRoundBox(a, vec3(0.285, 0.91, 0.47), 0.155); + if (dA < res.x) res = vec2(dA, 1.0); + + vec3 b = q - vec3(0.11, 0.73, 0.055); + b.xy = rot(-0.17) * b.xy; + b.xz = rot(0.05) * b.xz; + float dB = sdRoundBox(b, vec3(0.78, 0.255, 0.43), 0.135); + if (dB < res.x) res = vec2(dB, 2.0); + + vec3 c = q - vec3(0.20, -0.72, -0.015); + c.xy = rot(0.115) * c.xy; + c.xz = rot(-0.08) * c.xz; + float dC = sdRoundBox(c, vec3(0.69, 0.255, 0.455), 0.14); + if (dC < res.x) res = vec2(dC, 1.0); + + vec3 d = q - vec3(0.71, 0.10, -0.19); + d.yz = rot(0.19) * d.yz; + d.xz = rot(0.23) * d.xz; + float dD = sdRoundBox(d, vec3(0.245, 0.62, 0.30), 0.13); + if (dD < res.x) res = vec2(dD, 2.0); + + vec3 rear = q - vec3(0.04, -0.02, -0.45); + rear.xy = rot(-0.045) * rear.xy; + float dRear = sdRoundBox(rear, vec3(0.68, 0.68, 0.095), 0.07); + if (dRear < res.x) res = vec2(dRear, 1.0); + + vec3 glass = q - vec3(0.18, 0.015, 0.385); + glass.xy = rot(0.055) * glass.xy; + float dGlass = sdRoundBox(glass, vec3(0.47, 0.50, 0.055), 0.065); + if (dGlass < res.x) res = vec2(dGlass, 3.0); + + float dInner = innerDistanceFromObject(q); + if (dInner < res.x) res = vec2(dInner, 4.0); + + float floorD = sdPlane(p, vec3(0.0, 1.0, 0.0), 1.28); + if (floorD < res.x) res = vec2(floorD, 6.0); + + return res; + } + + vec3 calcNormal(vec3 p) { + vec2 e = vec2(0.0016, 0.0); + float d = mapScene(p).x; + return normalize(vec3( + mapScene(p + e.xyy).x - d, + mapScene(p + e.yxy).x - d, + mapScene(p + e.yyx).x - d + )); + } + + float softShadow(vec3 ro, vec3 rd, float mint, float maxt) { + float res = 1.0; + float t = mint; + for (int i = 0; i < 26; i++) { + float h = mapScene(ro + rd * t).x; + res = min(res, 14.0 * h / t); + t += clamp(h, 0.02, 0.18); + if (h < 0.001 || t > maxt) break; + } + return clamp(res, 0.0, 1.0); + } + + float ambientOcclusion(vec3 p, vec3 n) { + float occ = 0.0; + float sca = 1.0; + for (int i = 0; i < 4; i++) { + float h = 0.035 + 0.085 * float(i); + float d = mapScene(p + n * h).x; + occ += (h - d) * sca; + sca *= 0.68; + } + return clamp(1.0 - 1.35 * occ, 0.0, 1.0); + } + + vec3 materialColor(float id, vec3 p, vec3 n, vec3 rd, float glow) { + vec3 graphite = vec3(0.085, 0.103, 0.112); + vec3 steel = vec3(0.18, 0.205, 0.214); + vec3 cyan = vec3(0.31, 0.83, 0.98); + vec3 warm = vec3(0.86, 0.72, 0.52); + + vec3 keyPos = vec3(-2.5, 3.2, 4.4); + vec3 rimPos = vec3(3.6, 1.6, 2.3); + vec3 l = normalize(keyPos - p); + vec3 l2 = normalize(rimPos - p); + vec3 v = normalize(-rd); + float ndl = max(dot(n, l), 0.0); + float ndl2 = max(dot(n, l2), 0.0); + float shadow = softShadow(p + n * 0.008, l, 0.025, 6.0); + float ao = ambientOcclusion(p, n); + float fres = pow(1.0 - max(dot(n, v), 0.0), 4.0); + + if (id < 1.5) { + float rough = 0.44 + 0.08 * sin(p.x * 8.0 + p.y * 4.0); + vec3 h = normalize(l + v); + float spec = pow(max(dot(n, h), 0.0), mix(52.0, 95.0, 1.0 - rough)); + vec3 base = graphite * (0.42 + 0.82 * ndl * shadow) * ao; + base += vec3(0.36, 0.40, 0.42) * spec * 0.48; + base += cyan * fres * 0.11; + base += warm * ndl2 * fres * 0.045; + return base; + } + + if (id < 2.5) { + vec3 h = normalize(l + v); + float spec = pow(max(dot(n, h), 0.0), 88.0); + vec3 base = steel * (0.46 + 0.92 * ndl * shadow) * ao; + base += vec3(0.72,0.78,0.80) * spec * 0.72; + base += cyan * fres * 0.13; + base += warm * ndl2 * fres * 0.075; + return base; + } + + if (id < 3.5) { + float facing = abs(dot(n, v)); + vec3 smoke = vec3(0.035, 0.060, 0.067); + vec3 base = smoke * (0.42 + ndl * 0.32); + base += cyan * (0.08 + fres * 0.35 + glow * 0.22); + base += vec3(0.66,0.77,0.79) * pow(1.0 - facing, 2.8) * 0.10; + return base; + } + + if (id < 4.5) { + float pulse = 0.78 + 0.12 * uMotion * sin(uTime * 1.25 + p.y * 5.0) + uStage * 0.035; + vec3 inner = mix(vec3(0.035,0.17,0.21), cyan, 0.54 + 0.14 * fres); + inner *= pulse * (0.72 + ndl * 0.18); + inner += cyan * (0.24 + fres * 0.30); + return inner; + } + + vec3 floorBase = vec3(0.012, 0.015, 0.016); + float radial = exp(-0.55 * dot(p.xz, p.xz)); + return floorBase + cyan * radial * 0.008; + } + + vec2 curveDistance(vec2 p, vec2 a, vec2 b, vec2 c, vec2 d) { + float md = 10.0; + float mt = 0.0; + vec2 prev = a; + for (int i = 1; i <= 34; i++) { + float t = float(i) / 34.0; + float s = 1.0 - t; + vec2 cur = s*s*s*a + 3.0*s*s*t*b + 3.0*s*t*t*c + t*t*t*d; + vec2 pa = p - prev; + vec2 ba = cur - prev; + float h = clamp(dot(pa,ba) / max(dot(ba,ba), 0.00001), 0.0, 1.0); + float dd = length(pa - ba * h); + if (dd < md) { + md = dd; + mt = (float(i - 1) + h) / 34.0; + } + prev = cur; + } + return vec2(md, mt); + } + + vec3 signalField(vec2 uv, bool objectHit, float objectDepth) { + vec3 cyan = vec3(0.31, 0.83, 0.98); + vec3 ice = vec3(0.58, 0.91, 1.0); + vec3 col = vec3(0.0); + + vec2 c1 = curveDistance(uv, + vec2(-1.05, 0.34), vec2(-0.48, 0.60), vec2(-0.39, -0.25), vec2(1.06, -0.08)); + vec2 c2 = curveDistance(uv, + vec2(-0.91, -0.52), vec2(-0.24, -0.11), vec2(0.17, -0.63), vec2(0.96, -0.27)); + vec2 c3 = curveDistance(uv, + vec2(-0.80, 0.69), vec2(-0.16, 0.17), vec2(0.28, 0.54), vec2(0.91, 0.42)); + + float stagePhase = uStage * 0.095; + float line1 = 1.0 - smoothstep(0.0014, 0.009, c1.x); + float line2 = 1.0 - smoothstep(0.0012, 0.007, c2.x); + float line3 = 1.0 - smoothstep(0.0010, 0.006, c3.x); + + float fragDash = mix(0.32, 0.74, smoothstep(0.38, 0.67, c1.y)); + float dashed = smoothstep(0.18, 0.48, fract(c1.y * 31.0 - uTime * 0.055 * uMotion)); + line1 *= mix(dashed, 1.0, fragDash); + + float pulse1 = exp(-150.0 * pow(abs(fract(c1.y - uTime * 0.060 * uMotion - stagePhase) - 0.5), 2.0)); + float pulse2 = exp(-135.0 * pow(abs(fract(c2.y - uTime * 0.047 * uMotion - 0.24 - stagePhase) - 0.5), 2.0)); + float pulse3 = exp(-165.0 * pow(abs(fract(c3.y - uTime * 0.038 * uMotion - 0.58 - stagePhase) - 0.5), 2.0)); + + float behind1 = step(0.34, c1.y) * (1.0 - step(0.66, c1.y)); + float behind3 = step(0.43, c3.y) * (1.0 - step(0.72, c3.y)); + if (objectHit && objectDepth < 6.0) { + line1 *= mix(1.0, 0.09, behind1); + line3 *= mix(1.0, 0.12, behind3); + } + + col += cyan * line1 * (0.16 + pulse1 * 0.74); + col += ice * line2 * (0.075 + pulse2 * 0.33); + col += cyan * line3 * (0.055 + pulse3 * 0.28); + + float branch = 1.0 - smoothstep(0.0012, 0.006, curveDistance(uv, + vec2(-0.10, 0.02), vec2(0.12, 0.20), vec2(0.32, 0.08), vec2(0.54, 0.17)).x); + col += cyan * branch * 0.07 * smoothstep(0.6, 2.6, uStage); + + return col; + } + + vec3 aces(vec3 x) { + float a = 2.51; + float b = 0.03; + float c = 2.43; + float d = 0.59; + float e = 0.14; + return clamp((x * (a * x + b)) / (x * (c * x + d) + e), 0.0, 1.0); + } + + void main() { + vec2 frag = gl_FragCoord.xy; + vec2 p = (2.0 * frag - uResolution.xy) / uResolution.y; + p.x += 0.015; + + vec3 ro = vec3(0.02 + uPointer.x * 0.055 * uMotion, 0.07 + uPointer.y * 0.035 * uMotion, 4.35); + vec3 ta = vec3(0.055, -0.015, 0.0); + vec3 ww = normalize(ta - ro); + vec3 uu = normalize(cross(ww, vec3(0.0, 1.0, 0.0))); + vec3 vv = cross(uu, ww); + vec3 rd = normalize(uu * p.x + vv * p.y + ww * 2.28); + + vec3 bg = vec3(0.0065, 0.009, 0.0105); + float halo = exp(-1.9 * dot(p - vec2(0.06, -0.02), p - vec2(0.06, -0.02))); + bg += vec3(0.018, 0.046, 0.052) * halo * 0.52; + float warmEnv = exp(-5.5 * dot(p - vec2(0.58, 0.22), p - vec2(0.58, 0.22))); + bg += vec3(0.042, 0.028, 0.016) * warmEnv * 0.18; + + float grain = hash21(frag + floor(uTime * 2.0 * uMotion)); + bg += (grain - 0.5) * 0.0035; + + float t = 0.0; + float id = 0.0; + float glow = 0.0; + bool hit = false; + int maxSteps = int(mix(48.0, 76.0, uQuality)); + + for (int i = 0; i < 78; i++) { + if (i > maxSteps) break; + vec3 pos = ro + rd * t; + vec2 h = mapScene(pos); + vec3 q = objectSpace(pos); + float innerD = innerDistanceFromObject(q); + glow += exp(-10.0 * abs(innerD)) * 0.0105 * exp(-0.08 * t); + if (h.x < 0.0016) { + hit = true; + id = h.y; + break; + } + t += max(h.x * 0.78, 0.009); + if (t > 10.0) break; + } + + vec3 color = bg; + if (hit) { + vec3 pos = ro + rd * t; + vec3 n = calcNormal(pos); + color = materialColor(id, pos, n, rd, glow); + + if (id > 5.5) { + float coreShadow = exp(-1.65 * (pos.x * pos.x + pos.z * pos.z)); + color *= 1.0 - 0.72 * coreShadow; + color += vec3(0.31,0.83,0.98) * exp(-3.2 * (pos.x*pos.x + pos.z*pos.z)) * 0.006; + } + + float fog = 1.0 - exp(-0.035 * t * t); + color = mix(color, bg, fog * 0.42); + } + + color += vec3(0.20, 0.76, 0.93) * min(glow, 0.52) * (0.34 + 0.08 * uStage); + vec2 signalUv = p * vec2(0.92, 0.92); + color += signalField(signalUv, hit && id < 5.5, t); + + float vignette = 1.0 - smoothstep(0.32, 1.62, length(p * vec2(0.76, 0.92))); + color *= mix(0.62, 1.0, vignette); + color = aces(color * 1.22); + color = pow(color, vec3(0.94)); + + float alpha = smoothstep(0.0, 0.16, max(max(color.r, color.g), color.b)); + outColor = vec4(color, max(alpha, 0.82)); + } + `; + + const compile = (type, source) => { + const shader = gl.createShader(type); + gl.shaderSource(shader, source); + gl.compileShader(shader); + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + const message = gl.getShaderInfoLog(shader) || 'Unknown shader compile failure'; + gl.deleteShader(shader); + throw new Error(message); + } + return shader; + }; + + let program; + try { + const vertex = compile(gl.VERTEX_SHADER, vertexSource); + const fragment = compile(gl.FRAGMENT_SHADER, fragmentSource); + program = gl.createProgram(); + gl.attachShader(program, vertex); + gl.attachShader(program, fragment); + gl.linkProgram(program); + gl.deleteShader(vertex); + gl.deleteShader(fragment); + if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { + throw new Error(gl.getProgramInfoLog(program) || 'Hero Core 2.0 program link failed'); + } + } catch (error) { + console.error('[Hero Core 2.0]', error); + root.classList.add('hero-core2--fallback'); + return; + } + + gl.useProgram(program); + const uniforms = { + resolution: gl.getUniformLocation(program, 'uResolution'), + pointer: gl.getUniformLocation(program, 'uPointer'), + time: gl.getUniformLocation(program, 'uTime'), + stage: gl.getUniformLocation(program, 'uStage'), + motion: gl.getUniformLocation(program, 'uMotion'), + quality: gl.getUniformLocation(program, 'uQuality') + }; + + let pointer = { x: 0, y: 0 }; + let pointerTarget = { x: 0, y: 0 }; + let visible = true; + let renderScale = 1; + let quality = 1; + let firstFrame = true; + let frameSamples = []; + let lastFrame = performance.now(); + + const mobileViewport = () => window.innerWidth <= 700; + + const resize = () => { + const rect = visual.getBoundingClientRect(); + const cssWidth = Math.max(1, Math.round(rect.width)); + const cssHeight = Math.max(1, Math.round(rect.height)); + const dprCap = mobileViewport() ? 1.15 : 1.55; + const dpr = Math.min(window.devicePixelRatio || 1, dprCap) * renderScale; + const width = Math.max(2, Math.round(cssWidth * dpr)); + const height = Math.max(2, Math.round(cssHeight * dpr)); + if (canvas.width !== width || canvas.height !== height) { + canvas.width = width; + canvas.height = height; + gl.viewport(0, 0, width, height); + } + }; + + const resizeObserver = new ResizeObserver(resize); + resizeObserver.observe(visual); + window.addEventListener('resize', resize, { passive: true }); + resize(); + + const updatePointer = (event) => { + if (motionReduced || coarsePointer.matches) return; + const rect = visual.getBoundingClientRect(); + const x = (event.clientX - rect.left) / Math.max(rect.width, 1); + const y = (event.clientY - rect.top) / Math.max(rect.height, 1); + pointerTarget.x = (Math.max(0, Math.min(1, x)) - 0.5) * 2; + pointerTarget.y = (0.5 - Math.max(0, Math.min(1, y))) * 2; + }; + visual.addEventListener('pointermove', updatePointer, { passive: true }); + visual.addEventListener('pointerleave', () => { pointerTarget.x = 0; pointerTarget.y = 0; }); + + const visibilityObserver = new IntersectionObserver((entries) => { + visible = entries.some((entry) => entry.isIntersecting); + }, { threshold: 0.02 }); + visibilityObserver.observe(visual); + + const adaptPerformance = (delta) => { + if (firstFrame || motionReduced) return; + frameSamples.push(delta); + if (frameSamples.length < 75) return; + const avg = frameSamples.reduce((sum, value) => sum + value, 0) / frameSamples.length; + frameSamples = []; + if (avg > 25 && renderScale > 0.74) { + renderScale = Math.max(0.74, renderScale * 0.86); + quality = Math.max(0.62, quality - 0.16); + resize(); + } + }; + + const start = performance.now(); + const render = (now) => { + requestAnimationFrame(render); + if (!visible || document.hidden) return; + + const delta = now - lastFrame; + lastFrame = now; + adaptPerformance(delta); + + pointer.x += (pointerTarget.x - pointer.x) * 0.035; + pointer.y += (pointerTarget.y - pointer.y) * 0.035; + + const elapsed = motionReduced ? 6.4 : (now - start) * 0.001; + gl.useProgram(program); + gl.uniform2f(uniforms.resolution, canvas.width, canvas.height); + gl.uniform2f(uniforms.pointer, pointer.x, pointer.y); + gl.uniform1f(uniforms.time, elapsed); + gl.uniform1f(uniforms.stage, activeStage); + gl.uniform1f(uniforms.motion, motionReduced ? 0 : 1); + gl.uniform1f(uniforms.quality, mobileViewport() ? Math.min(quality, 0.78) : quality); + gl.drawArrays(gl.TRIANGLES, 0, 3); + + if (firstFrame) { + firstFrame = false; + root.classList.add('hero-core2--ready'); + } + }; + + requestAnimationFrame(render); +})(); From cb9124bad2ec0828341d4e41e4454cac426a7199 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:00:12 -0700 Subject: [PATCH 05/69] Add EN Premium Core 2.0 isolated preview --- hero-premium-core-2-preview/index.html | 81 ++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 hero-premium-core-2-preview/index.html diff --git a/hero-premium-core-2-preview/index.html b/hero-premium-core-2-preview/index.html new file mode 100644 index 00000000..53b94e95 --- /dev/null +++ b/hero-premium-core-2-preview/index.html @@ -0,0 +1,81 @@ +--- +permalink: /hero-premium-core-2-preview/ +--- + + + + + + + ProAI Expert — Premium Core 2.0 Hero EN + + + + + + + + Skip to main content + + {% include header-system/header.html lang="en" current_page="home" locale_url="/ru/hero-premium-core-2-preview/" variant="standard" %} + +
+
+
+
+

AI SYSTEMS · AUTOMATION · PREMIUM WEBSITES

+

From first impression to result — one system.

+

We build premium websites for service businesses and connect them with AI and automation. Customers understand your services and reach out with the right information; you respond faster and spend less time on routine work. Key decisions stay with you.

+ +
+
+ + Request a Review + +

Briefly describe the challenge. We’ll recommend where to start.

+
+ + View Work + +
+ +

Washington-based · Working across the U.S. · EN / RU / UA

+
+ +
+

Connected client journey: 01 TRUST. 02 INQUIRY. 03 RESPONSE. 04 RESULT.

+ + + + +
    +
  1. + +
  2. +
  3. + +
  4. +
  5. + +
  6. +
  7. + +
  8. +
+
+
+
+
+ + + + + From b3deac62dc19df291781541d79f9dd5686fd0a80 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:00:40 -0700 Subject: [PATCH 06/69] Add RU Premium Core 2.0 isolated preview --- ru/hero-premium-core-2-preview/index.html | 81 +++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 ru/hero-premium-core-2-preview/index.html diff --git a/ru/hero-premium-core-2-preview/index.html b/ru/hero-premium-core-2-preview/index.html new file mode 100644 index 00000000..a5946cb0 --- /dev/null +++ b/ru/hero-premium-core-2-preview/index.html @@ -0,0 +1,81 @@ +--- +permalink: /ru/hero-premium-core-2-preview/ +--- + + + + + + + ProAI Expert — Premium Core 2.0 Hero RU + + + + + + + + Перейти к содержимому + + {% include header-system/header.html lang="ru" current_page="home" locale_url="/hero-premium-core-2-preview/" variant="standard" %} + +
+
+
+
+

AI-СИСТЕМЫ · АВТОМАТИЗАЦИЯ · ПРЕМИАЛЬНЫЕ САЙТЫ

+

От первого впечатления до результата — одна система.

+

Создаём премиальные сайты для компаний сферы услуг и соединяем их с AI и автоматизацией. Клиенту проще понять ваши услуги и обратиться с нужной информацией, вам — быстрее ответить и меньше заниматься рутиной. Ключевые решения — за вами.

+ +
+
+ + Запросить разбор + +

Коротко опишите задачу. Мы предложим, с чего разумнее начать.

+
+ + Смотреть проекты + +
+ +

Штат Вашингтон · Работаем по всей США · EN / RU / UA

+
+ +
+

Путь клиента: 01 ДОВЕРИЕ. 02 ОБРАЩЕНИЕ. 03 ОТВЕТ. 04 РЕЗУЛЬТАТ.

+ + + + +
    +
  1. + +
  2. +
  3. + +
  4. +
  5. + +
  6. +
  7. + +
  8. +
+
+
+
+
+ + + + + From 05dc17f4a583b976a862d0e0ec7ec49b0d624570 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:01:14 -0700 Subject: [PATCH 07/69] Add Premium Core 2.0 browser owner-review capture --- tools/hero_premium_core_2_owner_review.mjs | 141 +++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 tools/hero_premium_core_2_owner_review.mjs diff --git a/tools/hero_premium_core_2_owner_review.mjs b/tools/hero_premium_core_2_owner_review.mjs new file mode 100644 index 00000000..4f748a1a --- /dev/null +++ b/tools/hero_premium_core_2_owner_review.mjs @@ -0,0 +1,141 @@ +import { chromium } from 'playwright'; +import fs from 'node:fs'; +import path from 'node:path'; +import { spawnSync } from 'node:child_process'; + +const base = process.env.CORE2_BASE_URL || 'http://127.0.0.1:4173'; +const out = process.env.CORE2_OUT || 'premium-core-2-owner-review'; +const routes = { + en: '/hero-premium-core-2-preview/', + ru: '/ru/hero-premium-core-2-preview/' +}; + +fs.rmSync(out, { recursive: true, force: true }); +fs.mkdirSync(out, { recursive: true }); + +const browser = await chromium.launch({ + headless: true, + args: [ + '--enable-webgl', + '--ignore-gpu-blocklist', + '--use-angle=swiftshader', + '--enable-unsafe-swiftshader' + ] +}); + +async function ready(page, route, reducedMotion = 'no-preference') { + const errors = []; + page.on('console', msg => { + if (msg.type() === 'error') errors.push(`console: ${msg.text()}`); + }); + page.on('pageerror', error => errors.push(`pageerror: ${error.message}`)); + await page.emulateMedia({ reducedMotion }); + await page.goto(`${base}${route}`, { waitUntil: 'networkidle' }); + await page.evaluate(async () => { if (document.fonts?.ready) await document.fonts.ready; }); + await page.waitForFunction(() => document.documentElement.classList.contains('hero-core2--ready'), null, { timeout: 20000 }); + await page.waitForTimeout(550); + if (errors.length) throw new Error(errors.join('\n')); + return errors; +} + +async function captureStatic({ locale, width, height, mobile, file }) { + const context = await browser.newContext({ + viewport: { width, height }, + deviceScaleFactor: 1, + isMobile: mobile, + hasTouch: mobile + }); + const page = await context.newPage(); + await ready(page, routes[locale]); + const diagnostics = await page.evaluate(() => ({ + ready: document.documentElement.classList.contains('hero-core2--ready'), + fallback: document.documentElement.classList.contains('hero-core2--fallback'), + scrollWidth: document.documentElement.scrollWidth, + innerWidth: window.innerWidth, + title: document.querySelector('.hero-core2__title')?.textContent?.trim(), + lead: document.querySelector('.hero-core2__lead')?.textContent?.trim(), + primary: document.querySelector('.hero-core2__button--primary span')?.textContent?.trim(), + stageLabels: [...document.querySelectorAll('.hero-core2__stage-label')].map(el => el.textContent.trim()), + canvas: (() => { + const c = document.querySelector('[data-hero-core2-canvas]'); + const gl = c?.getContext('webgl2'); + return { width: c?.width || 0, height: c?.height || 0, webgl2: !!gl }; + })() + })); + if (!diagnostics.ready || diagnostics.fallback || !diagnostics.canvas.webgl2) throw new Error(`${locale} ${width}x${height}: WebGL2 did not reach ready state`); + if (diagnostics.scrollWidth > diagnostics.innerWidth + 1) throw new Error(`${locale} ${width}x${height}: horizontal overflow ${diagnostics.scrollWidth} > ${diagnostics.innerWidth}`); + await page.screenshot({ path: path.join(out, file), fullPage: false }); + await context.close(); + return diagnostics; +} + +const diagnostics = { + enDesktop: await captureStatic({ locale: 'en', width: 1440, height: 900, mobile: false, file: 'CORE2_EN_DESKTOP_1440x900.png' }), + ruDesktop: await captureStatic({ locale: 'ru', width: 1440, height: 900, mobile: false, file: 'CORE2_RU_DESKTOP_1440x900.png' }), + enMobile: await captureStatic({ locale: 'en', width: 390, height: 844, mobile: true, file: 'CORE2_EN_MOBILE_390x844.png' }), + ruMobile: await captureStatic({ locale: 'ru', width: 390, height: 844, mobile: true, file: 'CORE2_RU_MOBILE_390x844.png' }), + enNarrow: await captureStatic({ locale: 'en', width: 320, height: 780, mobile: true, file: 'CORE2_EN_MOBILE_320x780.png' }) +}; + +// Reduced-motion runtime gate: WebGL remains available but the final/result state is static. +{ + const context = await browser.newContext({ viewport: { width: 390, height: 844 }, deviceScaleFactor: 1, isMobile: true, hasTouch: true }); + const page = await context.newPage(); + await ready(page, routes.en, 'reduce'); + const reduced = await page.evaluate(() => ({ + active: [...document.querySelectorAll('[data-hero-core2-stage]')].findIndex(el => el.classList.contains('is-active')), + ready: document.documentElement.classList.contains('hero-core2--ready') + })); + if (!reduced.ready || reduced.active !== 3) throw new Error(`Reduced-motion state invalid: ${JSON.stringify(reduced)}`); + await page.screenshot({ path: path.join(out, 'CORE2_EN_REDUCED_MOTION_390x844.png'), fullPage: false }); + await context.close(); +} + +// Browser-native desktop motion capture. +const videoDir = path.join(out, '.video-tmp'); +fs.mkdirSync(videoDir, { recursive: true }); +let webmPath; +{ + const context = await browser.newContext({ + viewport: { width: 1440, height: 900 }, + deviceScaleFactor: 1, + recordVideo: { dir: videoDir, size: { width: 1440, height: 900 } } + }); + const page = await context.newPage(); + await ready(page, routes.en); + const video = page.video(); + await page.waitForTimeout(9300); + await page.close(); + webmPath = await video.path(); + await context.close(); +} + +await browser.close(); + +const mp4 = path.join(out, 'CORE2_EN_DESKTOP_MOTION.mp4'); +const ff = spawnSync('ffmpeg', [ + '-y', '-i', webmPath, + '-c:v', 'libx264', '-preset', 'medium', '-crf', '20', + '-pix_fmt', 'yuv420p', '-movflags', '+faststart', + mp4 +], { stdio: 'inherit' }); +if (ff.status !== 0) process.exit(ff.status ?? 1); +fs.rmSync(videoDir, { recursive: true, force: true }); + +fs.writeFileSync(path.join(out, 'diagnostics.json'), JSON.stringify(diagnostics, null, 2) + '\n'); + +for (const file of [ + 'CORE2_EN_DESKTOP_1440x900.png', + 'CORE2_RU_DESKTOP_1440x900.png', + 'CORE2_EN_MOBILE_390x844.png', + 'CORE2_RU_MOBILE_390x844.png', + 'CORE2_EN_MOBILE_320x780.png', + 'CORE2_EN_REDUCED_MOTION_390x844.png', + 'CORE2_EN_DESKTOP_MOTION.mp4', + 'diagnostics.json' +]) { + const p = path.join(out, file); + if (!fs.existsSync(p) || fs.statSync(p).size < (file.endsWith('.json') ? 100 : 1000)) throw new Error(`Missing/empty owner-review output: ${p}`); +} + +console.log('Premium Core 2.0 owner-review package complete:', fs.readdirSync(out)); From 1a677e50524e6783dcd688b2eab1f025927c346c Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:01:47 -0700 Subject: [PATCH 08/69] Add Premium Core 2.0 owner-review QA workflow --- .../hero-premium-core-2-owner-review.yml | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 .github/workflows/hero-premium-core-2-owner-review.yml diff --git a/.github/workflows/hero-premium-core-2-owner-review.yml b/.github/workflows/hero-premium-core-2-owner-review.yml new file mode 100644 index 00000000..23a92d3b --- /dev/null +++ b/.github/workflows/hero-premium-core-2-owner-review.yml @@ -0,0 +1,141 @@ +name: Hero Premium Core 2.0 owner review + +on: + push: + branches: + - agent/hero-premium-core-2-r1 + paths: + - assets/css/hero-premium-core-2.css + - assets/js/hero-premium-core-2.js + - hero-premium-core-2-preview/** + - ru/hero-premium-core-2-preview/** + - tools/hero_premium_core_2_owner_review.mjs + - .github/workflows/hero-premium-core-2-owner-review.yml + - .github/hero-premium-core-2-run.txt + workflow_dispatch: + +permissions: + contents: read + actions: read + +jobs: + owner-preview: + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - name: Checkout isolated Premium Core branch + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: agent/hero-premium-core-2-r1 + + - name: Guard production and unrelated systems + shell: bash + run: | + set -euo pipefail + git fetch origin main --quiet + CHANGED="$(git diff --name-only origin/main...HEAD)" + if printf '%s\n' "$CHANGED" | grep -Eq '^(index\.html|ru/index\.html)$'; then + echo 'Production homepage route changed — forbidden in owner-review branch.' >&2 + exit 1 + fi + if printf '%s\n' "$CHANGED" | grep -E '^financialstream/' >/dev/null; then + echo 'Financial Stream changed — forbidden in Hero scope.' >&2 + exit 1 + fi + + - name: Verify final EN/RU copy locks in Premium Core preview + shell: bash + run: | + set -euo pipefail + python3 - <<'PY' + from pathlib import Path + en=Path('hero-premium-core-2-preview/index.html').read_text(encoding='utf-8') + ru=Path('ru/hero-premium-core-2-preview/index.html').read_text(encoding='utf-8') + en_locks=[ + 'AI SYSTEMS · AUTOMATION · PREMIUM WEBSITES', + 'From first impression to result — one system.', + 'We build premium websites for service businesses and connect them with AI and automation. Customers understand your services and reach out with the right information; you respond faster and spend less time on routine work. Key decisions stay with you.', + 'Request a Review', + 'Briefly describe the challenge. We’ll recommend where to start.', + 'View Work', + 'Washington-based · Working across the U.S. · EN / RU / UA', + '>TRUST<','>INQUIRY<','>RESPONSE<','>RESULT<' + ] + ru_locks=[ + 'AI-СИСТЕМЫ · АВТОМАТИЗАЦИЯ · ПРЕМИАЛЬНЫЕ САЙТЫ', + 'От первого впечатления до результата — одна система.', + 'Создаём премиальные сайты для компаний сферы услуг и соединяем их с AI и автоматизацией. Клиенту проще понять ваши услуги и обратиться с нужной информацией, вам — быстрее ответить и меньше заниматься рутиной. Ключевые решения — за вами.', + 'Запросить разбор', + 'Коротко опишите задачу. Мы предложим, с чего разумнее начать.', + 'Смотреть проекты', + 'Штат Вашингтон · Работаем по всей США · EN / RU / UA', + '>ДОВЕРИЕ<','>ОБРАЩЕНИЕ<','>ОТВЕТ<','>РЕЗУЛЬТАТ<' + ] + for lock in en_locks: + if lock not in en: raise SystemExit(f'Missing EN lock: {lock}') + for lock in ru_locks: + if lock not in ru: raise SystemExit(f'Missing RU lock: {lock}') + h1=en.split('

',1)[1].split('

',1)[0] + if '',1)[1].split('',1)[0] + if ' /tmp/core2-http.log 2>&1 & + sleep 2 + curl --fail http://127.0.0.1:4173/hero-premium-core-2-preview/ > /dev/null + curl --fail http://127.0.0.1:4173/ru/hero-premium-core-2-preview/ > /dev/null + + - name: Browser runtime and owner-review captures + run: node tools/hero_premium_core_2_owner_review.mjs + + - name: Static implementation guards + shell: bash + run: | + set -euo pipefail + grep -q 'sdRoundBox' assets/js/hero-premium-core-2.js + grep -q 'curveDistance' assets/js/hero-premium-core-2.js + grep -q 'innerDistanceFromObject' assets/js/hero-premium-core-2.js + grep -q 'requestAnimationFrame' assets/js/hero-premium-core-2.js + if grep -Eq 'THREE\.BoxGeometry|new THREE\.BoxGeometry|stroke-dasharray: *4, *12' assets/js/hero-premium-core-2.js assets/css/hero-premium-core-2.css; then + echo 'Rejected primitive/orbit language detected.' >&2 + exit 1 + fi + + - name: Upload Premium Core 2.0 owner-review package + uses: actions/upload-artifact@v4 + with: + name: PROAI_HERO_PREMIUM_CORE_2_OWNER_REVIEW + path: premium-core-2-owner-review/ + if-no-files-found: error + retention-days: 14 + + - name: Print diagnostics on failure + if: failure() + shell: bash + run: | + cat /tmp/core2-http.log || true + if test -f premium-core-2-owner-review/diagnostics.json; then cat premium-core-2-owner-review/diagnostics.json; fi From fe9ffd580ae331e63c309a1899ff1dd31bb20e40 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:04:49 -0700 Subject: [PATCH 09/69] Enable Premium Core 2.0 PR-based owner-review QA --- .github/workflows/hero-premium-core-2-owner-review.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/hero-premium-core-2-owner-review.yml b/.github/workflows/hero-premium-core-2-owner-review.yml index 23a92d3b..5736f7c1 100644 --- a/.github/workflows/hero-premium-core-2-owner-review.yml +++ b/.github/workflows/hero-premium-core-2-owner-review.yml @@ -12,6 +12,16 @@ on: - tools/hero_premium_core_2_owner_review.mjs - .github/workflows/hero-premium-core-2-owner-review.yml - .github/hero-premium-core-2-run.txt + pull_request: + branches: + - agent/hero-layered-25d-static-r1 + paths: + - assets/css/hero-premium-core-2.css + - assets/js/hero-premium-core-2.js + - hero-premium-core-2-preview/** + - ru/hero-premium-core-2-preview/** + - tools/hero_premium_core_2_owner_review.mjs + - .github/workflows/hero-premium-core-2-owner-review.yml workflow_dispatch: permissions: From e184c4377b09d6399958b014a87b0781da61aea8 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:11:15 -0700 Subject: [PATCH 10/69] Trigger Premium Core 2.0 owner-review QA --- .github/hero-premium-core-2-run.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/hero-premium-core-2-run.txt diff --git a/.github/hero-premium-core-2-run.txt b/.github/hero-premium-core-2-run.txt new file mode 100644 index 00000000..03850a9a --- /dev/null +++ b/.github/hero-premium-core-2-run.txt @@ -0,0 +1 @@ +2026-08-11T02:09:00-07:00 owner-review QA trigger From ff53e95b3af1c4d0fce38a59f287db112c797b47 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:12:42 -0700 Subject: [PATCH 11/69] Build Premium Core 2.0 R2 sculptural WebGL scene --- assets/js/hero-premium-core-2-r2.js | 588 ++++++++++++++++++++++++++++ 1 file changed, 588 insertions(+) create mode 100644 assets/js/hero-premium-core-2-r2.js diff --git a/assets/js/hero-premium-core-2-r2.js b/assets/js/hero-premium-core-2-r2.js new file mode 100644 index 00000000..a3e81961 --- /dev/null +++ b/assets/js/hero-premium-core-2-r2.js @@ -0,0 +1,588 @@ +(() => { + 'use strict'; + + const root = document.documentElement; + const canvas = document.querySelector('[data-hero-core2-canvas]'); + const visual = document.querySelector('[data-hero-core2-visual]'); + const stageItems = [...document.querySelectorAll('[data-hero-core2-stage]')]; + const stageButtons = [...document.querySelectorAll('[data-hero-core2-stage-button]')]; + if (!canvas || !visual) return; + + const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)'); + const coarsePointer = window.matchMedia('(pointer: coarse)'); + let motionReduced = reducedMotion.matches; + let activeStage = motionReduced ? 3 : 0; + let narrativeTimers = []; + let replayTimer = null; + let manualStageUntil = 0; + + const setActiveStage = (index, manual = false) => { + activeStage = Math.max(0, Math.min(3, index)); + stageItems.forEach((item, i) => item.classList.toggle('is-active', i === activeStage)); + stageButtons.forEach((button, i) => button.setAttribute('aria-current', i === activeStage ? 'step' : 'false')); + if (manual) manualStageUntil = performance.now() + 9000; + }; + + const clearNarrative = () => { + narrativeTimers.forEach(window.clearTimeout); + narrativeTimers = []; + if (replayTimer) window.clearInterval(replayTimer); + replayTimer = null; + }; + + const runNarrative = () => { + if (motionReduced) { + setActiveStage(3); + return; + } + narrativeTimers.forEach(window.clearTimeout); + narrativeTimers = []; + [[800,0],[3000,1],[5400,2],[7900,3]].forEach(([delay, stage]) => { + narrativeTimers.push(window.setTimeout(() => { + if (performance.now() < manualStageUntil) return; + setActiveStage(stage); + }, delay)); + }); + }; + + const scheduleNarrative = () => { + clearNarrative(); + runNarrative(); + if (!motionReduced) { + replayTimer = window.setInterval(() => { + if (document.hidden || performance.now() < manualStageUntil) return; + runNarrative(); + }, 25000); + } + }; + + stageButtons.forEach((button, i) => { + button.addEventListener('mouseenter', () => setActiveStage(i, true)); + button.addEventListener('focus', () => setActiveStage(i, true)); + button.addEventListener('click', () => setActiveStage(i, true)); + }); + + setActiveStage(activeStage); + scheduleNarrative(); + reducedMotion.addEventListener?.('change', (event) => { + motionReduced = event.matches; + scheduleNarrative(); + }); + + const gl = canvas.getContext('webgl2', { + alpha: true, + antialias: false, + depth: false, + stencil: false, + premultipliedAlpha: false, + preserveDrawingBuffer: false, + powerPreference: 'high-performance' + }); + + if (!gl) { + root.classList.add('hero-core2--fallback'); + return; + } + + const vertexSource = `#version 300 es + precision highp float; + const vec2 POS[3] = vec2[3]( + vec2(-1.0,-1.0), vec2(3.0,-1.0), vec2(-1.0,3.0) + ); + void main(){ gl_Position = vec4(POS[gl_VertexID],0.0,1.0); } + `; + + const fragmentSource = `#version 300 es + precision highp float; + + uniform vec2 uResolution; + uniform vec2 uPointer; + uniform float uTime; + uniform float uStage; + uniform float uMotion; + uniform float uQuality; + out vec4 outColor; + + mat2 rot(float a){ float c=cos(a),s=sin(a); return mat2(c,-s,s,c); } + + float hash21(vec2 p){ + p=fract(p*vec2(123.34,456.21)); + p+=dot(p,p+45.32); + return fract(p.x*p.y); + } + + float sdRoundBox(vec3 p, vec3 b, float r){ + vec3 q=abs(p)-b+r; + return min(max(q.x,max(q.y,q.z)),0.0)+length(max(q,0.0))-r; + } + + float sdEllipsoid(vec3 p, vec3 r){ + float k0=length(p/r); + float k1=length(p/(r*r)); + return k0*(k0-1.0)/max(k1,0.0001); + } + + float sdCapsule(vec3 p, vec3 a, vec3 b, float r){ + vec3 pa=p-a, ba=b-a; + float h=clamp(dot(pa,ba)/dot(ba,ba),0.0,1.0); + return length(pa-ba*h)-r; + } + + float sdPlane(vec3 p, vec3 n, float h){ return dot(p,n)+h; } + + float stageYaw(){ + if(uStage<0.5)return -0.12; + if(uStage<1.5)return -0.035; + if(uStage<2.5)return 0.075; + return 0.14; + } + float stagePitch(){ + if(uStage<0.5)return 0.07; + if(uStage<1.5)return 0.12; + if(uStage<2.5)return 0.045; + return -0.02; + } + + vec3 objectSpace(vec3 p){ + p-=vec3(0.02,-0.015,0.0); + float dy=uMotion*(0.052*sin(uTime*0.21)+0.020*sin(uTime*0.067+1.4)); + float dx=uMotion*(0.025*sin(uTime*0.16+0.9)); + float yaw=-0.29+stageYaw()+dy+uPointer.x*0.052*uMotion; + float pitch=0.09+stagePitch()+dx-uPointer.y*0.032*uMotion; + p.xz=rot(-yaw)*p.xz; + p.yz=rot(-pitch)*p.yz; + return p; + } + + float innerDistanceFromObject(vec3 q){ + vec3 p=q-vec3(0.10,-0.01,0.035); + p.xy=rot(0.18+uMotion*0.028*sin(uTime*0.34))*p.xy; + p.xz=rot(-0.17-uMotion*uTime*0.012)*p.xz; + float lens=sdEllipsoid(p,vec3(0.40,0.49,0.30)); + vec3 p2=p-vec3(0.07,-0.02,0.03); + float kernel=sdEllipsoid(p2,vec3(0.23,0.34,0.20)); + return min(lens,kernel+0.025); + } + + vec2 mapScene(vec3 p){ + vec3 q=objectSpace(p); + vec2 res=vec2(1000.0,0.0); + + // 01 — rear graphite spine: notched, leaned and intentionally incomplete. + vec3 s=q-vec3(-0.50,0.01,-0.08); + s.xy=rot(-0.21)*s.xy; + s.yz=rot(0.08)*s.yz; + float spine=sdRoundBox(s,vec3(0.20,0.82,0.32),0.115); + vec3 spineCut=s-vec3(0.12,0.05,0.27); + float spineNotch=sdRoundBox(spineCut,vec3(0.12,0.40,0.13),0.055); + spine=max(spine,-spineNotch); + if(spinemaxt)break; + } + return clamp(res,0.0,1.0); + } + + float ambientOcclusion(vec3 p,vec3 n){ + float occ=0.0,sca=1.0; + for(int i=0;i<4;i++){ + float h=0.04+0.085*float(i); + float d=mapScene(p+n*h).x; + occ+=(h-d)*sca; + sca*=0.66; + } + return clamp(1.0-1.30*occ,0.0,1.0); + } + + vec3 materialColor(float id,vec3 p,vec3 n,vec3 rd,float glow){ + vec3 graphite=vec3(0.050,0.064,0.071); + vec3 steel=vec3(0.185,0.210,0.220); + vec3 darkSteel=vec3(0.105,0.125,0.135); + vec3 cyan=vec3(0.31,0.84,0.98); + vec3 ice=vec3(0.70,0.90,0.95); + vec3 warm=vec3(0.82,0.67,0.45); + vec3 keyPos=vec3(-2.8,3.4,4.2); + vec3 rimPos=vec3(3.5,1.5,2.4); + vec3 l=normalize(keyPos-p), l2=normalize(rimPos-p), v=normalize(-rd); + vec3 h=normalize(l+v); + float ndl=max(dot(n,l),0.0); + float ndl2=max(dot(n,l2),0.0); + float shadow=softShadow(p+n*0.009,l,0.026,6.0); + float ao=ambientOcclusion(p,n); + float fres=pow(1.0-max(dot(n,v),0.0),4.2); + float brush=0.5+0.5*sin((p.y+p.x*0.22)*76.0); + + if(id<1.5){ + float spec=pow(max(dot(n,h),0.0),58.0+28.0*brush); + vec3 base=graphite*(0.42+0.92*ndl*shadow)*ao; + base+=vec3(0.34,0.39,0.41)*spec*(0.30+0.18*brush); + base+=cyan*fres*0.075; + base+=warm*ndl2*fres*0.035; + return base; + } + if(id<2.5){ + float spec=pow(max(dot(n,h),0.0),96.0); + vec3 base=steel*(0.44+0.98*ndl*shadow)*ao; + base+=ice*spec*0.52; + base+=cyan*fres*0.095; + base+=warm*ndl2*fres*0.055; + return base; + } + if(id<3.5){ + float facing=abs(dot(n,v)); + vec3 smoke=vec3(0.020,0.042,0.048); + vec3 base=smoke*(0.45+ndl*0.24); + base+=cyan*(0.045+fres*0.20+glow*0.13); + base+=ice*pow(1.0-facing,3.0)*0.075; + return base; + } + if(id<4.5){ + float phase=0.82+0.10*uMotion*sin(uTime*1.15+p.y*5.5)+uStage*0.030; + float filament=0.5+0.5*sin((p.x*7.0+p.y*9.0-p.z*6.0)+uTime*0.55*uMotion); + vec3 inner=mix(vec3(0.018,0.12,0.16),cyan,0.48+0.18*fres+0.07*filament); + inner*=phase*(0.70+ndl*0.16); + inner+=cyan*(0.18+fres*0.24+filament*0.06); + return inner; + } + if(id<5.5){ + float spec=pow(max(dot(n,h),0.0),72.0); + vec3 base=darkSteel*(0.48+0.78*ndl*shadow)*ao; + base+=ice*spec*0.35+cyan*fres*0.08; + return base; + } + return vec3(0.008,0.011,0.012); + } + + vec2 curveDistance(vec2 p,vec2 a,vec2 b,vec2 c,vec2 d){ + float md=10.0,mt=0.0; + vec2 prev=a; + for(int i=1;i<=32;i++){ + float t=float(i)/32.0,s=1.0-t; + vec2 cur=s*s*s*a+3.0*s*s*t*b+3.0*s*t*t*c+t*t*t*d; + vec2 pa=p-prev,ba=cur-prev; + float h=clamp(dot(pa,ba)/max(dot(ba,ba),0.00001),0.0,1.0); + float dd=length(pa-ba*h); + if(ddmaxSteps)break; + vec3 pos=ro+rd*t; + vec2 h=mapScene(pos); + vec3 q=objectSpace(pos); + float innerD=innerDistanceFromObject(q); + glow+=exp(-10.5*abs(innerD))*0.010*exp(-0.075*t); + if(h.x<0.0017){hit=true;id=h.y;break;} + t+=max(h.x*0.78,0.0095); + if(t>9.5)break; + } + + vec3 color=vec3(0.0); + float alpha=0.0; + if(hit){ + vec3 pos=ro+rd*t; + if(id<5.5){ + vec3 n=calcNormal(pos); + color=materialColor(id,pos,n,rd,glow); + float fog=1.0-exp(-0.03*t*t); + color*=1.0-fog*0.20; + alpha=1.0; + }else{ + float shadow=exp(-1.55*(pos.x*pos.x+pos.z*pos.z)); + float light=exp(-3.3*(pos.x*pos.x+pos.z*pos.z)); + color=vec3(0.003,0.006,0.007)+vec3(0.22,0.70,0.82)*light*0.010; + alpha=shadow*0.20; + } + } + + float halo=exp(-2.15*dot(p-vec2(0.05,-0.02),p-vec2(0.05,-0.02))); + vec3 haloColor=vec3(0.05,0.16,0.19)*halo*(0.08+min(glow,0.34)*0.20); + color+=haloColor; + alpha=max(alpha,halo*0.055); + + color+=vec3(0.20,0.75,0.92)*min(glow,0.48)*(0.30+0.07*uStage); + alpha=max(alpha,min(glow,0.48)*0.26); + + vec4 signals=signalField(p*vec2(0.92,0.92),hit&&id<5.5,t); + color+=signals.rgb; + alpha=max(alpha,signals.a); + + float grain=hash21(frag+floor(uTime*1.5*uMotion)); + color+=(grain-0.5)*0.0022*alpha; + color=aces(color*1.28); + color=pow(color,vec3(0.95)); + outColor=vec4(color,clamp(alpha,0.0,1.0)); + } + `; + + const compile = (type, source) => { + const shader = gl.createShader(type); + gl.shaderSource(shader, source); + gl.compileShader(shader); + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + const message = gl.getShaderInfoLog(shader) || 'Unknown shader compile failure'; + gl.deleteShader(shader); + throw new Error(message); + } + return shader; + }; + + let program; + try { + const vertex = compile(gl.VERTEX_SHADER, vertexSource); + const fragment = compile(gl.FRAGMENT_SHADER, fragmentSource); + program = gl.createProgram(); + gl.attachShader(program, vertex); + gl.attachShader(program, fragment); + gl.linkProgram(program); + gl.deleteShader(vertex); + gl.deleteShader(fragment); + if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { + throw new Error(gl.getProgramInfoLog(program) || 'Hero Core 2.0 R2 program link failed'); + } + } catch (error) { + console.error('[Hero Core 2.0 R2]', error); + root.classList.add('hero-core2--fallback'); + return; + } + + gl.useProgram(program); + const uniforms = { + resolution: gl.getUniformLocation(program, 'uResolution'), + pointer: gl.getUniformLocation(program, 'uPointer'), + time: gl.getUniformLocation(program, 'uTime'), + stage: gl.getUniformLocation(program, 'uStage'), + motion: gl.getUniformLocation(program, 'uMotion'), + quality: gl.getUniformLocation(program, 'uQuality') + }; + + let pointer={x:0,y:0}, pointerTarget={x:0,y:0}; + let visible=true, renderScale=1, quality=1, firstFrame=true; + let frameSamples=[], lastFrame=performance.now(); + const mobileViewport=()=>window.innerWidth<=700; + + const resize=()=>{ + const rect=visual.getBoundingClientRect(); + const cssWidth=Math.max(1,Math.round(rect.width)); + const cssHeight=Math.max(1,Math.round(rect.height)); + const dprCap=mobileViewport()?1.10:1.48; + const dpr=Math.min(window.devicePixelRatio||1,dprCap)*renderScale; + const width=Math.max(2,Math.round(cssWidth*dpr)); + const height=Math.max(2,Math.round(cssHeight*dpr)); + if(canvas.width!==width||canvas.height!==height){ + canvas.width=width; canvas.height=height; gl.viewport(0,0,width,height); + } + }; + + const resizeObserver=new ResizeObserver(resize); + resizeObserver.observe(visual); + window.addEventListener('resize',resize,{passive:true}); + resize(); + + const updatePointer=(event)=>{ + if(motionReduced||coarsePointer.matches)return; + const rect=visual.getBoundingClientRect(); + const x=(event.clientX-rect.left)/Math.max(rect.width,1); + const y=(event.clientY-rect.top)/Math.max(rect.height,1); + pointerTarget.x=(Math.max(0,Math.min(1,x))-0.5)*2; + pointerTarget.y=(0.5-Math.max(0,Math.min(1,y)))*2; + }; + visual.addEventListener('pointermove',updatePointer,{passive:true}); + visual.addEventListener('pointerleave',()=>{pointerTarget.x=0;pointerTarget.y=0;}); + + const visibilityObserver=new IntersectionObserver((entries)=>{ + visible=entries.some((entry)=>entry.isIntersecting); + },{threshold:0.02}); + visibilityObserver.observe(visual); + + const adaptPerformance=(delta)=>{ + if(firstFrame||motionReduced)return; + frameSamples.push(delta); + if(frameSamples.length<70)return; + const avg=frameSamples.reduce((s,v)=>s+v,0)/frameSamples.length; + frameSamples=[]; + if(avg>26&&renderScale>0.72){ + renderScale=Math.max(0.72,renderScale*0.86); + quality=Math.max(0.60,quality-0.16); + resize(); + } + }; + + const start=performance.now(); + const render=(now)=>{ + requestAnimationFrame(render); + if(!visible||document.hidden)return; + const delta=now-lastFrame; lastFrame=now; adaptPerformance(delta); + pointer.x+=(pointerTarget.x-pointer.x)*0.034; + pointer.y+=(pointerTarget.y-pointer.y)*0.034; + const elapsed=motionReduced?7.1:(now-start)*0.001; + + gl.clearColor(0,0,0,0); + gl.clear(gl.COLOR_BUFFER_BIT); + gl.useProgram(program); + gl.uniform2f(uniforms.resolution,canvas.width,canvas.height); + gl.uniform2f(uniforms.pointer,pointer.x,pointer.y); + gl.uniform1f(uniforms.time,elapsed); + gl.uniform1f(uniforms.stage,activeStage); + gl.uniform1f(uniforms.motion,motionReduced?0:1); + gl.uniform1f(uniforms.quality,mobileViewport()?Math.min(quality,0.76):quality); + gl.drawArrays(gl.TRIANGLES,0,3); + + if(firstFrame){ firstFrame=false; root.classList.add('hero-core2--ready'); } + }; + requestAnimationFrame(render); +})(); From 650eedf4be46a9bc2b657fedfd832ea2ad0240c3 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:13:04 -0700 Subject: [PATCH 12/69] Refine Premium Core 2.0 R2 composition and typography --- assets/css/hero-premium-core-2-r2.css | 68 +++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 assets/css/hero-premium-core-2-r2.css diff --git a/assets/css/hero-premium-core-2-r2.css b/assets/css/hero-premium-core-2-r2.css new file mode 100644 index 00000000..77faf5c1 --- /dev/null +++ b/assets/css/hero-premium-core-2-r2.css @@ -0,0 +1,68 @@ +.hero-core2__title { + max-width: 13.2ch; + font-size: clamp(56px, 4.65vw, 76px); + line-height: .965; + font-weight: 745; + letter-spacing: -.058em; +} + +.hero-core2__shell { + grid-template-columns: minmax(0, .9fr) minmax(620px, 1.1fr); + gap: clamp(22px, 3vw, 54px); +} + +.hero-core2__visual { + height: min(78vh, 775px); + min-height: 620px; + margin-right: clamp(-54px, -3vw, -12px); +} + +.hero-core2__canvas { + filter: saturate(.93) contrast(1.055); +} + +.hero-core2__visual::before { + inset: 5% 0 1% 1%; + background: + radial-gradient(circle at 50% 48%, rgba(91, 219, 246, .065), transparent 25%), + radial-gradient(circle at 61% 52%, rgba(255, 226, 184, .018), transparent 18%); + filter: blur(34px); +} + +.hero-core2__stage-button::after { width: 62px; opacity: .82; } +.hero-core2__stage:nth-child(1) { left: 3%; top: 15%; } +.hero-core2__stage:nth-child(2) { left: 8%; bottom: 16%; } +.hero-core2__stage:nth-child(3) { right: 2%; top: 25%; } +.hero-core2__stage:nth-child(4) { right: 4%; bottom: 14%; } + +@media (max-width: 1220px) { + .hero-core2__shell { grid-template-columns: minmax(0, .94fr) minmax(510px, 1.06fr); } + .hero-core2__title { max-width: 13ch; font-size: clamp(50px, 4.8vw, 67px); } + .hero-core2__visual { min-height: 570px; } +} + +@media (max-width: 980px) { + .hero-core2__shell { grid-template-columns: 1fr; } + .hero-core2__title { max-width: 14ch; font-size: clamp(47px, 7.7vw, 67px); } + .hero-core2__visual { width: min(100%, 880px); min-height: 510px; } +} + +@media (max-width: 700px) { + .hero-core2__shell { gap: 2px; padding-top: calc(var(--core2-header) + 20px); } + .hero-core2__eyebrow { margin-bottom: 11px; } + .hero-core2__title { max-width: 14.4ch; font-size: clamp(39px, 10.9vw, 52px); line-height: .98; } + .hero-core2__lead { margin-top: 16px; font-size: 14px; line-height: 1.47; } + .hero-core2__actions { margin-top: 18px; } + .hero-core2__accountability { margin-top: 13px; } + .hero-core2__visual { + height: 390px; + min-height: 390px; + margin-top: -8px; + } +} + +@media (max-width: 390px) { + .hero-core2__title { font-size: clamp(38px, 10.6vw, 45px); } + .hero-core2__lead { font-size: 13.7px; } + .hero-core2__visual { height: 355px; min-height: 355px; margin-top: -12px; } +} From 6120b9bb4deb65d497356bf2195f49e1e3bc83a2 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:13:28 -0700 Subject: [PATCH 13/69] Switch EN Premium Core preview to R2 --- hero-premium-core-2-preview/index.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hero-premium-core-2-preview/index.html b/hero-premium-core-2-preview/index.html index 53b94e95..0a22d04a 100644 --- a/hero-premium-core-2-preview/index.html +++ b/hero-premium-core-2-preview/index.html @@ -13,6 +13,7 @@ + Skip to main content @@ -76,6 +77,6 @@

From first impression to res

- + From f936177f728ea98f2b9f043ad9509fff42d31b3e Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:13:55 -0700 Subject: [PATCH 14/69] Switch RU Premium Core preview to R2 --- ru/hero-premium-core-2-preview/index.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ru/hero-premium-core-2-preview/index.html b/ru/hero-premium-core-2-preview/index.html index a5946cb0..ee3f35ae 100644 --- a/ru/hero-premium-core-2-preview/index.html +++ b/ru/hero-premium-core-2-preview/index.html @@ -13,6 +13,7 @@ + Перейти к содержимому @@ -76,6 +77,6 @@

От первого впеч - + From 6b65e44c2005fbebee37ce9e0a8d7b34584f8a4d Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:14:37 -0700 Subject: [PATCH 15/69] Point Premium Core owner-review QA at R2 --- .../hero-premium-core-2-owner-review.yml | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/.github/workflows/hero-premium-core-2-owner-review.yml b/.github/workflows/hero-premium-core-2-owner-review.yml index 5736f7c1..9f0317d1 100644 --- a/.github/workflows/hero-premium-core-2-owner-review.yml +++ b/.github/workflows/hero-premium-core-2-owner-review.yml @@ -6,7 +6,9 @@ on: - agent/hero-premium-core-2-r1 paths: - assets/css/hero-premium-core-2.css + - assets/css/hero-premium-core-2-r2.css - assets/js/hero-premium-core-2.js + - assets/js/hero-premium-core-2-r2.js - hero-premium-core-2-preview/** - ru/hero-premium-core-2-preview/** - tools/hero_premium_core_2_owner_review.mjs @@ -17,7 +19,9 @@ on: - agent/hero-layered-25d-static-r1 paths: - assets/css/hero-premium-core-2.css + - assets/css/hero-premium-core-2-r2.css - assets/js/hero-premium-core-2.js + - assets/js/hero-premium-core-2-r2.js - hero-premium-core-2-preview/** - ru/hero-premium-core-2-preview/** - tools/hero_premium_core_2_owner_review.mjs @@ -126,11 +130,14 @@ jobs: shell: bash run: | set -euo pipefail - grep -q 'sdRoundBox' assets/js/hero-premium-core-2.js - grep -q 'curveDistance' assets/js/hero-premium-core-2.js - grep -q 'innerDistanceFromObject' assets/js/hero-premium-core-2.js - grep -q 'requestAnimationFrame' assets/js/hero-premium-core-2.js - if grep -Eq 'THREE\.BoxGeometry|new THREE\.BoxGeometry|stroke-dasharray: *4, *12' assets/js/hero-premium-core-2.js assets/css/hero-premium-core-2.css; then + grep -q 'sdRoundBox' assets/js/hero-premium-core-2-r2.js + grep -q 'sdCapsule' assets/js/hero-premium-core-2-r2.js + grep -q 'curveDistance' assets/js/hero-premium-core-2-r2.js + grep -q 'innerDistanceFromObject' assets/js/hero-premium-core-2-r2.js + grep -q 'requestAnimationFrame' assets/js/hero-premium-core-2-r2.js + grep -q "hero-premium-core-2-r2.js" hero-premium-core-2-preview/index.html + grep -q "hero-premium-core-2-r2.js" ru/hero-premium-core-2-preview/index.html + if grep -Eq 'THREE\.BoxGeometry|new THREE\.BoxGeometry|stroke-dasharray: *4, *12' assets/js/hero-premium-core-2-r2.js assets/css/hero-premium-core-2-r2.css; then echo 'Rejected primitive/orbit language detected.' >&2 exit 1 fi From c3c506f11fca49a4e9f4de8740db1d38a5c6cd7f Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:18:06 -0700 Subject: [PATCH 16/69] Build sculptural Premium Core 2.0 V2 scene --- assets/js/hero-premium-core-2-v2.js | 589 ++++++++++++++++++++++++++++ 1 file changed, 589 insertions(+) create mode 100644 assets/js/hero-premium-core-2-v2.js diff --git a/assets/js/hero-premium-core-2-v2.js b/assets/js/hero-premium-core-2-v2.js new file mode 100644 index 00000000..715f8874 --- /dev/null +++ b/assets/js/hero-premium-core-2-v2.js @@ -0,0 +1,589 @@ +(() => { + 'use strict'; + + const root = document.documentElement; + const canvas = document.querySelector('[data-hero-core2-canvas]'); + const visual = document.querySelector('[data-hero-core2-visual]'); + const stageItems = [...document.querySelectorAll('[data-hero-core2-stage]')]; + const stageButtons = [...document.querySelectorAll('[data-hero-core2-stage-button]')]; + if (!canvas || !visual) return; + + const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)'); + const coarsePointer = window.matchMedia('(pointer: coarse)'); + let motionReduced = reducedMotion.matches; + let activeStage = motionReduced ? 3 : 0; + let narrativeTimers = []; + let replayTimer = null; + let manualStageUntil = 0; + + const setActiveStage = (index, manual = false) => { + activeStage = Math.max(0, Math.min(3, index)); + stageItems.forEach((item, i) => item.classList.toggle('is-active', i === activeStage)); + stageButtons.forEach((button, i) => button.setAttribute('aria-current', i === activeStage ? 'step' : 'false')); + if (manual) manualStageUntil = performance.now() + 9000; + }; + + const clearNarrative = () => { + narrativeTimers.forEach(window.clearTimeout); + narrativeTimers = []; + if (replayTimer) window.clearInterval(replayTimer); + replayTimer = null; + }; + + const runNarrative = () => { + if (motionReduced) { + setActiveStage(3); + return; + } + narrativeTimers.forEach(window.clearTimeout); + narrativeTimers = []; + [[800,0],[3000,1],[5350,2],[7900,3]].forEach(([delay, stage]) => { + narrativeTimers.push(window.setTimeout(() => { + if (performance.now() < manualStageUntil) return; + setActiveStage(stage); + }, delay)); + }); + }; + + const scheduleNarrative = () => { + clearNarrative(); + runNarrative(); + if (!motionReduced) { + replayTimer = window.setInterval(() => { + if (document.hidden || performance.now() < manualStageUntil) return; + runNarrative(); + }, 24500); + } + }; + + stageButtons.forEach((button, i) => { + button.addEventListener('mouseenter', () => setActiveStage(i, true)); + button.addEventListener('focus', () => setActiveStage(i, true)); + button.addEventListener('click', () => setActiveStage(i, true)); + }); + + setActiveStage(activeStage); + scheduleNarrative(); + reducedMotion.addEventListener?.('change', (event) => { + motionReduced = event.matches; + scheduleNarrative(); + }); + + const gl = canvas.getContext('webgl2', { + alpha: true, + antialias: false, + depth: false, + stencil: false, + premultipliedAlpha: false, + preserveDrawingBuffer: false, + powerPreference: 'high-performance' + }); + + if (!gl) { + root.classList.add('hero-core2--fallback'); + return; + } + + const vertexSource = `#version 300 es + precision highp float; + const vec2 POS[3] = vec2[3](vec2(-1.0,-1.0), vec2(3.0,-1.0), vec2(-1.0,3.0)); + void main(){ gl_Position = vec4(POS[gl_VertexID],0.0,1.0); } + `; + + const fragmentSource = `#version 300 es + precision highp float; + + uniform vec2 uResolution; + uniform vec2 uPointer; + uniform float uTime; + uniform float uStage; + uniform float uMotion; + uniform float uQuality; + out vec4 outColor; + + mat2 rot(float a){ float c=cos(a), s=sin(a); return mat2(c,-s,s,c); } + + float hash21(vec2 p){ + p=fract(p*vec2(123.34,456.21)); + p+=dot(p,p+45.32); + return fract(p.x*p.y); + } + + float sdRoundBox(vec3 p, vec3 b, float r){ + vec3 q=abs(p)-b+r; + return min(max(q.x,max(q.y,q.z)),0.0)+length(max(q,0.0))-r; + } + + float sdEllipsoid(vec3 p, vec3 r){ + float k0=length(p/r); + float k1=length(p/(r*r)); + return k0*(k0-1.0)/max(k1,0.0001); + } + + float sdPlane(vec3 p, vec3 n, float h){ return dot(p,n)+h; } + + float stageYaw(){ + if(uStage<0.5) return -0.13; + if(uStage<1.5) return -0.045; + if(uStage<2.5) return 0.065; + return 0.14; + } + + float stagePitch(){ + if(uStage<0.5) return 0.055; + if(uStage<1.5) return 0.10; + if(uStage<2.5) return 0.035; + return -0.035; + } + + vec3 objectSpace(vec3 p){ + p.y-=0.025; + float driftY=uMotion*(0.050*sin(uTime*0.205)+0.020*sin(uTime*0.071+1.8)); + float driftX=uMotion*(0.024*sin(uTime*0.157+0.6)); + float yaw=-0.22+stageYaw()+driftY+uPointer.x*0.050*uMotion; + float pitch=0.07+stagePitch()+driftX-uPointer.y*0.032*uMotion; + p.xz=rot(-yaw)*p.xz; + p.yz=rot(-pitch)*p.yz; + return p; + } + + float innerDistanceFromObject(vec3 q){ + vec3 p=q-vec3(0.075,-0.005,0.02); + p.xy=rot(0.20+uMotion*0.030*sin(uTime*0.31))*p.xy; + p.xz=rot(-0.20-uMotion*uTime*0.010)*p.xz; + float a=sdEllipsoid(p,vec3(0.40,0.54,0.30)); + vec3 b=p-vec3(0.08,0.03,-0.02); + b.yz=rot(0.42+uMotion*uTime*0.015)*b.yz; + float c=sdRoundBox(b,vec3(0.22,0.36,0.20),0.17); + return min(a,c+0.035); + } + + vec2 mapScene(vec3 p){ + vec3 q=objectSpace(p); + vec2 res=vec2(1000.0,0.0); + float breathe=uMotion*sin(uTime*0.38)*0.012; + + // Rear diagonal spine: establishes monolithic ancestry without closing the silhouette. + vec3 r=q-vec3(-0.08,0.01,-0.36); + r.xy=rot(-0.31)*r.xy; + r.xz=rot(0.10)*r.xz; + float dr=sdRoundBox(r,vec3(0.25,0.88,0.105),0.075); + vec3 rcut=q-vec3(-0.01,0.07,-0.29); + rcut.xy=rot(-0.27)*rcut.xy; + dr=max(dr,-sdEllipsoid(rcut,vec3(0.29,0.43,0.27))); + if(drmaxt) break; + } + return clamp(res,0.0,1.0); + } + + float ambientOcclusion(vec3 p, vec3 n){ + float occ=0.0, sca=1.0; + for(int i=0;i<3;i++){ + float h=0.045+0.10*float(i); + float d=mapScene(p+n*h).x; + occ+=(h-d)*sca; + sca*=0.64; + } + return clamp(1.0-1.25*occ,0.0,1.0); + } + + vec3 materialColor(float id, vec3 p, vec3 n, vec3 rd, float glow){ + vec3 graphite=vec3(0.068,0.082,0.090); + vec3 steel=vec3(0.17,0.195,0.202); + vec3 cyan=vec3(0.31,0.84,0.99); + vec3 silver=vec3(0.74,0.80,0.82); + vec3 warm=vec3(0.84,0.70,0.50); + vec3 keyPos=vec3(-2.7,3.3,4.2); + vec3 rimPos=vec3(3.3,1.8,2.6); + vec3 l=normalize(keyPos-p); + vec3 l2=normalize(rimPos-p); + vec3 v=normalize(-rd); + float ndl=max(dot(n,l),0.0); + float ndl2=max(dot(n,l2),0.0); + float sh=softShadow(p+n*0.009,l,0.03,5.6); + float ao=ambientOcclusion(p,n); + float fres=pow(1.0-max(dot(n,v),0.0),4.0); + vec3 h=normalize(l+v); + + if(id<1.5){ + float rough=0.42+0.07*sin(p.x*7.0+p.y*4.0+p.z*5.0); + float spec=pow(max(dot(n,h),0.0),mix(48.0,92.0,1.0-rough)); + vec3 base=graphite*(0.36+0.86*ndl*sh)*ao; + base+=silver*spec*0.40; + base+=cyan*fres*0.085; + base+=warm*ndl2*fres*0.035; + return base; + } + if(id<2.5){ + float spec=pow(max(dot(n,h),0.0),96.0); + vec3 base=steel*(0.40+0.94*ndl*sh)*ao; + base+=silver*spec*0.70; + base+=cyan*fres*0.10; + base+=warm*ndl2*fres*0.055; + return base; + } + if(id<3.5){ + float facing=abs(dot(n,v)); + vec3 smoke=vec3(0.018,0.042,0.050); + vec3 base=smoke*(0.36+ndl*0.24); + base+=cyan*(0.055+fres*0.31+glow*0.16); + base+=silver*pow(1.0-facing,3.0)*0.075; + return base; + } + if(id<4.5){ + float pulse=0.78+0.10*uMotion*sin(uTime*1.18+p.y*5.4)+0.036*uStage; + vec3 inner=mix(vec3(0.022,0.13,0.17),cyan,0.48+0.18*fres); + inner*=pulse*(0.72+ndl*0.14); + inner+=cyan*(0.18+fres*0.26); + return inner; + } + float radial=exp(-0.72*dot(p.xz,p.xz)); + return vec3(0.008,0.010,0.011)+cyan*radial*0.004; + } + + vec2 curveDistance(vec2 p, vec2 a, vec2 b, vec2 c, vec2 d){ + float md=10.0, mt=0.0; + vec2 prev=a; + for(int i=1;i<=24;i++){ + float t=float(i)/24.0, s=1.0-t; + vec2 cur=s*s*s*a+3.0*s*s*t*b+3.0*s*t*t*c+t*t*t*d; + vec2 pa=p-prev, ba=cur-prev; + float h=clamp(dot(pa,ba)/max(dot(ba,ba),0.00001),0.0,1.0); + float dd=length(pa-ba*h); + if(dd0.91){ + vec2 center=(cell+vec2(hash21(cell+1.7),hash21(cell+4.2)))/32.0-2.0; + dust=(1.0-smoothstep(0.002,0.013,length(uv-center)))*0.18; + } + col+=ice*dust*(0.25+0.18*uStage/3.0); + mask=max(mask,dust*0.18); + return vec4(col,mask); + } + + vec3 aces(vec3 x){ + float a=2.51,b=0.03,c=2.43,d=0.59,e=0.14; + return clamp((x*(a*x+b))/(x*(c*x+d)+e),0.0,1.0); + } + + void main(){ + vec2 frag=gl_FragCoord.xy; + vec2 p=(2.0*frag-uResolution.xy)/uResolution.y; + p.x+=0.01; + + vec3 ro=vec3(0.02+uPointer.x*0.050*uMotion,0.07+uPointer.y*0.032*uMotion,4.38); + vec3 ta=vec3(0.035,-0.015,0.0); + vec3 ww=normalize(ta-ro); + vec3 uu=normalize(cross(ww,vec3(0.0,1.0,0.0))); + vec3 vv=cross(uu,ww); + vec3 rd=normalize(uu*p.x+vv*p.y+ww*2.30); + + vec3 bg=vec3(0.004,0.0065,0.0075); + float halo=exp(-2.1*dot(p-vec2(0.04,-0.01),p-vec2(0.04,-0.01))); + bg+=vec3(0.014,0.038,0.045)*halo*0.42; + float warmEnv=exp(-6.3*dot(p-vec2(0.56,0.20),p-vec2(0.56,0.20))); + bg+=vec3(0.034,0.022,0.012)*warmEnv*0.13; + float grain=hash21(frag+floor(uTime*1.8*uMotion)); + bg+=(grain-0.5)*0.0022; + + float t=0.0,id=0.0,glow=0.0; + bool hit=false; + int maxSteps=int(mix(46.0,68.0,uQuality)); + for(int i=0;i<70;i++){ + if(i>maxSteps) break; + vec3 pos=ro+rd*t; + vec2 h=mapScene(pos); + vec3 q=objectSpace(pos); + float innerD=innerDistanceFromObject(q); + glow+=exp(-11.0*abs(innerD))*0.0092*exp(-0.08*t); + if(h.x<0.0017){ hit=true; id=h.y; break; } + t+=max(h.x*0.78,0.010); + if(t>10.0) break; + } + + vec3 color=bg; + float sceneAlpha=halo*0.055; + if(hit){ + vec3 pos=ro+rd*t; + vec3 n=calcNormal(pos); + color=materialColor(id,pos,n,rd,glow); + if(id>5.5){ + float contact=exp(-1.9*(pos.x*pos.x+pos.z*pos.z)); + color*=1.0-0.66*contact; + color+=vec3(0.31,0.84,0.99)*contact*0.004; + sceneAlpha=max(sceneAlpha,0.08+contact*0.22); + }else{ + sceneAlpha=0.98; + } + float fog=1.0-exp(-0.036*t*t); + color=mix(color,bg,fog*0.38); + } + + color+=vec3(0.20,0.76,0.94)*min(glow,0.50)*(0.30+0.075*uStage); + vec4 signal=signalField(p*vec2(0.93,0.93),hit&&id<5.5,t); + color+=signal.rgb; + sceneAlpha=max(sceneAlpha,clamp(signal.a+glow*0.25,0.0,0.56)); + + float vignette=1.0-smoothstep(0.38,1.66,length(p*vec2(0.76,0.92))); + color*=mix(0.68,1.0,vignette); + color=aces(color*1.26); + color=pow(color,vec3(0.95)); + sceneAlpha*=smoothstep(0.02,0.23,vignette+0.06); + outColor=vec4(color,clamp(sceneAlpha,0.0,0.99)); + } + `; + + const compile = (type, source) => { + const shader = gl.createShader(type); + gl.shaderSource(shader, source); + gl.compileShader(shader); + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + const message = gl.getShaderInfoLog(shader) || 'Unknown shader compile failure'; + gl.deleteShader(shader); + throw new Error(message); + } + return shader; + }; + + let program; + try { + const vertex = compile(gl.VERTEX_SHADER, vertexSource); + const fragment = compile(gl.FRAGMENT_SHADER, fragmentSource); + program = gl.createProgram(); + gl.attachShader(program, vertex); + gl.attachShader(program, fragment); + gl.linkProgram(program); + gl.deleteShader(vertex); + gl.deleteShader(fragment); + if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { + throw new Error(gl.getProgramInfoLog(program) || 'Hero Core 2.0 program link failed'); + } + } catch (error) { + console.error('[Hero Core 2.0 V2]', error); + root.classList.add('hero-core2--fallback'); + return; + } + + gl.useProgram(program); + const uniforms = { + resolution: gl.getUniformLocation(program,'uResolution'), + pointer: gl.getUniformLocation(program,'uPointer'), + time: gl.getUniformLocation(program,'uTime'), + stage: gl.getUniformLocation(program,'uStage'), + motion: gl.getUniformLocation(program,'uMotion'), + quality: gl.getUniformLocation(program,'uQuality') + }; + + let pointer={x:0,y:0}; + let pointerTarget={x:0,y:0}; + let visible=true; + let renderScale=1; + let quality=1; + let firstFrame=true; + let frameSamples=[]; + let lastFrame=performance.now(); + const mobileViewport=()=>window.innerWidth<=700; + + const resize=()=>{ + const rect=visual.getBoundingClientRect(); + const cssWidth=Math.max(1,Math.round(rect.width)); + const cssHeight=Math.max(1,Math.round(rect.height)); + const dprCap=mobileViewport()?1.12:1.50; + const dpr=Math.min(window.devicePixelRatio||1,dprCap)*renderScale; + const width=Math.max(2,Math.round(cssWidth*dpr)); + const height=Math.max(2,Math.round(cssHeight*dpr)); + if(canvas.width!==width||canvas.height!==height){ + canvas.width=width; + canvas.height=height; + gl.viewport(0,0,width,height); + } + }; + + const resizeObserver=new ResizeObserver(resize); + resizeObserver.observe(visual); + window.addEventListener('resize',resize,{passive:true}); + resize(); + + visual.addEventListener('pointermove',(event)=>{ + if(motionReduced||coarsePointer.matches) return; + const rect=visual.getBoundingClientRect(); + const x=(event.clientX-rect.left)/Math.max(rect.width,1); + const y=(event.clientY-rect.top)/Math.max(rect.height,1); + pointerTarget.x=(Math.max(0,Math.min(1,x))-0.5)*2; + pointerTarget.y=(0.5-Math.max(0,Math.min(1,y)))*2; + },{passive:true}); + visual.addEventListener('pointerleave',()=>{ pointerTarget.x=0; pointerTarget.y=0; }); + + const visibilityObserver=new IntersectionObserver((entries)=>{ + visible=entries.some((entry)=>entry.isIntersecting); + },{threshold:0.02}); + visibilityObserver.observe(visual); + + const adaptPerformance=(delta)=>{ + if(firstFrame||motionReduced) return; + frameSamples.push(delta); + if(frameSamples.length<72) return; + const avg=frameSamples.reduce((sum,value)=>sum+value,0)/frameSamples.length; + frameSamples=[]; + if(avg>25&&renderScale>0.72){ + renderScale=Math.max(0.72,renderScale*0.86); + quality=Math.max(0.60,quality-0.16); + resize(); + } + }; + + const start=performance.now(); + const render=(now)=>{ + requestAnimationFrame(render); + if(!visible||document.hidden) return; + const delta=now-lastFrame; + lastFrame=now; + adaptPerformance(delta); + pointer.x+=(pointerTarget.x-pointer.x)*0.035; + pointer.y+=(pointerTarget.y-pointer.y)*0.035; + const elapsed=motionReduced?7.8:(now-start)*0.001; + gl.useProgram(program); + gl.uniform2f(uniforms.resolution,canvas.width,canvas.height); + gl.uniform2f(uniforms.pointer,pointer.x,pointer.y); + gl.uniform1f(uniforms.time,elapsed); + gl.uniform1f(uniforms.stage,activeStage); + gl.uniform1f(uniforms.motion,motionReduced?0:1); + gl.uniform1f(uniforms.quality,mobileViewport()?Math.min(quality,0.76):quality); + gl.drawArrays(gl.TRIANGLES,0,3); + if(firstFrame){ + firstFrame=false; + root.classList.add('hero-core2--ready'); + } + }; + + requestAnimationFrame(render); +})(); From a4828f1e17820bcbcb1470ddfae6ba6656345b6b Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:18:27 -0700 Subject: [PATCH 17/69] Recompose Premium Core 2.0 V2 mobile and scene integration --- assets/css/hero-premium-core-2-v2.css | 138 ++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 assets/css/hero-premium-core-2-v2.css diff --git a/assets/css/hero-premium-core-2-v2.css b/assets/css/hero-premium-core-2-v2.css new file mode 100644 index 00000000..b6e3bac5 --- /dev/null +++ b/assets/css/hero-premium-core-2-v2.css @@ -0,0 +1,138 @@ +.hero-core2__visual{ + background:transparent; +} + +.hero-core2__canvas{ + mix-blend-mode:normal; +} + +.hero-core2__visual::after{ + content:""; + position:absolute; + left:16%; + right:10%; + bottom:7%; + height:15%; + z-index:1; + pointer-events:none; + background:radial-gradient(ellipse at center, rgba(0,0,0,.48), transparent 70%); + filter:blur(18px); + opacity:.58; +} + +.hero-core2__stage-list{z-index:8;} +.hero-core2__stage:nth-child(1){left:1%;top:17%;} +.hero-core2__stage:nth-child(2){left:8%;bottom:16%;} +.hero-core2__stage:nth-child(3){right:2%;top:26%;} +.hero-core2__stage:nth-child(4){right:4%;bottom:12%;} + +@media (max-width:700px){ + .hero-core2{ + overflow:hidden; + } + + .hero-core2__shell{ + position:relative; + display:block; + min-height:100svh; + padding-bottom:26px; + } + + .hero-core2__copy{ + position:relative; + z-index:9; + width:100%; + } + + .hero-core2__title{ + max-width:13.5ch; + } + + .hero-core2__visual{ + position:absolute; + top:284px; + left:8px; + right:8px; + width:auto; + height:266px; + min-height:266px; + margin:0; + z-index:4; + } + + .hero-core2__visual::before{ + inset:-3% -4% -4%; + opacity:.9; + } + + .hero-core2__visual::after{ + left:19%; + right:15%; + bottom:8%; + height:16%; + } + + .hero-core2__lead{ + margin-top:296px; + } + + .hero-core2__stage-list{ + inset:auto 0 0; + } + + .hero-core2__stage-button{ + padding:6px 2px 3px; + } + + .hero-core2__stage-button::after{ + max-width:52px; + } +} + +@media (max-width:390px){ + .hero-core2__visual{ + top:276px; + height:244px; + min-height:244px; + } + + .hero-core2__lead{ + margin-top:270px; + } +} + +@media (max-width:340px){ + .hero-core2__visual{ + top:295px; + left:2px; + right:2px; + height:226px; + min-height:226px; + } + + .hero-core2__lead{ + margin-top:246px; + } + + .hero-core2__stage-label{ + font-size:6.9px; + } +} + +@media (max-height:500px) and (min-width:701px){ + .hero-core2__shell{ + grid-template-columns:minmax(0,.9fr) minmax(430px,1.1fr); + padding-top:calc(var(--core2-header) + 12px); + padding-bottom:12px; + gap:14px; + } + + .hero-core2__eyebrow{margin-bottom:10px;} + .hero-core2__title{font-size:clamp(40px,4.3vw,56px);max-width:11.5ch;} + .hero-core2__lead{margin-top:12px;font-size:13px;line-height:1.45;max-width:560px;} + .hero-core2__actions{margin-top:13px;} + .hero-core2__button{min-height:42px;} + .hero-core2__microcopy{font-size:10px;} + .hero-core2__accountability{margin-top:10px;font-size:8.7px;} + .hero-core2__visual{height:72vh;min-height:330px;} +} From 382698a96ba86af93488a8e684bc201ecd103b94 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:19:41 -0700 Subject: [PATCH 18/69] Run Premium Core 2.0 R2 owner-review QA --- .github/hero-premium-core-2-run.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/hero-premium-core-2-run.txt b/.github/hero-premium-core-2-run.txt index 03850a9a..d66c96c8 100644 --- a/.github/hero-premium-core-2-run.txt +++ b/.github/hero-premium-core-2-run.txt @@ -1 +1 @@ -2026-08-11T02:09:00-07:00 owner-review QA trigger +2026-08-11T02:16:00-07:00 owner-review QA trigger R2 From dea4549cf9ec4e130cb7c1e7b5311ea2034a44ad Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:22:35 -0700 Subject: [PATCH 19/69] Refine Premium Core intelligence material and aperture --- assets/js/hero-premium-core-2-r2.js | 336 +++++++++++----------------- 1 file changed, 127 insertions(+), 209 deletions(-) diff --git a/assets/js/hero-premium-core-2-r2.js b/assets/js/hero-premium-core-2-r2.js index a3e81961..6be8dd47 100644 --- a/assets/js/hero-premium-core-2-r2.js +++ b/assets/js/hero-premium-core-2-r2.js @@ -86,10 +86,8 @@ const vertexSource = `#version 300 es precision highp float; - const vec2 POS[3] = vec2[3]( - vec2(-1.0,-1.0), vec2(3.0,-1.0), vec2(-1.0,3.0) - ); - void main(){ gl_Position = vec4(POS[gl_VertexID],0.0,1.0); } + const vec2 POS[3] = vec2[3](vec2(-1.0,-1.0),vec2(3.0,-1.0),vec2(-1.0,3.0)); + void main(){ gl_Position=vec4(POS[gl_VertexID],0.0,1.0); } `; const fragmentSource = `#version 300 es @@ -104,31 +102,22 @@ out vec4 outColor; mat2 rot(float a){ float c=cos(a),s=sin(a); return mat2(c,-s,s,c); } + float hash21(vec2 p){ p=fract(p*vec2(123.34,456.21)); p+=dot(p,p+45.32); return fract(p.x*p.y); } - float hash21(vec2 p){ - p=fract(p*vec2(123.34,456.21)); - p+=dot(p,p+45.32); - return fract(p.x*p.y); - } - - float sdRoundBox(vec3 p, vec3 b, float r){ + float sdRoundBox(vec3 p,vec3 b,float r){ vec3 q=abs(p)-b+r; return min(max(q.x,max(q.y,q.z)),0.0)+length(max(q,0.0))-r; } - - float sdEllipsoid(vec3 p, vec3 r){ - float k0=length(p/r); - float k1=length(p/(r*r)); + float sdEllipsoid(vec3 p,vec3 r){ + float k0=length(p/r),k1=length(p/(r*r)); return k0*(k0-1.0)/max(k1,0.0001); } - - float sdCapsule(vec3 p, vec3 a, vec3 b, float r){ - vec3 pa=p-a, ba=b-a; + float sdCapsule(vec3 p,vec3 a,vec3 b,float r){ + vec3 pa=p-a,ba=b-a; float h=clamp(dot(pa,ba)/dot(ba,ba),0.0,1.0); return length(pa-ba*h)-r; } - - float sdPlane(vec3 p, vec3 n, float h){ return dot(p,n)+h; } + float sdPlane(vec3 p,vec3 n,float h){ return dot(p,n)+h; } float stageYaw(){ if(uStage<0.5)return -0.12; @@ -158,80 +147,59 @@ vec3 p=q-vec3(0.10,-0.01,0.035); p.xy=rot(0.18+uMotion*0.028*sin(uTime*0.34))*p.xy; p.xz=rot(-0.17-uMotion*uTime*0.012)*p.xz; - float lens=sdEllipsoid(p,vec3(0.40,0.49,0.30)); - vec3 p2=p-vec3(0.07,-0.02,0.03); - float kernel=sdEllipsoid(p2,vec3(0.23,0.34,0.20)); - return min(lens,kernel+0.025); + float lens=sdEllipsoid(p,vec3(0.37,0.46,0.285)); + vec3 p2=p-vec3(0.065,-0.018,0.025); + float kernel=sdEllipsoid(p2,vec3(0.205,0.305,0.175)); + return min(lens,kernel+0.030); } vec2 mapScene(vec3 p){ vec3 q=objectSpace(p); vec2 res=vec2(1000.0,0.0); - // 01 — rear graphite spine: notched, leaned and intentionally incomplete. vec3 s=q-vec3(-0.50,0.01,-0.08); - s.xy=rot(-0.21)*s.xy; - s.yz=rot(0.08)*s.yz; + s.xy=rot(-0.21)*s.xy; s.yz=rot(0.08)*s.yz; float spine=sdRoundBox(s,vec3(0.20,0.82,0.32),0.115); vec3 spineCut=s-vec3(0.12,0.05,0.27); float spineNotch=sdRoundBox(spineCut,vec3(0.12,0.40,0.13),0.055); spine=max(spine,-spineNotch); if(spinemaxSteps)break; @@ -425,56 +368,50 @@ vec2 h=mapScene(pos); vec3 q=objectSpace(pos); float innerD=innerDistanceFromObject(q); - glow+=exp(-10.5*abs(innerD))*0.010*exp(-0.075*t); + glow+=exp(-11.5*abs(innerD))*0.0070*exp(-0.08*t); if(h.x<0.0017){hit=true;id=h.y;break;} t+=max(h.x*0.78,0.0095); - if(t>9.5)break; + if(t>9.2)break; } - vec3 color=vec3(0.0); - float alpha=0.0; + vec3 color=vec3(0.0); float alpha=0.0; if(hit){ vec3 pos=ro+rd*t; if(id<5.5){ vec3 n=calcNormal(pos); color=materialColor(id,pos,n,rd,glow); float fog=1.0-exp(-0.03*t*t); - color*=1.0-fog*0.20; + color*=1.0-fog*0.18; alpha=1.0; }else{ - float shadow=exp(-1.55*(pos.x*pos.x+pos.z*pos.z)); - float light=exp(-3.3*(pos.x*pos.x+pos.z*pos.z)); - color=vec3(0.003,0.006,0.007)+vec3(0.22,0.70,0.82)*light*0.010; - alpha=shadow*0.20; + float shadow=exp(-1.45*(pos.x*pos.x+pos.z*pos.z)); + float light=exp(-3.5*(pos.x*pos.x+pos.z*pos.z)); + color=vec3(0.002,0.005,0.006)+vec3(0.18,0.54,0.62)*light*0.007; + alpha=shadow*0.26; } } - float halo=exp(-2.15*dot(p-vec2(0.05,-0.02),p-vec2(0.05,-0.02))); - vec3 haloColor=vec3(0.05,0.16,0.19)*halo*(0.08+min(glow,0.34)*0.20); - color+=haloColor; - alpha=max(alpha,halo*0.055); - - color+=vec3(0.20,0.75,0.92)*min(glow,0.48)*(0.30+0.07*uStage); - alpha=max(alpha,min(glow,0.48)*0.26); + float halo=exp(-2.25*dot(p-vec2(0.05,-0.02),p-vec2(0.05,-0.02))); + color+=vec3(0.035,0.11,0.13)*halo*(0.055+min(glow,0.28)*0.12); + alpha=max(alpha,halo*0.042); + color+=vec3(0.18,0.62,0.76)*min(glow,0.40)*(0.13+0.04*uStage); + alpha=max(alpha,min(glow,0.40)*0.15); vec4 signals=signalField(p*vec2(0.92,0.92),hit&&id<5.5,t); - color+=signals.rgb; - alpha=max(alpha,signals.a); - + color+=signals.rgb; alpha=max(alpha,signals.a); float grain=hash21(frag+floor(uTime*1.5*uMotion)); - color+=(grain-0.5)*0.0022*alpha; - color=aces(color*1.28); - color=pow(color,vec3(0.95)); + color+=(grain-0.5)*0.0020*alpha; + color=aces(color*1.32); color=pow(color,vec3(0.95)); outColor=vec4(color,clamp(alpha,0.0,1.0)); } `; - const compile = (type, source) => { - const shader = gl.createShader(type); - gl.shaderSource(shader, source); + const compile=(type,source)=>{ + const shader=gl.createShader(type); + gl.shaderSource(shader,source); gl.compileShader(shader); - if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { - const message = gl.getShaderInfoLog(shader) || 'Unknown shader compile failure'; + if(!gl.getShaderParameter(shader,gl.COMPILE_STATUS)){ + const message=gl.getShaderInfoLog(shader)||'Unknown shader compile failure'; gl.deleteShader(shader); throw new Error(message); } @@ -482,50 +419,41 @@ }; let program; - try { - const vertex = compile(gl.VERTEX_SHADER, vertexSource); - const fragment = compile(gl.FRAGMENT_SHADER, fragmentSource); - program = gl.createProgram(); - gl.attachShader(program, vertex); - gl.attachShader(program, fragment); - gl.linkProgram(program); - gl.deleteShader(vertex); - gl.deleteShader(fragment); - if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { - throw new Error(gl.getProgramInfoLog(program) || 'Hero Core 2.0 R2 program link failed'); - } - } catch (error) { - console.error('[Hero Core 2.0 R2]', error); + try{ + const vertex=compile(gl.VERTEX_SHADER,vertexSource); + const fragment=compile(gl.FRAGMENT_SHADER,fragmentSource); + program=gl.createProgram(); + gl.attachShader(program,vertex); gl.attachShader(program,fragment); gl.linkProgram(program); + gl.deleteShader(vertex); gl.deleteShader(fragment); + if(!gl.getProgramParameter(program,gl.LINK_STATUS))throw new Error(gl.getProgramInfoLog(program)||'Hero Core 2.0 program link failed'); + }catch(error){ + console.error('[Hero Core 2.0 material refinement]',error); root.classList.add('hero-core2--fallback'); return; } gl.useProgram(program); - const uniforms = { - resolution: gl.getUniformLocation(program, 'uResolution'), - pointer: gl.getUniformLocation(program, 'uPointer'), - time: gl.getUniformLocation(program, 'uTime'), - stage: gl.getUniformLocation(program, 'uStage'), - motion: gl.getUniformLocation(program, 'uMotion'), - quality: gl.getUniformLocation(program, 'uQuality') + const uniforms={ + resolution:gl.getUniformLocation(program,'uResolution'), + pointer:gl.getUniformLocation(program,'uPointer'), + time:gl.getUniformLocation(program,'uTime'), + stage:gl.getUniformLocation(program,'uStage'), + motion:gl.getUniformLocation(program,'uMotion'), + quality:gl.getUniformLocation(program,'uQuality') }; - let pointer={x:0,y:0}, pointerTarget={x:0,y:0}; - let visible=true, renderScale=1, quality=1, firstFrame=true; - let frameSamples=[], lastFrame=performance.now(); + let pointer={x:0,y:0},pointerTarget={x:0,y:0}; + let visible=true,renderScale=1,quality=1,firstFrame=true; + let frameSamples=[],lastFrame=performance.now(); const mobileViewport=()=>window.innerWidth<=700; const resize=()=>{ const rect=visual.getBoundingClientRect(); - const cssWidth=Math.max(1,Math.round(rect.width)); - const cssHeight=Math.max(1,Math.round(rect.height)); + const cssWidth=Math.max(1,Math.round(rect.width)),cssHeight=Math.max(1,Math.round(rect.height)); const dprCap=mobileViewport()?1.10:1.48; const dpr=Math.min(window.devicePixelRatio||1,dprCap)*renderScale; - const width=Math.max(2,Math.round(cssWidth*dpr)); - const height=Math.max(2,Math.round(cssHeight*dpr)); - if(canvas.width!==width||canvas.height!==height){ - canvas.width=width; canvas.height=height; gl.viewport(0,0,width,height); - } + const width=Math.max(2,Math.round(cssWidth*dpr)),height=Math.max(2,Math.round(cssHeight*dpr)); + if(canvas.width!==width||canvas.height!==height){ canvas.width=width; canvas.height=height; gl.viewport(0,0,width,height); } }; const resizeObserver=new ResizeObserver(resize); @@ -536,17 +464,14 @@ const updatePointer=(event)=>{ if(motionReduced||coarsePointer.matches)return; const rect=visual.getBoundingClientRect(); - const x=(event.clientX-rect.left)/Math.max(rect.width,1); - const y=(event.clientY-rect.top)/Math.max(rect.height,1); + const x=(event.clientX-rect.left)/Math.max(rect.width,1),y=(event.clientY-rect.top)/Math.max(rect.height,1); pointerTarget.x=(Math.max(0,Math.min(1,x))-0.5)*2; pointerTarget.y=(0.5-Math.max(0,Math.min(1,y)))*2; }; visual.addEventListener('pointermove',updatePointer,{passive:true}); visual.addEventListener('pointerleave',()=>{pointerTarget.x=0;pointerTarget.y=0;}); - const visibilityObserver=new IntersectionObserver((entries)=>{ - visible=entries.some((entry)=>entry.isIntersecting); - },{threshold:0.02}); + const visibilityObserver=new IntersectionObserver((entries)=>{ visible=entries.some((entry)=>entry.isIntersecting); },{threshold:0.02}); visibilityObserver.observe(visual); const adaptPerformance=(delta)=>{ @@ -555,11 +480,7 @@ if(frameSamples.length<70)return; const avg=frameSamples.reduce((s,v)=>s+v,0)/frameSamples.length; frameSamples=[]; - if(avg>26&&renderScale>0.72){ - renderScale=Math.max(0.72,renderScale*0.86); - quality=Math.max(0.60,quality-0.16); - resize(); - } + if(avg>26&&renderScale>0.72){ renderScale=Math.max(0.72,renderScale*0.86); quality=Math.max(0.60,quality-0.16); resize(); } }; const start=performance.now(); @@ -570,9 +491,7 @@ pointer.x+=(pointerTarget.x-pointer.x)*0.034; pointer.y+=(pointerTarget.y-pointer.y)*0.034; const elapsed=motionReduced?7.1:(now-start)*0.001; - - gl.clearColor(0,0,0,0); - gl.clear(gl.COLOR_BUFFER_BIT); + gl.clearColor(0,0,0,0); gl.clear(gl.COLOR_BUFFER_BIT); gl.useProgram(program); gl.uniform2f(uniforms.resolution,canvas.width,canvas.height); gl.uniform2f(uniforms.pointer,pointer.x,pointer.y); @@ -581,7 +500,6 @@ gl.uniform1f(uniforms.motion,motionReduced?0:1); gl.uniform1f(uniforms.quality,mobileViewport()?Math.min(quality,0.76):quality); gl.drawArrays(gl.TRIANGLES,0,3); - if(firstFrame){ firstFrame=false; root.classList.add('hero-core2--ready'); } }; requestAnimationFrame(render); From d3086650a1409fb95e11e433f6c7de790790b6be Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:23:01 -0700 Subject: [PATCH 20/69] Ground and refine Premium Core 2.0 scene --- assets/css/hero-premium-core-2-r2.css | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/assets/css/hero-premium-core-2-r2.css b/assets/css/hero-premium-core-2-r2.css index 77faf5c1..1b48ca1c 100644 --- a/assets/css/hero-premium-core-2-r2.css +++ b/assets/css/hero-premium-core-2-r2.css @@ -18,17 +18,31 @@ } .hero-core2__canvas { - filter: saturate(.93) contrast(1.055); + filter: saturate(.90) contrast(1.075); } .hero-core2__visual::before { inset: 5% 0 1% 1%; background: - radial-gradient(circle at 50% 48%, rgba(91, 219, 246, .065), transparent 25%), - radial-gradient(circle at 61% 52%, rgba(255, 226, 184, .018), transparent 18%); + radial-gradient(circle at 50% 48%, rgba(91, 219, 246, .055), transparent 24%), + radial-gradient(circle at 61% 52%, rgba(255, 226, 184, .016), transparent 18%); filter: blur(34px); } +.hero-core2__visual::after { + content: ""; + position: absolute; + z-index: 1; + left: 24%; + right: 8%; + bottom: 8.5%; + height: 15%; + pointer-events: none; + background: radial-gradient(ellipse at center, rgba(0, 0, 0, .58) 0 18%, rgba(18, 75, 88, .10) 34%, transparent 72%); + filter: blur(18px); + opacity: .78; +} + .hero-core2__stage-button::after { width: 62px; opacity: .82; } .hero-core2__stage:nth-child(1) { left: 3%; top: 15%; } .hero-core2__stage:nth-child(2) { left: 8%; bottom: 16%; } @@ -59,6 +73,13 @@ min-height: 390px; margin-top: -8px; } + .hero-core2__visual::after { + left: 14%; + right: 10%; + bottom: 6%; + height: 13%; + opacity: .62; + } } @media (max-width: 390px) { From 5dfae3bdea0639c0297313936a99d53fceb45aa9 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:25:54 -0700 Subject: [PATCH 21/69] Harden Premium Core 2.0 R2 narrow and landscape composition --- assets/css/hero-premium-core-2-r2.css | 39 +++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/assets/css/hero-premium-core-2-r2.css b/assets/css/hero-premium-core-2-r2.css index 1b48ca1c..cf079a90 100644 --- a/assets/css/hero-premium-core-2-r2.css +++ b/assets/css/hero-premium-core-2-r2.css @@ -87,3 +87,42 @@ .hero-core2__lead { font-size: 13.7px; } .hero-core2__visual { height: 355px; min-height: 355px; margin-top: -12px; } } + +@media (max-width: 340px) { + .hero-core2__shell { + padding-top: calc(var(--core2-header) + 12px); + padding-left: 14px; + padding-right: 14px; + } + .hero-core2__eyebrow { margin-bottom: 8px; font-size: 9px; } + .hero-core2__title { max-width: 13.8ch; font-size: 35px; line-height: .97; } + .hero-core2__lead { margin-top: 11px; font-size: 12.4px; line-height: 1.40; } + .hero-core2__actions { margin-top: 12px; gap: 8px; flex-wrap: nowrap; } + .hero-core2__primary { width: 172px; gap: 5px; } + .hero-core2__button { min-height: 40px; padding: 0 11px; font-size: 9.2px; letter-spacing: .035em; } + .hero-core2__microcopy { width: 172px; font-size: 9.2px; line-height: 1.35; } + .hero-core2__button--secondary { align-self: start; } + .hero-core2__accountability { margin-top: 8px; font-size: 7.7px; line-height: 1.35; } + .hero-core2__visual { height: 190px; min-height: 190px; margin-top: -6px; } + .hero-core2__stage-button { padding-top: 4px; padding-bottom: 2px; } + .hero-core2__stage-label { font-size: 6.8px; letter-spacing: .055em; } + .hero-core2__stage-num { font-size: 7px; } + .hero-core2__stage-button::after { max-width: 46px; } +} + +@media (max-height: 500px) and (min-width: 701px) { + .hero-core2__shell { + grid-template-columns: minmax(0, .92fr) minmax(430px, 1.08fr); + padding-top: calc(var(--core2-header) + 10px); + padding-bottom: 10px; + gap: 12px; + } + .hero-core2__eyebrow { margin-bottom: 8px; } + .hero-core2__title { max-width: 12ch; font-size: clamp(39px, 4.1vw, 54px); line-height: .95; } + .hero-core2__lead { margin-top: 10px; max-width: 560px; font-size: 12.6px; line-height: 1.40; } + .hero-core2__actions { margin-top: 10px; } + .hero-core2__button { min-height: 40px; } + .hero-core2__microcopy { font-size: 9.5px; } + .hero-core2__accountability { margin-top: 8px; font-size: 8.2px; } + .hero-core2__visual { height: 76vh; min-height: 320px; } +} From f87a0cbe75d9a08d359a19391f5418c318433737 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:26:43 -0700 Subject: [PATCH 22/69] Add narrow and landscape owner-review gates --- tools/hero_premium_core_2_owner_review.mjs | 54 ++++++++++++++-------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/tools/hero_premium_core_2_owner_review.mjs b/tools/hero_premium_core_2_owner_review.mjs index 4f748a1a..e5c72069 100644 --- a/tools/hero_premium_core_2_owner_review.mjs +++ b/tools/hero_premium_core_2_owner_review.mjs @@ -35,10 +35,9 @@ async function ready(page, route, reducedMotion = 'no-preference') { await page.waitForFunction(() => document.documentElement.classList.contains('hero-core2--ready'), null, { timeout: 20000 }); await page.waitForTimeout(550); if (errors.length) throw new Error(errors.join('\n')); - return errors; } -async function captureStatic({ locale, width, height, mobile, file }) { +async function captureStatic({ locale, width, height, mobile, file, minVisualRatio = 0 }) { const context = await browser.newContext({ viewport: { width, height }, deviceScaleFactor: 1, @@ -47,23 +46,36 @@ async function captureStatic({ locale, width, height, mobile, file }) { }); const page = await context.newPage(); await ready(page, routes[locale]); - const diagnostics = await page.evaluate(() => ({ - ready: document.documentElement.classList.contains('hero-core2--ready'), - fallback: document.documentElement.classList.contains('hero-core2--fallback'), - scrollWidth: document.documentElement.scrollWidth, - innerWidth: window.innerWidth, - title: document.querySelector('.hero-core2__title')?.textContent?.trim(), - lead: document.querySelector('.hero-core2__lead')?.textContent?.trim(), - primary: document.querySelector('.hero-core2__button--primary span')?.textContent?.trim(), - stageLabels: [...document.querySelectorAll('.hero-core2__stage-label')].map(el => el.textContent.trim()), - canvas: (() => { - const c = document.querySelector('[data-hero-core2-canvas]'); - const gl = c?.getContext('webgl2'); - return { width: c?.width || 0, height: c?.height || 0, webgl2: !!gl }; - })() - })); + const diagnostics = await page.evaluate(() => { + const visual = document.querySelector('[data-hero-core2-visual]'); + const rect = visual?.getBoundingClientRect(); + const viewportVisible = rect ? Math.max(0, Math.min(rect.bottom, innerHeight) - Math.max(rect.top, 0)) : 0; + return { + ready: document.documentElement.classList.contains('hero-core2--ready'), + fallback: document.documentElement.classList.contains('hero-core2--fallback'), + scrollWidth: document.documentElement.scrollWidth, + innerWidth: window.innerWidth, + innerHeight: window.innerHeight, + title: document.querySelector('.hero-core2__title')?.textContent?.trim(), + lead: document.querySelector('.hero-core2__lead')?.textContent?.trim(), + primary: document.querySelector('.hero-core2__button--primary span')?.textContent?.trim(), + stageLabels: [...document.querySelectorAll('.hero-core2__stage-label')].map(el => el.textContent.trim()), + visual: rect ? { + top: Math.round(rect.top), + bottom: Math.round(rect.bottom), + height: Math.round(rect.height), + viewportRatio: Number((viewportVisible / Math.max(rect.height, 1)).toFixed(3)) + } : null, + canvas: (() => { + const c = document.querySelector('[data-hero-core2-canvas]'); + const gl = c?.getContext('webgl2'); + return { width: c?.width || 0, height: c?.height || 0, webgl2: !!gl }; + })() + }; + }); if (!diagnostics.ready || diagnostics.fallback || !diagnostics.canvas.webgl2) throw new Error(`${locale} ${width}x${height}: WebGL2 did not reach ready state`); if (diagnostics.scrollWidth > diagnostics.innerWidth + 1) throw new Error(`${locale} ${width}x${height}: horizontal overflow ${diagnostics.scrollWidth} > ${diagnostics.innerWidth}`); + if (minVisualRatio && (diagnostics.visual?.viewportRatio || 0) < minVisualRatio) throw new Error(`${locale} ${width}x${height}: Core visibility ratio ${(diagnostics.visual?.viewportRatio || 0)} < ${minVisualRatio}`); await page.screenshot({ path: path.join(out, file), fullPage: false }); await context.close(); return diagnostics; @@ -72,9 +84,10 @@ async function captureStatic({ locale, width, height, mobile, file }) { const diagnostics = { enDesktop: await captureStatic({ locale: 'en', width: 1440, height: 900, mobile: false, file: 'CORE2_EN_DESKTOP_1440x900.png' }), ruDesktop: await captureStatic({ locale: 'ru', width: 1440, height: 900, mobile: false, file: 'CORE2_RU_DESKTOP_1440x900.png' }), - enMobile: await captureStatic({ locale: 'en', width: 390, height: 844, mobile: true, file: 'CORE2_EN_MOBILE_390x844.png' }), - ruMobile: await captureStatic({ locale: 'ru', width: 390, height: 844, mobile: true, file: 'CORE2_RU_MOBILE_390x844.png' }), - enNarrow: await captureStatic({ locale: 'en', width: 320, height: 780, mobile: true, file: 'CORE2_EN_MOBILE_320x780.png' }) + enMobile: await captureStatic({ locale: 'en', width: 390, height: 844, mobile: true, file: 'CORE2_EN_MOBILE_390x844.png', minVisualRatio: 0.54 }), + ruMobile: await captureStatic({ locale: 'ru', width: 390, height: 844, mobile: true, file: 'CORE2_RU_MOBILE_390x844.png', minVisualRatio: 0.50 }), + enNarrow: await captureStatic({ locale: 'en', width: 320, height: 780, mobile: true, file: 'CORE2_EN_MOBILE_320x780.png', minVisualRatio: 0.72 }), + enLandscape: await captureStatic({ locale: 'en', width: 844, height: 390, mobile: true, file: 'CORE2_EN_LANDSCAPE_844x390.png', minVisualRatio: 0.78 }) }; // Reduced-motion runtime gate: WebGL remains available but the final/result state is static. @@ -130,6 +143,7 @@ for (const file of [ 'CORE2_EN_MOBILE_390x844.png', 'CORE2_RU_MOBILE_390x844.png', 'CORE2_EN_MOBILE_320x780.png', + 'CORE2_EN_LANDSCAPE_844x390.png', 'CORE2_EN_REDUCED_MOTION_390x844.png', 'CORE2_EN_DESKTOP_MOTION.mp4', 'diagnostics.json' From 038da40f6a2a962e51a912de4e51705abaecfdf9 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:31:02 -0700 Subject: [PATCH 23/69] Finalize Premium Core 2.0 short-landscape fit --- assets/css/hero-premium-core-2-r2.css | 30 ++++++++++++++++----------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/assets/css/hero-premium-core-2-r2.css b/assets/css/hero-premium-core-2-r2.css index cf079a90..267f8576 100644 --- a/assets/css/hero-premium-core-2-r2.css +++ b/assets/css/hero-premium-core-2-r2.css @@ -112,17 +112,23 @@ @media (max-height: 500px) and (min-width: 701px) { .hero-core2__shell { - grid-template-columns: minmax(0, .92fr) minmax(430px, 1.08fr); - padding-top: calc(var(--core2-header) + 10px); - padding-bottom: 10px; - gap: 12px; + grid-template-columns: minmax(0, 1fr) minmax(390px, .92fr); + padding-top: calc(var(--core2-header) + 6px); + padding-bottom: 6px; + gap: 10px; } - .hero-core2__eyebrow { margin-bottom: 8px; } - .hero-core2__title { max-width: 12ch; font-size: clamp(39px, 4.1vw, 54px); line-height: .95; } - .hero-core2__lead { margin-top: 10px; max-width: 560px; font-size: 12.6px; line-height: 1.40; } - .hero-core2__actions { margin-top: 10px; } - .hero-core2__button { min-height: 40px; } - .hero-core2__microcopy { font-size: 9.5px; } - .hero-core2__accountability { margin-top: 8px; font-size: 8.2px; } - .hero-core2__visual { height: 76vh; min-height: 320px; } + .hero-core2__copy { max-width: 470px; } + .hero-core2__eyebrow { margin-bottom: 6px; font-size: 9px; } + .hero-core2__title { max-width: 15ch; font-size: clamp(35px, 3.9vw, 48px); line-height: .93; } + .hero-core2__lead { margin-top: 7px; max-width: 470px; font-size: 11.7px; line-height: 1.34; } + .hero-core2__actions { margin-top: 7px; gap: 8px; flex-wrap: nowrap; } + .hero-core2__primary { gap: 4px; } + .hero-core2__button { min-height: 36px; padding: 0 14px; font-size: 9.4px; } + .hero-core2__microcopy { width: 225px; font-size: 8.6px; line-height: 1.25; } + .hero-core2__accountability { margin-top: 6px; font-size: 7.5px; line-height: 1.25; } + .hero-core2__visual { height: 66vh; min-height: 250px; margin-right: -12px; } + .hero-core2__stage:nth-child(1) { top: 11%; } + .hero-core2__stage:nth-child(2) { bottom: 8%; } + .hero-core2__stage:nth-child(3) { top: 19%; } + .hero-core2__stage:nth-child(4) { bottom: 7%; } } From c960e450ebb1205240b5381b545c180f1d08adb0 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:33:12 -0700 Subject: [PATCH 24/69] Remove unused Premium Core 2.0 experiment --- assets/js/hero-premium-core-2-v2.js | 589 ---------------------------- 1 file changed, 589 deletions(-) delete mode 100644 assets/js/hero-premium-core-2-v2.js diff --git a/assets/js/hero-premium-core-2-v2.js b/assets/js/hero-premium-core-2-v2.js deleted file mode 100644 index 715f8874..00000000 --- a/assets/js/hero-premium-core-2-v2.js +++ /dev/null @@ -1,589 +0,0 @@ -(() => { - 'use strict'; - - const root = document.documentElement; - const canvas = document.querySelector('[data-hero-core2-canvas]'); - const visual = document.querySelector('[data-hero-core2-visual]'); - const stageItems = [...document.querySelectorAll('[data-hero-core2-stage]')]; - const stageButtons = [...document.querySelectorAll('[data-hero-core2-stage-button]')]; - if (!canvas || !visual) return; - - const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)'); - const coarsePointer = window.matchMedia('(pointer: coarse)'); - let motionReduced = reducedMotion.matches; - let activeStage = motionReduced ? 3 : 0; - let narrativeTimers = []; - let replayTimer = null; - let manualStageUntil = 0; - - const setActiveStage = (index, manual = false) => { - activeStage = Math.max(0, Math.min(3, index)); - stageItems.forEach((item, i) => item.classList.toggle('is-active', i === activeStage)); - stageButtons.forEach((button, i) => button.setAttribute('aria-current', i === activeStage ? 'step' : 'false')); - if (manual) manualStageUntil = performance.now() + 9000; - }; - - const clearNarrative = () => { - narrativeTimers.forEach(window.clearTimeout); - narrativeTimers = []; - if (replayTimer) window.clearInterval(replayTimer); - replayTimer = null; - }; - - const runNarrative = () => { - if (motionReduced) { - setActiveStage(3); - return; - } - narrativeTimers.forEach(window.clearTimeout); - narrativeTimers = []; - [[800,0],[3000,1],[5350,2],[7900,3]].forEach(([delay, stage]) => { - narrativeTimers.push(window.setTimeout(() => { - if (performance.now() < manualStageUntil) return; - setActiveStage(stage); - }, delay)); - }); - }; - - const scheduleNarrative = () => { - clearNarrative(); - runNarrative(); - if (!motionReduced) { - replayTimer = window.setInterval(() => { - if (document.hidden || performance.now() < manualStageUntil) return; - runNarrative(); - }, 24500); - } - }; - - stageButtons.forEach((button, i) => { - button.addEventListener('mouseenter', () => setActiveStage(i, true)); - button.addEventListener('focus', () => setActiveStage(i, true)); - button.addEventListener('click', () => setActiveStage(i, true)); - }); - - setActiveStage(activeStage); - scheduleNarrative(); - reducedMotion.addEventListener?.('change', (event) => { - motionReduced = event.matches; - scheduleNarrative(); - }); - - const gl = canvas.getContext('webgl2', { - alpha: true, - antialias: false, - depth: false, - stencil: false, - premultipliedAlpha: false, - preserveDrawingBuffer: false, - powerPreference: 'high-performance' - }); - - if (!gl) { - root.classList.add('hero-core2--fallback'); - return; - } - - const vertexSource = `#version 300 es - precision highp float; - const vec2 POS[3] = vec2[3](vec2(-1.0,-1.0), vec2(3.0,-1.0), vec2(-1.0,3.0)); - void main(){ gl_Position = vec4(POS[gl_VertexID],0.0,1.0); } - `; - - const fragmentSource = `#version 300 es - precision highp float; - - uniform vec2 uResolution; - uniform vec2 uPointer; - uniform float uTime; - uniform float uStage; - uniform float uMotion; - uniform float uQuality; - out vec4 outColor; - - mat2 rot(float a){ float c=cos(a), s=sin(a); return mat2(c,-s,s,c); } - - float hash21(vec2 p){ - p=fract(p*vec2(123.34,456.21)); - p+=dot(p,p+45.32); - return fract(p.x*p.y); - } - - float sdRoundBox(vec3 p, vec3 b, float r){ - vec3 q=abs(p)-b+r; - return min(max(q.x,max(q.y,q.z)),0.0)+length(max(q,0.0))-r; - } - - float sdEllipsoid(vec3 p, vec3 r){ - float k0=length(p/r); - float k1=length(p/(r*r)); - return k0*(k0-1.0)/max(k1,0.0001); - } - - float sdPlane(vec3 p, vec3 n, float h){ return dot(p,n)+h; } - - float stageYaw(){ - if(uStage<0.5) return -0.13; - if(uStage<1.5) return -0.045; - if(uStage<2.5) return 0.065; - return 0.14; - } - - float stagePitch(){ - if(uStage<0.5) return 0.055; - if(uStage<1.5) return 0.10; - if(uStage<2.5) return 0.035; - return -0.035; - } - - vec3 objectSpace(vec3 p){ - p.y-=0.025; - float driftY=uMotion*(0.050*sin(uTime*0.205)+0.020*sin(uTime*0.071+1.8)); - float driftX=uMotion*(0.024*sin(uTime*0.157+0.6)); - float yaw=-0.22+stageYaw()+driftY+uPointer.x*0.050*uMotion; - float pitch=0.07+stagePitch()+driftX-uPointer.y*0.032*uMotion; - p.xz=rot(-yaw)*p.xz; - p.yz=rot(-pitch)*p.yz; - return p; - } - - float innerDistanceFromObject(vec3 q){ - vec3 p=q-vec3(0.075,-0.005,0.02); - p.xy=rot(0.20+uMotion*0.030*sin(uTime*0.31))*p.xy; - p.xz=rot(-0.20-uMotion*uTime*0.010)*p.xz; - float a=sdEllipsoid(p,vec3(0.40,0.54,0.30)); - vec3 b=p-vec3(0.08,0.03,-0.02); - b.yz=rot(0.42+uMotion*uTime*0.015)*b.yz; - float c=sdRoundBox(b,vec3(0.22,0.36,0.20),0.17); - return min(a,c+0.035); - } - - vec2 mapScene(vec3 p){ - vec3 q=objectSpace(p); - vec2 res=vec2(1000.0,0.0); - float breathe=uMotion*sin(uTime*0.38)*0.012; - - // Rear diagonal spine: establishes monolithic ancestry without closing the silhouette. - vec3 r=q-vec3(-0.08,0.01,-0.36); - r.xy=rot(-0.31)*r.xy; - r.xz=rot(0.10)*r.xz; - float dr=sdRoundBox(r,vec3(0.25,0.88,0.105),0.075); - vec3 rcut=q-vec3(-0.01,0.07,-0.29); - rcut.xy=rot(-0.27)*rcut.xy; - dr=max(dr,-sdEllipsoid(rcut,vec3(0.29,0.43,0.27))); - if(drmaxt) break; - } - return clamp(res,0.0,1.0); - } - - float ambientOcclusion(vec3 p, vec3 n){ - float occ=0.0, sca=1.0; - for(int i=0;i<3;i++){ - float h=0.045+0.10*float(i); - float d=mapScene(p+n*h).x; - occ+=(h-d)*sca; - sca*=0.64; - } - return clamp(1.0-1.25*occ,0.0,1.0); - } - - vec3 materialColor(float id, vec3 p, vec3 n, vec3 rd, float glow){ - vec3 graphite=vec3(0.068,0.082,0.090); - vec3 steel=vec3(0.17,0.195,0.202); - vec3 cyan=vec3(0.31,0.84,0.99); - vec3 silver=vec3(0.74,0.80,0.82); - vec3 warm=vec3(0.84,0.70,0.50); - vec3 keyPos=vec3(-2.7,3.3,4.2); - vec3 rimPos=vec3(3.3,1.8,2.6); - vec3 l=normalize(keyPos-p); - vec3 l2=normalize(rimPos-p); - vec3 v=normalize(-rd); - float ndl=max(dot(n,l),0.0); - float ndl2=max(dot(n,l2),0.0); - float sh=softShadow(p+n*0.009,l,0.03,5.6); - float ao=ambientOcclusion(p,n); - float fres=pow(1.0-max(dot(n,v),0.0),4.0); - vec3 h=normalize(l+v); - - if(id<1.5){ - float rough=0.42+0.07*sin(p.x*7.0+p.y*4.0+p.z*5.0); - float spec=pow(max(dot(n,h),0.0),mix(48.0,92.0,1.0-rough)); - vec3 base=graphite*(0.36+0.86*ndl*sh)*ao; - base+=silver*spec*0.40; - base+=cyan*fres*0.085; - base+=warm*ndl2*fres*0.035; - return base; - } - if(id<2.5){ - float spec=pow(max(dot(n,h),0.0),96.0); - vec3 base=steel*(0.40+0.94*ndl*sh)*ao; - base+=silver*spec*0.70; - base+=cyan*fres*0.10; - base+=warm*ndl2*fres*0.055; - return base; - } - if(id<3.5){ - float facing=abs(dot(n,v)); - vec3 smoke=vec3(0.018,0.042,0.050); - vec3 base=smoke*(0.36+ndl*0.24); - base+=cyan*(0.055+fres*0.31+glow*0.16); - base+=silver*pow(1.0-facing,3.0)*0.075; - return base; - } - if(id<4.5){ - float pulse=0.78+0.10*uMotion*sin(uTime*1.18+p.y*5.4)+0.036*uStage; - vec3 inner=mix(vec3(0.022,0.13,0.17),cyan,0.48+0.18*fres); - inner*=pulse*(0.72+ndl*0.14); - inner+=cyan*(0.18+fres*0.26); - return inner; - } - float radial=exp(-0.72*dot(p.xz,p.xz)); - return vec3(0.008,0.010,0.011)+cyan*radial*0.004; - } - - vec2 curveDistance(vec2 p, vec2 a, vec2 b, vec2 c, vec2 d){ - float md=10.0, mt=0.0; - vec2 prev=a; - for(int i=1;i<=24;i++){ - float t=float(i)/24.0, s=1.0-t; - vec2 cur=s*s*s*a+3.0*s*s*t*b+3.0*s*t*t*c+t*t*t*d; - vec2 pa=p-prev, ba=cur-prev; - float h=clamp(dot(pa,ba)/max(dot(ba,ba),0.00001),0.0,1.0); - float dd=length(pa-ba*h); - if(dd0.91){ - vec2 center=(cell+vec2(hash21(cell+1.7),hash21(cell+4.2)))/32.0-2.0; - dust=(1.0-smoothstep(0.002,0.013,length(uv-center)))*0.18; - } - col+=ice*dust*(0.25+0.18*uStage/3.0); - mask=max(mask,dust*0.18); - return vec4(col,mask); - } - - vec3 aces(vec3 x){ - float a=2.51,b=0.03,c=2.43,d=0.59,e=0.14; - return clamp((x*(a*x+b))/(x*(c*x+d)+e),0.0,1.0); - } - - void main(){ - vec2 frag=gl_FragCoord.xy; - vec2 p=(2.0*frag-uResolution.xy)/uResolution.y; - p.x+=0.01; - - vec3 ro=vec3(0.02+uPointer.x*0.050*uMotion,0.07+uPointer.y*0.032*uMotion,4.38); - vec3 ta=vec3(0.035,-0.015,0.0); - vec3 ww=normalize(ta-ro); - vec3 uu=normalize(cross(ww,vec3(0.0,1.0,0.0))); - vec3 vv=cross(uu,ww); - vec3 rd=normalize(uu*p.x+vv*p.y+ww*2.30); - - vec3 bg=vec3(0.004,0.0065,0.0075); - float halo=exp(-2.1*dot(p-vec2(0.04,-0.01),p-vec2(0.04,-0.01))); - bg+=vec3(0.014,0.038,0.045)*halo*0.42; - float warmEnv=exp(-6.3*dot(p-vec2(0.56,0.20),p-vec2(0.56,0.20))); - bg+=vec3(0.034,0.022,0.012)*warmEnv*0.13; - float grain=hash21(frag+floor(uTime*1.8*uMotion)); - bg+=(grain-0.5)*0.0022; - - float t=0.0,id=0.0,glow=0.0; - bool hit=false; - int maxSteps=int(mix(46.0,68.0,uQuality)); - for(int i=0;i<70;i++){ - if(i>maxSteps) break; - vec3 pos=ro+rd*t; - vec2 h=mapScene(pos); - vec3 q=objectSpace(pos); - float innerD=innerDistanceFromObject(q); - glow+=exp(-11.0*abs(innerD))*0.0092*exp(-0.08*t); - if(h.x<0.0017){ hit=true; id=h.y; break; } - t+=max(h.x*0.78,0.010); - if(t>10.0) break; - } - - vec3 color=bg; - float sceneAlpha=halo*0.055; - if(hit){ - vec3 pos=ro+rd*t; - vec3 n=calcNormal(pos); - color=materialColor(id,pos,n,rd,glow); - if(id>5.5){ - float contact=exp(-1.9*(pos.x*pos.x+pos.z*pos.z)); - color*=1.0-0.66*contact; - color+=vec3(0.31,0.84,0.99)*contact*0.004; - sceneAlpha=max(sceneAlpha,0.08+contact*0.22); - }else{ - sceneAlpha=0.98; - } - float fog=1.0-exp(-0.036*t*t); - color=mix(color,bg,fog*0.38); - } - - color+=vec3(0.20,0.76,0.94)*min(glow,0.50)*(0.30+0.075*uStage); - vec4 signal=signalField(p*vec2(0.93,0.93),hit&&id<5.5,t); - color+=signal.rgb; - sceneAlpha=max(sceneAlpha,clamp(signal.a+glow*0.25,0.0,0.56)); - - float vignette=1.0-smoothstep(0.38,1.66,length(p*vec2(0.76,0.92))); - color*=mix(0.68,1.0,vignette); - color=aces(color*1.26); - color=pow(color,vec3(0.95)); - sceneAlpha*=smoothstep(0.02,0.23,vignette+0.06); - outColor=vec4(color,clamp(sceneAlpha,0.0,0.99)); - } - `; - - const compile = (type, source) => { - const shader = gl.createShader(type); - gl.shaderSource(shader, source); - gl.compileShader(shader); - if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { - const message = gl.getShaderInfoLog(shader) || 'Unknown shader compile failure'; - gl.deleteShader(shader); - throw new Error(message); - } - return shader; - }; - - let program; - try { - const vertex = compile(gl.VERTEX_SHADER, vertexSource); - const fragment = compile(gl.FRAGMENT_SHADER, fragmentSource); - program = gl.createProgram(); - gl.attachShader(program, vertex); - gl.attachShader(program, fragment); - gl.linkProgram(program); - gl.deleteShader(vertex); - gl.deleteShader(fragment); - if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { - throw new Error(gl.getProgramInfoLog(program) || 'Hero Core 2.0 program link failed'); - } - } catch (error) { - console.error('[Hero Core 2.0 V2]', error); - root.classList.add('hero-core2--fallback'); - return; - } - - gl.useProgram(program); - const uniforms = { - resolution: gl.getUniformLocation(program,'uResolution'), - pointer: gl.getUniformLocation(program,'uPointer'), - time: gl.getUniformLocation(program,'uTime'), - stage: gl.getUniformLocation(program,'uStage'), - motion: gl.getUniformLocation(program,'uMotion'), - quality: gl.getUniformLocation(program,'uQuality') - }; - - let pointer={x:0,y:0}; - let pointerTarget={x:0,y:0}; - let visible=true; - let renderScale=1; - let quality=1; - let firstFrame=true; - let frameSamples=[]; - let lastFrame=performance.now(); - const mobileViewport=()=>window.innerWidth<=700; - - const resize=()=>{ - const rect=visual.getBoundingClientRect(); - const cssWidth=Math.max(1,Math.round(rect.width)); - const cssHeight=Math.max(1,Math.round(rect.height)); - const dprCap=mobileViewport()?1.12:1.50; - const dpr=Math.min(window.devicePixelRatio||1,dprCap)*renderScale; - const width=Math.max(2,Math.round(cssWidth*dpr)); - const height=Math.max(2,Math.round(cssHeight*dpr)); - if(canvas.width!==width||canvas.height!==height){ - canvas.width=width; - canvas.height=height; - gl.viewport(0,0,width,height); - } - }; - - const resizeObserver=new ResizeObserver(resize); - resizeObserver.observe(visual); - window.addEventListener('resize',resize,{passive:true}); - resize(); - - visual.addEventListener('pointermove',(event)=>{ - if(motionReduced||coarsePointer.matches) return; - const rect=visual.getBoundingClientRect(); - const x=(event.clientX-rect.left)/Math.max(rect.width,1); - const y=(event.clientY-rect.top)/Math.max(rect.height,1); - pointerTarget.x=(Math.max(0,Math.min(1,x))-0.5)*2; - pointerTarget.y=(0.5-Math.max(0,Math.min(1,y)))*2; - },{passive:true}); - visual.addEventListener('pointerleave',()=>{ pointerTarget.x=0; pointerTarget.y=0; }); - - const visibilityObserver=new IntersectionObserver((entries)=>{ - visible=entries.some((entry)=>entry.isIntersecting); - },{threshold:0.02}); - visibilityObserver.observe(visual); - - const adaptPerformance=(delta)=>{ - if(firstFrame||motionReduced) return; - frameSamples.push(delta); - if(frameSamples.length<72) return; - const avg=frameSamples.reduce((sum,value)=>sum+value,0)/frameSamples.length; - frameSamples=[]; - if(avg>25&&renderScale>0.72){ - renderScale=Math.max(0.72,renderScale*0.86); - quality=Math.max(0.60,quality-0.16); - resize(); - } - }; - - const start=performance.now(); - const render=(now)=>{ - requestAnimationFrame(render); - if(!visible||document.hidden) return; - const delta=now-lastFrame; - lastFrame=now; - adaptPerformance(delta); - pointer.x+=(pointerTarget.x-pointer.x)*0.035; - pointer.y+=(pointerTarget.y-pointer.y)*0.035; - const elapsed=motionReduced?7.8:(now-start)*0.001; - gl.useProgram(program); - gl.uniform2f(uniforms.resolution,canvas.width,canvas.height); - gl.uniform2f(uniforms.pointer,pointer.x,pointer.y); - gl.uniform1f(uniforms.time,elapsed); - gl.uniform1f(uniforms.stage,activeStage); - gl.uniform1f(uniforms.motion,motionReduced?0:1); - gl.uniform1f(uniforms.quality,mobileViewport()?Math.min(quality,0.76):quality); - gl.drawArrays(gl.TRIANGLES,0,3); - if(firstFrame){ - firstFrame=false; - root.classList.add('hero-core2--ready'); - } - }; - - requestAnimationFrame(render); -})(); From a55dc46a751fa5e9e2c6156f8c5c1926b7277b78 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:33:22 -0700 Subject: [PATCH 25/69] Remove unused Premium Core 2.0 experiment --- assets/css/hero-premium-core-2-v2.css | 138 -------------------------- 1 file changed, 138 deletions(-) delete mode 100644 assets/css/hero-premium-core-2-v2.css diff --git a/assets/css/hero-premium-core-2-v2.css b/assets/css/hero-premium-core-2-v2.css deleted file mode 100644 index b6e3bac5..00000000 --- a/assets/css/hero-premium-core-2-v2.css +++ /dev/null @@ -1,138 +0,0 @@ -.hero-core2__visual{ - background:transparent; -} - -.hero-core2__canvas{ - mix-blend-mode:normal; -} - -.hero-core2__visual::after{ - content:""; - position:absolute; - left:16%; - right:10%; - bottom:7%; - height:15%; - z-index:1; - pointer-events:none; - background:radial-gradient(ellipse at center, rgba(0,0,0,.48), transparent 70%); - filter:blur(18px); - opacity:.58; -} - -.hero-core2__stage-list{z-index:8;} -.hero-core2__stage:nth-child(1){left:1%;top:17%;} -.hero-core2__stage:nth-child(2){left:8%;bottom:16%;} -.hero-core2__stage:nth-child(3){right:2%;top:26%;} -.hero-core2__stage:nth-child(4){right:4%;bottom:12%;} - -@media (max-width:700px){ - .hero-core2{ - overflow:hidden; - } - - .hero-core2__shell{ - position:relative; - display:block; - min-height:100svh; - padding-bottom:26px; - } - - .hero-core2__copy{ - position:relative; - z-index:9; - width:100%; - } - - .hero-core2__title{ - max-width:13.5ch; - } - - .hero-core2__visual{ - position:absolute; - top:284px; - left:8px; - right:8px; - width:auto; - height:266px; - min-height:266px; - margin:0; - z-index:4; - } - - .hero-core2__visual::before{ - inset:-3% -4% -4%; - opacity:.9; - } - - .hero-core2__visual::after{ - left:19%; - right:15%; - bottom:8%; - height:16%; - } - - .hero-core2__lead{ - margin-top:296px; - } - - .hero-core2__stage-list{ - inset:auto 0 0; - } - - .hero-core2__stage-button{ - padding:6px 2px 3px; - } - - .hero-core2__stage-button::after{ - max-width:52px; - } -} - -@media (max-width:390px){ - .hero-core2__visual{ - top:276px; - height:244px; - min-height:244px; - } - - .hero-core2__lead{ - margin-top:270px; - } -} - -@media (max-width:340px){ - .hero-core2__visual{ - top:295px; - left:2px; - right:2px; - height:226px; - min-height:226px; - } - - .hero-core2__lead{ - margin-top:246px; - } - - .hero-core2__stage-label{ - font-size:6.9px; - } -} - -@media (max-height:500px) and (min-width:701px){ - .hero-core2__shell{ - grid-template-columns:minmax(0,.9fr) minmax(430px,1.1fr); - padding-top:calc(var(--core2-header) + 12px); - padding-bottom:12px; - gap:14px; - } - - .hero-core2__eyebrow{margin-bottom:10px;} - .hero-core2__title{font-size:clamp(40px,4.3vw,56px);max-width:11.5ch;} - .hero-core2__lead{margin-top:12px;font-size:13px;line-height:1.45;max-width:560px;} - .hero-core2__actions{margin-top:13px;} - .hero-core2__button{min-height:42px;} - .hero-core2__microcopy{font-size:10px;} - .hero-core2__accountability{margin-top:10px;font-size:8.7px;} - .hero-core2__visual{height:72vh;min-height:330px;} -} From 3ced1d82695bb5fbcfed88ec00c7ca26f64b1e1b Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:33:27 -0700 Subject: [PATCH 26/69] Keep Core silhouette open across all journey stages --- assets/js/hero-premium-core-2-r2.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/assets/js/hero-premium-core-2-r2.js b/assets/js/hero-premium-core-2-r2.js index 6be8dd47..82313877 100644 --- a/assets/js/hero-premium-core-2-r2.js +++ b/assets/js/hero-premium-core-2-r2.js @@ -120,16 +120,16 @@ float sdPlane(vec3 p,vec3 n,float h){ return dot(p,n)+h; } float stageYaw(){ - if(uStage<0.5)return -0.12; - if(uStage<1.5)return -0.035; - if(uStage<2.5)return 0.075; - return 0.14; + if(uStage<0.5)return 0.055; + if(uStage<1.5)return 0.070; + if(uStage<2.5)return 0.090; + return 0.120; } float stagePitch(){ - if(uStage<0.5)return 0.07; - if(uStage<1.5)return 0.12; - if(uStage<2.5)return 0.045; - return -0.02; + if(uStage<0.5)return 0.035; + if(uStage<1.5)return 0.040; + if(uStage<2.5)return 0.025; + return -0.010; } vec3 objectSpace(vec3 p){ From e5e13e1160acba5e0447e26bdea6ba4764071869 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:36:39 -0700 Subject: [PATCH 27/69] Trim motion pre-roll and capture full Hero narrative --- tools/hero_premium_core_2_owner_review.mjs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/hero_premium_core_2_owner_review.mjs b/tools/hero_premium_core_2_owner_review.mjs index e5c72069..2829be7e 100644 --- a/tools/hero_premium_core_2_owner_review.mjs +++ b/tools/hero_premium_core_2_owner_review.mjs @@ -104,7 +104,8 @@ const diagnostics = { await context.close(); } -// Browser-native desktop motion capture. +// Browser-native desktop motion capture. Playwright starts video recording before navigation, +// so the final MP4 trims the deterministic browser pre-roll and keeps the complete 4-stage story. const videoDir = path.join(out, '.video-tmp'); fs.mkdirSync(videoDir, { recursive: true }); let webmPath; @@ -117,7 +118,7 @@ let webmPath; const page = await context.newPage(); await ready(page, routes.en); const video = page.video(); - await page.waitForTimeout(9300); + await page.waitForTimeout(11800); await page.close(); webmPath = await video.path(); await context.close(); @@ -127,7 +128,8 @@ await browser.close(); const mp4 = path.join(out, 'CORE2_EN_DESKTOP_MOTION.mp4'); const ff = spawnSync('ffmpeg', [ - '-y', '-i', webmPath, + '-y', '-ss', '2.8', '-i', webmPath, + '-t', '9.6', '-c:v', 'libx264', '-preset', 'medium', '-crf', '20', '-pix_fmt', 'yuv420p', '-movflags', '+faststart', mp4 From 35f922580accde5b48f6800b19eb5390a5e1ba66 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:38:41 -0700 Subject: [PATCH 28/69] Keep mobile journey stages inside first Hero viewport --- assets/css/hero-premium-core-2-r2.css | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/assets/css/hero-premium-core-2-r2.css b/assets/css/hero-premium-core-2-r2.css index 267f8576..a3206bf3 100644 --- a/assets/css/hero-premium-core-2-r2.css +++ b/assets/css/hero-premium-core-2-r2.css @@ -73,6 +73,12 @@ min-height: 390px; margin-top: -8px; } + .hero-core2__stage-list { + inset: 0 4px auto 4px; + } + .hero-core2__canvas { + transform: translateY(13px); + } .hero-core2__visual::after { left: 14%; right: 10%; @@ -104,6 +110,8 @@ .hero-core2__button--secondary { align-self: start; } .hero-core2__accountability { margin-top: 8px; font-size: 7.7px; line-height: 1.35; } .hero-core2__visual { height: 190px; min-height: 190px; margin-top: -6px; } + .hero-core2__stage-list { inset: 0 2px auto 2px; } + .hero-core2__canvas { transform: translateY(11px); } .hero-core2__stage-button { padding-top: 4px; padding-bottom: 2px; } .hero-core2__stage-label { font-size: 6.8px; letter-spacing: .055em; } .hero-core2__stage-num { font-size: 7px; } From e7c7be8330672b12b938c8a5f49ac3593c0dacc5 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:41:37 -0700 Subject: [PATCH 29/69] Replace rejected box-like loading fallback --- assets/css/hero-premium-core-2-r2.css | 45 ++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/assets/css/hero-premium-core-2-r2.css b/assets/css/hero-premium-core-2-r2.css index a3206bf3..c8f02af5 100644 --- a/assets/css/hero-premium-core-2-r2.css +++ b/assets/css/hero-premium-core-2-r2.css @@ -21,6 +21,43 @@ filter: saturate(.90) contrast(1.075); } +/* Loading/fallback state follows the same open sculptural language as the live Core. + It deliberately avoids the rejected closed-box silhouette. */ +.hero-core2__fallback { + transform: translate(-48%, -50%) rotate(-7deg); + opacity: .70; +} +.hero-core2__fallback::before, +.hero-core2__fallback::after, +.hero-core2__fallback span { + border: 1px solid rgba(210, 229, 235, .12); + box-shadow: inset 0 1px rgba(255,255,255,.10), 0 26px 70px rgba(0,0,0,.38); +} +.hero-core2__fallback::before { + inset: 11% 19% 65% 8%; + border-radius: 15px 26px 12px 19px; + clip-path: polygon(0 16%, 74% 0, 100% 34%, 88% 100%, 19% 82%); + background: linear-gradient(142deg, rgba(76,87,92,.78), rgba(13,17,19,.92)); + transform: rotate(-7deg); +} +.hero-core2__fallback::after { + inset: 28% 9% 20% 70%; + border-radius: 18px 12px 24px 13px; + clip-path: polygon(22% 0, 100% 16%, 86% 84%, 36% 100%, 0 72%, 10% 18%); + background: linear-gradient(155deg, rgba(48,57,61,.84), rgba(9,12,14,.95)); + transform: rotate(8deg); + filter: none; +} +.hero-core2__fallback span { + inset: 29% 31% 23% 31%; + border: 1px solid rgba(103,225,250,.12); + border-radius: 48% 52% 45% 55% / 55% 47% 53% 45%; + clip-path: none; + background: radial-gradient(circle at 45% 48%, rgba(95,225,250,.46), rgba(8,42,50,.58) 34%, rgba(5,13,16,.90) 72%); + box-shadow: 0 0 34px rgba(75,211,239,.13), inset 0 0 28px rgba(83,220,246,.08); + transform: rotate(13deg); +} + .hero-core2__visual::before { inset: 5% 0 1% 1%; background: @@ -73,12 +110,6 @@ min-height: 390px; margin-top: -8px; } - .hero-core2__stage-list { - inset: 0 4px auto 4px; - } - .hero-core2__canvas { - transform: translateY(13px); - } .hero-core2__visual::after { left: 14%; right: 10%; @@ -110,8 +141,6 @@ .hero-core2__button--secondary { align-self: start; } .hero-core2__accountability { margin-top: 8px; font-size: 7.7px; line-height: 1.35; } .hero-core2__visual { height: 190px; min-height: 190px; margin-top: -6px; } - .hero-core2__stage-list { inset: 0 2px auto 2px; } - .hero-core2__canvas { transform: translateY(11px); } .hero-core2__stage-button { padding-top: 4px; padding-bottom: 2px; } .hero-core2__stage-label { font-size: 6.8px; letter-spacing: .055em; } .hero-core2__stage-num { font-size: 7px; } From 9d55423e0eb41274a790cebcb5148126067b3c90 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:43:40 -0700 Subject: [PATCH 30/69] Document Premium Core 2.0 owner-review candidate --- ...M_CORE_2_OWNER_REVIEW_STATUS_2026-08-11.md | 174 ++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 docs/site-evolution/PROAI_HERO_PREMIUM_CORE_2_OWNER_REVIEW_STATUS_2026-08-11.md diff --git a/docs/site-evolution/PROAI_HERO_PREMIUM_CORE_2_OWNER_REVIEW_STATUS_2026-08-11.md b/docs/site-evolution/PROAI_HERO_PREMIUM_CORE_2_OWNER_REVIEW_STATUS_2026-08-11.md new file mode 100644 index 00000000..a8368c03 --- /dev/null +++ b/docs/site-evolution/PROAI_HERO_PREMIUM_CORE_2_OWNER_REVIEW_STATUS_2026-08-11.md @@ -0,0 +1,174 @@ +# ProAI Expert Hero — Premium Core 2.0 — Owner Review Status + +Date: 2026-08-11 +Status: **PENDING OWNER REVIEW** +Scope: **HERO ONLY / ISOLATED PREVIEW ONLY** + +Repository: `proaiexpert/proaiexpert.github.io` +Source/research branch: `agent/hero-layered-25d-static-r1` +Implementation branch: `agent/hero-premium-core-2-r1` + +## 1. Source of truth + +Implementation follows: + +- `docs/site-evolution/PROAI_HERO_NEXT_CHAT_PREMIUM_CORE_100K_BUILD_BRIEF_2026-08-11.md` +- `docs/site-evolution/PROAI_HERO_EN_COPY_LOCK_2026-08-11.md` +- `docs/site-evolution/PROAI_HERO_RU_COPY_LOCK_2026-08-11.md` + +The rejected simple machined/closed box direction was not reused as the active art direction. + +## 2. Copy lock execution + +Final EN/RU Hero copy and CTA locks were applied before Premium Core visual development. + +H1 remains one authored continuous string in both languages; no authored `
` or split slogan markup was introduced. + +Locked stage chains remain: + +- EN: `TRUST → INQUIRY → RESPONSE → RESULT` +- RU: `ДОВЕРИЕ → ОБРАЩЕНИЕ → ОТВЕТ → РЕЗУЛЬТАТ` + +## 3. Active owner-review routes + +- EN: `/hero-premium-core-2-preview/` +- RU: `/ru/hero-premium-core-2-preview/` + +These routes are isolated candidates only. + +## 4. Active implementation + +### DOM / layout + +- `hero-premium-core-2-preview/index.html` +- `ru/hero-premium-core-2-preview/index.html` +- `assets/css/hero-premium-core-2.css` +- `assets/css/hero-premium-core-2-r2.css` + +DOM owns: + +- header/navigation; +- eyebrow; +- H1/support copy; +- CTA/microcopy/accountability; +- accessible `01–04` stage typography; +- responsive/mobile composition. + +### WebGL2 + +Active renderer: + +- `assets/js/hero-premium-core-2-r2.js` + +The active scene is procedural WebGL2 rather than the prior flattened Layered 2.5D PNG compositor. + +It contains: + +- asymmetric multi-mass sculptural Core geometry; +- graphite / dark-steel material families; +- a curved smoked aperture rather than a large rectangular screen; +- a contained dark intelligence volume with localized cyan rim/filament response; +- fine internal structural ribs; +- transparent scene integration into one near-black Hero environment; +- non-concentric spline-derived signal trajectories; +- fragmented-to-resolved signal behavior; +- localized moving pulses and sparse data marks; +- Core/signal occlusion behavior; +- stage-driven orientation/state changes; +- pointer micro-parallax on fine-pointer devices; +- adaptive render scale / quality reduction under sustained slow frames; +- reduced-motion final-state behavior. + +## 5. Motion correction before owner review + +An internal motion review found that early TRUST/INQUIRY angles could visually collapse the open Core silhouette into a more closed mass. + +That candidate was rejected internally before owner review. + +The active motion orientation was corrected so all four journey states preserve the open sculptural silhouette while still changing orientation subtly. + +## 6. Mobile recomposition + +Mobile is not a desktop shrink. + +The active mobile pass includes: + +- dedicated 390px composition; +- dedicated 320px/narrow composition; +- compact `01–04` journey row moved to the top of the mobile visual field so the stages remain visible in the first Hero view; +- short-landscape compaction; +- reduced rendering scale/quality budget on small devices; +- no horizontal document overflow in browser QA. + +## 7. Final automated/browser QA + +Final owner-review QA source commit: + +`35f922580accde5b48f6800b19eb5390a5e1ba66` + +GitHub Actions run: + +`31478630493` + +Result: + +**SUCCESS** + +Final artifact: + +- name: `PROAI_HERO_PREMIUM_CORE_2_OWNER_REVIEW` +- artifact id: `9096345760` +- SHA-256 digest: `d13438126a41bca995b0a2367a2281ba6c2bbd88461d2a9f6f0a6dc6fcc480a9` +- retention: 14 days from the run + +The package contains: + +- `CORE2_EN_DESKTOP_1440x900.png` +- `CORE2_RU_DESKTOP_1440x900.png` +- `CORE2_EN_MOBILE_390x844.png` +- `CORE2_RU_MOBILE_390x844.png` +- `CORE2_EN_MOBILE_320x780.png` +- `CORE2_EN_LANDSCAPE_844x390.png` +- `CORE2_EN_REDUCED_MOTION_390x844.png` +- `CORE2_EN_DESKTOP_MOTION.mp4` +- `diagnostics.json` + +Automated gates passed for: + +- production-route protection; +- exact EN/RU copy locks; +- no authored H1 hard split; +- Jekyll build; +- WebGL2 ready state; +- no fallback on tested Chromium captures; +- no page/console errors in capture flow; +- no horizontal document overflow in tested viewports; +- desktop EN/RU captures; +- 390px EN/RU captures; +- 320px narrow capture; +- 844×390 short-landscape capture; +- reduced-motion final-state behavior; +- desktop motion capture; +- active R2 implementation/static guards. + +## 8. Internal visual quality gate + +The first Premium Core implementation was not accepted internally merely because technical QA passed. It was revised because it still read too much like rounded box components around a cyan insert and exposed a visible WebGL panel boundary. + +The active candidate removes that panel boundary, uses transparent scene integration, reduces the cyan/reactor effect, introduces a curved smoked aperture, keeps the Core open across the full motion sequence, and materially separates the scene from the rejected closed-box direction. + +This is now an **owner-review candidate**, not an owner-approved final Hero. + +## 9. Production safety + +- Production `/index.html` was not modified by this Premium Core 2.0 pass. +- Production `/ru/index.html` was not modified by this Premium Core 2.0 pass. +- No production merge was performed. +- No production deploy was performed. +- No production PR was opened. +- Existing C-shape/recovery/history files were not deleted. +- Financial Stream was not touched. + +A draft owner-review PR exists only between the isolated implementation branch and the research/archive branch. It must not be merged or retargeted to production without explicit owner authorization. + +**PENDING OWNER REVIEW** From 66ae1ab29f7b4abc67f9e17d7ce0174f2322347e Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:47:12 -0700 Subject: [PATCH 31/69] Verify autonomous narrative and deterministic motion review --- tools/hero_premium_core_2_owner_review.mjs | 28 ++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/tools/hero_premium_core_2_owner_review.mjs b/tools/hero_premium_core_2_owner_review.mjs index 2829be7e..1ce0ca9d 100644 --- a/tools/hero_premium_core_2_owner_review.mjs +++ b/tools/hero_premium_core_2_owner_review.mjs @@ -104,8 +104,20 @@ const diagnostics = { await context.close(); } -// Browser-native desktop motion capture. Playwright starts video recording before navigation, -// so the final MP4 trims the deterministic browser pre-roll and keeps the complete 4-stage story. +// Autonomous narrative gate: without interaction the normal sequence must resolve to 04 RESULT. +{ + const context = await browser.newContext({ viewport: { width: 1440, height: 900 }, deviceScaleFactor: 1 }); + const page = await context.newPage(); + await ready(page, routes.en); + await page.waitForTimeout(8500); + const active = await page.evaluate(() => [...document.querySelectorAll('[data-hero-core2-stage]')].findIndex(el => el.classList.contains('is-active'))); + if (active !== 3) throw new Error(`Autonomous narrative did not resolve to RESULT: active stage ${active}`); + await context.close(); +} + +// Browser-native desktop motion capture. Playwright starts video before navigation, so the MP4 +// trims browser pre-roll. Stage activation is controlled here only to make the review artifact +// deterministic; the autonomous narrative is verified independently above. const videoDir = path.join(out, '.video-tmp'); fs.mkdirSync(videoDir, { recursive: true }); let webmPath; @@ -118,7 +130,15 @@ let webmPath; const page = await context.newPage(); await ready(page, routes.en); const video = page.video(); - await page.waitForTimeout(11800); + const stages = page.locator('[data-hero-core2-stage-button]'); + await stages.nth(0).click(); + await page.waitForTimeout(1900); + await stages.nth(1).click(); + await page.waitForTimeout(1900); + await stages.nth(2).click(); + await page.waitForTimeout(1900); + await stages.nth(3).click(); + await page.waitForTimeout(2700); await page.close(); webmPath = await video.path(); await context.close(); @@ -129,7 +149,7 @@ await browser.close(); const mp4 = path.join(out, 'CORE2_EN_DESKTOP_MOTION.mp4'); const ff = spawnSync('ffmpeg', [ '-y', '-ss', '2.8', '-i', webmPath, - '-t', '9.6', + '-t', '9.0', '-c:v', 'libx264', '-preset', 'medium', '-crf', '20', '-pix_fmt', 'yuv420p', '-movflags', '+faststart', mp4 From a4c2e5fddb16c611af066adb8532a34a433005e7 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:52:51 -0700 Subject: [PATCH 32/69] Make Premium Core motion capture timing deterministic --- tools/hero_premium_core_2_owner_review.mjs | 31 ++++++++++++++++++---- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/tools/hero_premium_core_2_owner_review.mjs b/tools/hero_premium_core_2_owner_review.mjs index 1ce0ca9d..26f60cd6 100644 --- a/tools/hero_premium_core_2_owner_review.mjs +++ b/tools/hero_premium_core_2_owner_review.mjs @@ -112,12 +112,12 @@ const diagnostics = { await page.waitForTimeout(8500); const active = await page.evaluate(() => [...document.querySelectorAll('[data-hero-core2-stage]')].findIndex(el => el.classList.contains('is-active'))); if (active !== 3) throw new Error(`Autonomous narrative did not resolve to RESULT: active stage ${active}`); + diagnostics.autonomousNarrativeFinalStage = active; await context.close(); } -// Browser-native desktop motion capture. Playwright starts video before navigation, so the MP4 -// trims browser pre-roll. Stage activation is controlled here only to make the review artifact -// deterministic; the autonomous narrative is verified independently above. +// Browser-native desktop motion capture. Stage activation is controlled only for a deterministic +// owner-review artifact; the autonomous sequence is independently verified above. const videoDir = path.join(out, '.video-tmp'); fs.mkdirSync(videoDir, { recursive: true }); let webmPath; @@ -146,10 +146,31 @@ let webmPath; await browser.close(); +// Detect the first dark Hero frame instead of assuming a fixed browser-navigation pre-roll. +const statsPath = path.join(videoDir, 'signalstats.txt'); +const scan = spawnSync('ffmpeg', [ + '-y', '-i', webmPath, + '-vf', `signalstats,metadata=print:file=${statsPath}`, + '-an', '-f', 'null', '-' +], { stdio: ['ignore', 'ignore', 'inherit'] }); +if (scan.status !== 0) process.exit(scan.status ?? 1); + +let currentPts = 0; +let trimStart = 0; +for (const line of fs.readFileSync(statsPath, 'utf8').split(/\r?\n/)) { + const tm = line.match(/pts_time:([0-9.]+)/); + if (tm) currentPts = Number(tm[1]); + const ym = line.match(/lavfi\.signalstats\.YAVG=([0-9.]+)/); + if (ym && Number(ym[1]) < 120) { + trimStart = Math.max(0, currentPts - 0.08); + break; + } +} +diagnostics.motionTrimStartSeconds = Number(trimStart.toFixed(3)); + const mp4 = path.join(out, 'CORE2_EN_DESKTOP_MOTION.mp4'); const ff = spawnSync('ffmpeg', [ - '-y', '-ss', '2.8', '-i', webmPath, - '-t', '9.0', + '-y', '-ss', String(trimStart), '-i', webmPath, '-c:v', 'libx264', '-preset', 'medium', '-crf', '20', '-pix_fmt', 'yuv420p', '-movflags', '+faststart', mp4 From c46570b164529e27e04f5707827fbe0c59435a57 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 02:58:20 -0700 Subject: [PATCH 33/69] Trim motion review from post-ready marker --- tools/hero_premium_core_2_owner_review.mjs | 26 +++++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/tools/hero_premium_core_2_owner_review.mjs b/tools/hero_premium_core_2_owner_review.mjs index 26f60cd6..83d63e7f 100644 --- a/tools/hero_premium_core_2_owner_review.mjs +++ b/tools/hero_premium_core_2_owner_review.mjs @@ -130,6 +130,21 @@ let webmPath; const page = await context.newPage(); await ready(page, routes.en); const video = page.video(); + + // Full-frame marker is inserted only into the raw capture after the Hero is ready. The final + // encoding trims through the end of this marker, so it never appears in the review MP4. + await page.evaluate(() => { + const marker = document.createElement('div'); + marker.id = 'hero-core2-capture-marker'; + Object.assign(marker.style, { + position: 'fixed', inset: '0', background: '#ffffff', zIndex: '2147483647', pointerEvents: 'none' + }); + document.body.appendChild(marker); + }); + await page.waitForTimeout(240); + await page.evaluate(() => document.getElementById('hero-core2-capture-marker')?.remove()); + await page.waitForTimeout(120); + const stages = page.locator('[data-hero-core2-stage-button]'); await stages.nth(0).click(); await page.waitForTimeout(1900); @@ -146,7 +161,8 @@ let webmPath; await browser.close(); -// Detect the first dark Hero frame instead of assuming a fixed browser-navigation pre-roll. +// Find the last full-white marker frame. Initial browser pre-roll may also be white, so the last +// high-luminance frame is the stable boundary immediately before the deterministic Hero sequence. const statsPath = path.join(videoDir, 'signalstats.txt'); const scan = spawnSync('ffmpeg', [ '-y', '-i', webmPath, @@ -156,16 +172,14 @@ const scan = spawnSync('ffmpeg', [ if (scan.status !== 0) process.exit(scan.status ?? 1); let currentPts = 0; -let trimStart = 0; +let lastWhitePts = 0; for (const line of fs.readFileSync(statsPath, 'utf8').split(/\r?\n/)) { const tm = line.match(/pts_time:([0-9.]+)/); if (tm) currentPts = Number(tm[1]); const ym = line.match(/lavfi\.signalstats\.YAVG=([0-9.]+)/); - if (ym && Number(ym[1]) < 120) { - trimStart = Math.max(0, currentPts - 0.08); - break; - } + if (ym && Number(ym[1]) > 220) lastWhitePts = currentPts; } +const trimStart = Math.max(0, lastWhitePts + 0.08); diagnostics.motionTrimStartSeconds = Number(trimStart.toFixed(3)); const mp4 = path.join(out, 'CORE2_EN_DESKTOP_MOTION.mp4'); From d7ed1b7fcbea55d1a492bde94b3efe30e37b720d Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 03:04:56 -0700 Subject: [PATCH 34/69] Add deterministic four-stage owner review captures --- tools/hero_premium_core_2_owner_review.mjs | 29 +++++++++++++++++----- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/tools/hero_premium_core_2_owner_review.mjs b/tools/hero_premium_core_2_owner_review.mjs index 83d63e7f..bb42bc05 100644 --- a/tools/hero_premium_core_2_owner_review.mjs +++ b/tools/hero_premium_core_2_owner_review.mjs @@ -116,8 +116,25 @@ const diagnostics = { await context.close(); } -// Browser-native desktop motion capture. Stage activation is controlled only for a deterministic -// owner-review artifact; the autonomous sequence is independently verified above. +// Deterministic owner-review captures for all four stage-driven states. +{ + const names = ['TRUST', 'INQUIRY', 'RESPONSE', 'RESULT']; + const context = await browser.newContext({ viewport: { width: 1440, height: 900 }, deviceScaleFactor: 1 }); + const page = await context.newPage(); + await ready(page, routes.en); + const stages = page.locator('[data-hero-core2-stage-button]'); + for (let i = 0; i < names.length; i += 1) { + await stages.nth(i).click(); + await page.waitForTimeout(550); + const active = await page.evaluate(() => [...document.querySelectorAll('[data-hero-core2-stage]')].findIndex(el => el.classList.contains('is-active'))); + if (active !== i) throw new Error(`Stage review capture mismatch for ${names[i]}: active ${active}`); + await page.screenshot({ path: path.join(out, `CORE2_EN_STAGE_0${i + 1}_${names[i]}.png`), fullPage: false }); + } + await context.close(); +} + +// Browser-native motion sample. Stage-state stills above are the deterministic visual authority; +// the autonomous sequence is independently verified above. const videoDir = path.join(out, '.video-tmp'); fs.mkdirSync(videoDir, { recursive: true }); let webmPath; @@ -131,8 +148,6 @@ let webmPath; await ready(page, routes.en); const video = page.video(); - // Full-frame marker is inserted only into the raw capture after the Hero is ready. The final - // encoding trims through the end of this marker, so it never appears in the review MP4. await page.evaluate(() => { const marker = document.createElement('div'); marker.id = 'hero-core2-capture-marker'; @@ -161,8 +176,6 @@ let webmPath; await browser.close(); -// Find the last full-white marker frame. Initial browser pre-roll may also be white, so the last -// high-luminance frame is the stable boundary immediately before the deterministic Hero sequence. const statsPath = path.join(videoDir, 'signalstats.txt'); const scan = spawnSync('ffmpeg', [ '-y', '-i', webmPath, @@ -202,6 +215,10 @@ for (const file of [ 'CORE2_EN_MOBILE_320x780.png', 'CORE2_EN_LANDSCAPE_844x390.png', 'CORE2_EN_REDUCED_MOTION_390x844.png', + 'CORE2_EN_STAGE_01_TRUST.png', + 'CORE2_EN_STAGE_02_INQUIRY.png', + 'CORE2_EN_STAGE_03_RESPONSE.png', + 'CORE2_EN_STAGE_04_RESULT.png', 'CORE2_EN_DESKTOP_MOTION.mp4', 'diagnostics.json' ]) { From b514e9ed74df63291614730c13c53dff5b5eae13 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 03:12:25 -0700 Subject: [PATCH 35/69] Keep four-stage journey visible on 390-class mobile --- assets/css/hero-premium-core-2-r2.css | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/assets/css/hero-premium-core-2-r2.css b/assets/css/hero-premium-core-2-r2.css index c8f02af5..b88602a1 100644 --- a/assets/css/hero-premium-core-2-r2.css +++ b/assets/css/hero-premium-core-2-r2.css @@ -119,10 +119,22 @@ } } +/* 390-class mobile browsers may expose a ~400–430px layout viewport in headless/device emulation. + Keep the complete Core + 01–04 journey inside the first physical capture in both EN and RU. */ +@media (max-width: 430px) { + .hero-core2__visual { + height: 250px; + min-height: 250px; + margin-top: -10px; + } + .hero-core2__stage-list { inset: 0; } + .hero-core2__stage-button { padding-top: 5px; padding-bottom: 2px; } +} + @media (max-width: 390px) { .hero-core2__title { font-size: clamp(38px, 10.6vw, 45px); } .hero-core2__lead { font-size: 13.7px; } - .hero-core2__visual { height: 355px; min-height: 355px; margin-top: -12px; } + .hero-core2__visual { height: 250px; min-height: 250px; margin-top: -10px; } } @media (max-width: 340px) { @@ -168,4 +180,4 @@ .hero-core2__stage:nth-child(2) { bottom: 8%; } .hero-core2__stage:nth-child(3) { top: 19%; } .hero-core2__stage:nth-child(4) { bottom: 7%; } -} +} \ No newline at end of file From 0ffb0c7d71c8184ec41f2e9e79bc561a92ef8919 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 03:18:45 -0700 Subject: [PATCH 36/69] Finalize Premium Core 2.0 owner-review status --- ...M_CORE_2_OWNER_REVIEW_STATUS_2026-08-11.md | 152 +++++++++++++----- 1 file changed, 116 insertions(+), 36 deletions(-) diff --git a/docs/site-evolution/PROAI_HERO_PREMIUM_CORE_2_OWNER_REVIEW_STATUS_2026-08-11.md b/docs/site-evolution/PROAI_HERO_PREMIUM_CORE_2_OWNER_REVIEW_STATUS_2026-08-11.md index a8368c03..40f3de54 100644 --- a/docs/site-evolution/PROAI_HERO_PREMIUM_CORE_2_OWNER_REVIEW_STATUS_2026-08-11.md +++ b/docs/site-evolution/PROAI_HERO_PREMIUM_CORE_2_OWNER_REVIEW_STATUS_2026-08-11.md @@ -1,12 +1,13 @@ # ProAI Expert Hero — Premium Core 2.0 — Owner Review Status Date: 2026-08-11 -Status: **PENDING OWNER REVIEW** +Status: **READY FOR OWNER REVIEW — NOT PRODUCTION AUTHORIZED** Scope: **HERO ONLY / ISOLATED PREVIEW ONLY** Repository: `proaiexpert/proaiexpert.github.io` Source/research branch: `agent/hero-layered-25d-static-r1` -Implementation branch: `agent/hero-premium-core-2-r1` +Implementation branch: `agent/hero-premium-core-2-r1` +Draft owner-review PR: `#117` — base is the research/archive branch only ## 1. Source of truth @@ -18,7 +19,7 @@ Implementation follows: The rejected simple machined/closed box direction was not reused as the active art direction. -## 2. Copy lock execution +## 2. Copy lock execution — completed first Final EN/RU Hero copy and CTA locks were applied before Premium Core visual development. @@ -29,16 +30,21 @@ Locked stage chains remain: - EN: `TRUST → INQUIRY → RESPONSE → RESULT` - RU: `ДОВЕРИЕ → ОБРАЩЕНИЕ → ОТВЕТ → РЕЗУЛЬТАТ` +Primary CTA locks remain: + +- EN: `Request a Review` +- RU: `Запросить разбор` + ## 3. Active owner-review routes - EN: `/hero-premium-core-2-preview/` - RU: `/ru/hero-premium-core-2-preview/` -These routes are isolated candidates only. +These routes are isolated candidates only. They are not production `/` or `/ru/`. ## 4. Active implementation -### DOM / layout +### DOM / layout ownership - `hero-premium-core-2-preview/index.html` - `ru/hero-premium-core-2-preview/index.html` @@ -54,7 +60,7 @@ DOM owns: - accessible `01–04` stage typography; - responsive/mobile composition. -### WebGL2 +### WebGL2 ownership Active renderer: @@ -65,10 +71,12 @@ The active scene is procedural WebGL2 rather than the prior flattened Layered 2. It contains: - asymmetric multi-mass sculptural Core geometry; +- open negative space rather than a closed product box; +- rear graphite spine, crown/upper shell mass, lower keel, detached output fin and floating collector/front masses; - graphite / dark-steel material families; -- a curved smoked aperture rather than a large rectangular screen; -- a contained dark intelligence volume with localized cyan rim/filament response; -- fine internal structural ribs; +- a restrained smoked aperture rather than a large rectangular screen; +- a contained internal intelligence volume with localized cyan rim/filament response; +- internal structural ribs/depth layers; - transparent scene integration into one near-black Hero environment; - non-concentric spline-derived signal trajectories; - fragmented-to-resolved signal behavior; @@ -79,36 +87,68 @@ It contains: - adaptive render scale / quality reduction under sustained slow frames; - reduced-motion final-state behavior. -## 5. Motion correction before owner review +## 5. Abstract Signal Field + +The rejected simple dotted ellipse/orbit treatment was not reused. + +The active field uses: + +- multiple non-concentric cubic trajectory families; +- broken-to-continuous line phases; +- localized pulses rather than uniform neon glow; +- depth/occlusion around the Core; +- restrained branching and sparse data marks; +- visual progression from fragmented input toward cleaner output/result states. -An internal motion review found that early TRUST/INQUIRY angles could visually collapse the open Core silhouette into a more closed mass. +## 6. Motion / journey behavior -That candidate was rejected internally before owner review. +The normal Hero remains immediately readable; copy is not hidden behind an intro. -The active motion orientation was corrected so all four journey states preserve the open sculptural silhouette while still changing orientation subtly. +The active choreography supports: -## 6. Mobile recomposition +1. `01 TRUST` +2. `02 INQUIRY` +3. `03 RESPONSE` +4. `04 RESULT` +5. continuing authored idle motion after resolution + +Stage changes affect DOM emphasis plus Core orientation/signal state. + +The four stages can also be activated by hover/focus/click/tap. The final QA independently verifies that the autonomous sequence resolves to stage index `3`, i.e. `04 RESULT`. + +Reduced-motion mode keeps the scene available but parks it in the stable final/result state rather than replaying the full sequence. + +## 7. Mobile recomposition Mobile is not a desktop shrink. The active mobile pass includes: -- dedicated 390px composition; -- dedicated 320px/narrow composition; -- compact `01–04` journey row moved to the top of the mobile visual field so the stages remain visible in the first Hero view; +- 390-class composition; +- 320px/narrow composition; - short-landscape compaction; +- compact `01–04` journey row integrated with the mobile visual field; +- smaller Core visual zone on 390-class widths so copy, CTA, accountability, all four stages and the Core remain visible in the first owner-review frame in both EN and RU; - reduced rendering scale/quality budget on small devices; - no horizontal document overflow in browser QA. -## 7. Final automated/browser QA +Manual review after the automated run specifically caught and corrected a 390px issue where stage labels could fall below the physical screenshot despite the WebGL area technically intersecting the viewport. The final 390-class captures now visibly include all `01–04` labels in both languages. + +## 8. Loading / fallback behavior -Final owner-review QA source commit: +The initial loading fallback was also reviewed against the rejection gate. -`35f922580accde5b48f6800b19eb5390a5e1ba66` +A box-like fallback was rejected and replaced with an open asymmetric fallback composition so the page does not briefly regress to the rejected closed-box silhouette before WebGL becomes ready. + +## 9. Final automated/browser QA + +Final tested implementation commit: + +`b514e9ed74df63291614730c13c53dff5b5eae13` GitHub Actions run: -`31478630493` +`31481180408` Result: @@ -117,11 +157,12 @@ Result: Final artifact: - name: `PROAI_HERO_PREMIUM_CORE_2_OWNER_REVIEW` -- artifact id: `9096345760` -- SHA-256 digest: `d13438126a41bca995b0a2367a2281ba6c2bbd88461d2a9f6f0a6dc6fcc480a9` +- artifact id: `9097364475` +- SHA-256 digest: `b375eea58a70c827a5f1141272a3208e6b06f01233d5add1a756cb71a5b6ee71` +- artifact size: `3,125,751` bytes - retention: 14 days from the run -The package contains: +The final package contains: - `CORE2_EN_DESKTOP_1440x900.png` - `CORE2_RU_DESKTOP_1440x900.png` @@ -130,6 +171,10 @@ The package contains: - `CORE2_EN_MOBILE_320x780.png` - `CORE2_EN_LANDSCAPE_844x390.png` - `CORE2_EN_REDUCED_MOTION_390x844.png` +- `CORE2_EN_STAGE_01_TRUST.png` +- `CORE2_EN_STAGE_02_INQUIRY.png` +- `CORE2_EN_STAGE_03_RESPONSE.png` +- `CORE2_EN_STAGE_04_RESULT.png` - `CORE2_EN_DESKTOP_MOTION.mp4` - `diagnostics.json` @@ -140,35 +185,70 @@ Automated gates passed for: - no authored H1 hard split; - Jekyll build; - WebGL2 ready state; -- no fallback on tested Chromium captures; +- no fallback on tested Chromium captures after ready; - no page/console errors in capture flow; - no horizontal document overflow in tested viewports; - desktop EN/RU captures; -- 390px EN/RU captures; +- 390-class EN/RU captures; - 320px narrow capture; - 844×390 short-landscape capture; - reduced-motion final-state behavior; -- desktop motion capture; -- active R2 implementation/static guards. +- autonomous narrative resolution to `04 RESULT`; +- four deterministic stage-state captures; +- desktop browser-native motion sample; +- active R2 implementation/static rejection guards. + +## 10. Final diagnostics summary + +Final browser diagnostics report: + +- EN desktop 1440×900: WebGL2 ready, fallback false, visual viewport ratio `1.0`, no horizontal overflow; +- RU desktop 1440×900: WebGL2 ready, fallback false, visual viewport ratio `1.0`, no horizontal overflow; +- EN 390-class capture: visual viewport ratio `1.0`, all `01–04` visible in manual capture review; +- RU 390-class capture: visual viewport ratio `1.0`, all `01–04` visible in manual capture review; +- EN 320/narrow capture: visual viewport ratio `1.0`; +- EN short-landscape capture: visual viewport ratio `1.0`; +- autonomous final stage: `3` = `04 RESULT`. + +## 11. Internal visual quality gate + +The first Premium Core implementation was not accepted merely because technical QA passed. It was revised because it still read too much like rounded box components around a cyan insert and exposed a visible WebGL panel boundary. + +Subsequent internal review also corrected: + +- overly closed Core readings in some angles; +- 320px composition; +- short-landscape fit; +- box-like loading fallback; +- 390-class stage visibility; +- owner-review motion/stage evidence. -## 8. Internal visual quality gate +The active candidate now: -The first Premium Core implementation was not accepted internally merely because technical QA passed. It was revised because it still read too much like rounded box components around a cyan insert and exposed a visible WebGL panel boundary. +- avoids a closed rectangular Core silhouette; +- avoids simple dotted ellipse/orbit graphics; +- avoids four floating glass feature cards; +- avoids a visible rectangular WebGL panel boundary; +- keeps cyan localized as intelligence/signal light rather than broad neon treatment; +- integrates the Core, signal field and stage journey into one near-black environment; +- preserves an open sculptural silhouette across the stage states; +- is materially richer and more authored than the older cube/orbit Hero engineering DNA. -The active candidate removes that panel boundary, uses transparent scene integration, reduces the cyan/reactor effect, introduces a curved smoked aperture, keeps the Core open across the full motion sequence, and materially separates the scene from the rejected closed-box direction. +This is an **owner-review candidate** targeting the brief's bespoke premium digital / AI studio standard. The monetary `$100k+` class is an art-direction target, not an objectively measurable QA fact. -This is now an **owner-review candidate**, not an owner-approved final Hero. +## 12. Production safety — confirmed -## 9. Production safety +Comparison against `agent/hero-layered-25d-static-r1` confirms this implementation branch contains isolated Hero preview/assets/docs/workflow changes only. - Production `/index.html` was not modified by this Premium Core 2.0 pass. - Production `/ru/index.html` was not modified by this Premium Core 2.0 pass. - No production merge was performed. - No production deploy was performed. -- No production PR was opened. +- No production-target PR was opened. +- Draft PR `#117` targets `agent/hero-layered-25d-static-r1`, not `main`. - Existing C-shape/recovery/history files were not deleted. - Financial Stream was not touched. -A draft owner-review PR exists only between the isolated implementation branch and the research/archive branch. It must not be merged or retargeted to production without explicit owner authorization. +Do not merge, retarget to production or deploy without explicit owner approval. -**PENDING OWNER REVIEW** +**READY FOR OWNER REVIEW — NOT PRODUCTION AUTHORIZED** From 78b1d6369ce0b069c5536ae40f8ff05d182a0bc8 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 03:20:32 -0700 Subject: [PATCH 37/69] Refine Premium Core 2.0 signature geometry and layered motion --- assets/js/hero-premium-core-2-r2.js | 637 ++++++++++++++++------------ 1 file changed, 357 insertions(+), 280 deletions(-) diff --git a/assets/js/hero-premium-core-2-r2.js b/assets/js/hero-premium-core-2-r2.js index 82313877..9722b6ca 100644 --- a/assets/js/hero-premium-core-2-r2.js +++ b/assets/js/hero-premium-core-2-r2.js @@ -10,6 +10,9 @@ const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)'); const coarsePointer = window.matchMedia('(pointer: coarse)'); + const reviewMode = new URLSearchParams(window.location.search).get('review') || ''; + root.dataset.heroCore2Review = reviewMode; + let motionReduced = reducedMotion.matches; let activeStage = motionReduced ? 3 : 0; let narrativeTimers = []; @@ -99,129 +102,170 @@ uniform float uStage; uniform float uMotion; uniform float uQuality; + uniform float uSignalMix; + uniform float uFxMix; out vec4 outColor; mat2 rot(float a){ float c=cos(a),s=sin(a); return mat2(c,-s,s,c); } float hash21(vec2 p){ p=fract(p*vec2(123.34,456.21)); p+=dot(p,p+45.32); return fract(p.x*p.y); } - - float sdRoundBox(vec3 p,vec3 b,float r){ - vec3 q=abs(p)-b+r; - return min(max(q.x,max(q.y,q.z)),0.0)+length(max(q,0.0))-r; - } - float sdEllipsoid(vec3 p,vec3 r){ - float k0=length(p/r),k1=length(p/(r*r)); - return k0*(k0-1.0)/max(k1,0.0001); - } - float sdCapsule(vec3 p,vec3 a,vec3 b,float r){ - vec3 pa=p-a,ba=b-a; - float h=clamp(dot(pa,ba)/dot(ba,ba),0.0,1.0); - return length(pa-ba*h)-r; - } + float sdRoundBox(vec3 p,vec3 b,float r){ vec3 q=abs(p)-b+r; return min(max(q.x,max(q.y,q.z)),0.0)+length(max(q,0.0))-r; } + float sdCapsule(vec3 p,vec3 a,vec3 b,float r){ vec3 pa=p-a,ba=b-a; float h=clamp(dot(pa,ba)/dot(ba,ba),0.0,1.0); return length(pa-ba*h)-r; } float sdPlane(vec3 p,vec3 n,float h){ return dot(p,n)+h; } + float sdSeg2(vec2 p,vec2 a,vec2 b){ vec2 pa=p-a,ba=b-a; float h=clamp(dot(pa,ba)/max(dot(ba,ba),.00001),0.0,1.0); return length(pa-ba*h); } - float stageYaw(){ - if(uStage<0.5)return 0.055; - if(uStage<1.5)return 0.070; - if(uStage<2.5)return 0.090; - return 0.120; - } - float stagePitch(){ - if(uStage<0.5)return 0.035; - if(uStage<1.5)return 0.040; - if(uStage<2.5)return 0.025; - return -0.010; - } + float stageYaw(){ if(uStage<0.5)return -0.045; if(uStage<1.5)return 0.015; if(uStage<2.5)return 0.075; return 0.135; } + float stagePitch(){ if(uStage<0.5)return 0.055; if(uStage<1.5)return 0.080; if(uStage<2.5)return 0.030; return -0.028; } + float stageProgress(){ return clamp(uStage/3.0,0.0,1.0); } + float detailMix(){ return smoothstep(0.70,0.96,uQuality); } vec3 objectSpace(vec3 p){ - p-=vec3(0.02,-0.015,0.0); - float dy=uMotion*(0.052*sin(uTime*0.21)+0.020*sin(uTime*0.067+1.4)); - float dx=uMotion*(0.025*sin(uTime*0.16+0.9)); - float yaw=-0.29+stageYaw()+dy+uPointer.x*0.052*uMotion; - float pitch=0.09+stagePitch()+dx-uPointer.y*0.032*uMotion; + p-=vec3(0.03,-0.015,0.0); + float detail=detailMix(); + float yaw=-0.24+stageYaw(); + yaw+=uMotion*(0.065*sin(uTime*0.115)+0.022*sin(uTime*0.041+1.7)); + yaw+=uMotion*detail*0.012*sin(uTime*0.015+0.8); + yaw+=uPointer.x*0.050*uMotion; + float pitch=0.10+stagePitch()+uMotion*(0.034*sin(uTime*0.087+0.9)+0.014*sin(uTime*0.027)); + pitch-=uPointer.y*0.030*uMotion; + float roll=uMotion*detail*(0.018*sin(uTime*0.063+2.1)); p.xz=rot(-yaw)*p.xz; p.yz=rot(-pitch)*p.yz; + p.xy=rot(-roll)*p.xy; return p; } - float innerDistanceFromObject(vec3 q){ - vec3 p=q-vec3(0.10,-0.01,0.035); - p.xy=rot(0.18+uMotion*0.028*sin(uTime*0.34))*p.xy; - p.xz=rot(-0.17-uMotion*uTime*0.012)*p.xz; - float lens=sdEllipsoid(p,vec3(0.37,0.46,0.285)); - vec3 p2=p-vec3(0.065,-0.018,0.025); - float kernel=sdEllipsoid(p2,vec3(0.205,0.305,0.175)); - return min(lens,kernel+0.030); + vec2 mapInternal(vec3 q){ + float detail=detailMix(); + vec2 res=vec2(1000.0,0.0); + + vec3 a=q-vec3(0.08,0.00,0.015); + a.xy=rot(0.16+uMotion*0.030*sin(uTime*0.23))*a.xy; + a.xz=rot(-0.18-uMotion*0.018*sin(uTime*0.17+0.6))*a.xz; + float outer=abs(sdRoundBox(a,vec3(0.315,0.410,0.220),0.135))-0.027; + outer=max(outer,-sdRoundBox(a-vec3(0.23,0.02,0.16),vec3(0.20,0.20,0.13),0.08)); + if(outer0.77){ + vec3 plane=q-vec3(0.02,0.0,-0.18); + plane.xy=rot(-0.18+uMotion*0.012*sin(uTime*0.25))*plane.xy; + float p1=abs(sdRoundBox(plane,vec3(0.29,0.39,0.018),0.035))-0.010; + if(p10.74){ + vec3 rear=q-vec3(0.08,0.02,-0.50-0.025*shellMotion*sin(uTime*.12)); + rear.xy=rot(0.09+0.012*shellMotion*sin(uTime*.09))*rear.xy; rear.xz=rot(-0.10)*rear.xz; + float rearD=sdRoundBox(rear,vec3(0.46,0.46,0.055),0.070); + rearD=max(rearD,-sdRoundBox(rear-vec3(0.15,0.00,0.03),vec3(0.31,0.30,0.05),0.055)); + if(rearD0.84){ + vec3 jaw=q-vec3(0.50,0.43,0.12+0.030*shellMotion*sin(uTime*.22+2.5)); + jaw.xy=rot(0.38+0.018*shellMotion*sin(uTime*.13))*jaw.xy; jaw.xz=rot(0.24)*jaw.xz; + float jawD=sdRoundBox(jaw,vec3(0.22,0.095,0.17),0.060); + if(jawDmaxt)break; } return clamp(res,0.0,1.0); @@ -230,188 +274,192 @@ float ambientOcclusion(vec3 p,vec3 n){ float occ=0.0,sca=1.0; for(int i=0;i<4;i++){ - float h=0.04+0.085*float(i); - float d=mapScene(p+n*h).x; - occ+=(h-d)*sca; - sca*=0.66; + float h=0.04+0.085*float(i),d=mapScene(p+n*h).x; occ+=(h-d)*sca; sca*=0.66; } return clamp(1.0-1.30*occ,0.0,1.0); } + float brandMark(vec3 p){ + vec3 q=objectSpace(p)-vec3(-0.03,0.34,0.42); + q.xy=rot(0.34)*q.xy; + vec2 uv=q.xy*3.25; + float d=10.0; + d=min(d,sdSeg2(uv,vec2(-0.32,-0.13),vec2(-0.32,0.15))); + d=min(d,sdSeg2(uv,vec2(-0.32,0.15),vec2(-0.14,0.15))); + d=min(d,sdSeg2(uv,vec2(-0.14,0.15),vec2(-0.11,0.02))); + d=min(d,sdSeg2(uv,vec2(-0.11,0.02),vec2(-0.32,0.02))); + d=min(d,sdSeg2(uv,vec2(0.00,-0.13),vec2(0.10,0.15))); + d=min(d,sdSeg2(uv,vec2(0.10,0.15),vec2(0.21,-0.13))); + d=min(d,sdSeg2(uv,vec2(0.045,-0.01),vec2(0.165,-0.01))); + d=min(d,sdSeg2(uv,vec2(0.29,-0.13),vec2(0.29,0.15))); + return 1.0-smoothstep(0.018,0.035,d); + } + vec3 materialColor(float id,vec3 p,vec3 n,vec3 rd,float glow){ - vec3 graphite=vec3(0.042,0.055,0.061); - vec3 steel=vec3(0.105,0.125,0.135); - vec3 darkSteel=vec3(0.072,0.089,0.098); - vec3 cyan=vec3(0.31,0.84,0.98); - vec3 ice=vec3(0.60,0.76,0.81); - vec3 warm=vec3(0.80,0.65,0.44); - vec3 keyPos=vec3(-2.8,3.4,4.2),rimPos=vec3(3.5,1.5,2.4); - vec3 l=normalize(keyPos-p),l2=normalize(rimPos-p),v=normalize(-rd),h=normalize(l+v); - float ndl=max(dot(n,l),0.0),ndl2=max(dot(n,l2),0.0); - float shadow=softShadow(p+n*0.009,l,0.026,6.0); - float ao=ambientOcclusion(p,n); - float facing=max(dot(n,v),0.0); - float fres=pow(1.0-facing,4.2); - float brush=0.5+0.5*sin((p.y+p.x*0.22)*76.0); + vec3 graphite=vec3(0.032,0.044,0.050),steel=vec3(0.095,0.116,0.126),darkSteel=vec3(0.058,0.073,0.082); + vec3 cyan=vec3(0.29,0.82,0.98),ice=vec3(0.63,0.76,0.81),warm=vec3(0.77,0.61,0.41); + vec3 keyPos=vec3(-2.7,3.5,4.2),rimPos=vec3(3.7,1.6,2.5),lowPos=vec3(0.0,-2.2,2.8); + vec3 l=normalize(keyPos-p),l2=normalize(rimPos-p),l3=normalize(lowPos-p),v=normalize(-rd),h=normalize(l+v),h2=normalize(l2+v); + float ndl=max(dot(n,l),0.0),ndl2=max(dot(n,l2),0.0),ndl3=max(dot(n,l3),0.0); + float shadow=softShadow(p+n*0.009,l,0.026,6.0),ao=ambientOcclusion(p,n); + float facing=max(dot(n,v),0.0),fres=pow(1.0-facing,4.1),brush=0.5+0.5*sin((p.y+p.x*0.22)*82.0); if(id<1.5){ - float spec=pow(max(dot(n,h),0.0),62.0+28.0*brush); - vec3 base=graphite*(0.44+0.90*ndl*shadow)*ao; - base+=vec3(0.30,0.34,0.36)*spec*(0.25+0.14*brush); - base+=cyan*fres*0.055+warm*ndl2*fres*0.025; + float spec=pow(max(dot(n,h),0.0),58.0+34.0*brush); + vec3 base=graphite*(0.38+0.98*ndl*shadow)*ao; + base+=vec3(0.28,0.31,0.33)*spec*(0.24+0.15*brush)+cyan*fres*0.045+warm*ndl2*fres*0.017; return base; } if(id<2.5){ - float spec=pow(max(dot(n,h),0.0),104.0); - vec3 base=steel*(0.47+0.94*ndl*shadow)*ao; - base+=ice*spec*0.38; - base+=cyan*fres*0.070+warm*ndl2*fres*0.040; + float spec=pow(max(dot(n,h),0.0),102.0),rimSpec=pow(max(dot(n,h2),0.0),68.0); + vec3 base=steel*(0.42+1.02*ndl*shadow)*ao; + base+=ice*spec*0.40+vec3(0.34,0.41,0.44)*rimSpec*0.12+cyan*fres*0.060+warm*ndl2*fres*0.026; return base; } if(id<3.5){ - float rim=pow(1.0-facing,2.6); - float spec=pow(max(dot(n,h),0.0),86.0); - vec3 smoke=vec3(0.012,0.028,0.034)*(0.48+ndl*0.18); - smoke+=cyan*(rim*0.12+glow*0.035); - smoke+=ice*spec*0.075; - return smoke; + float rim=pow(1.0-facing,2.55),spec=pow(max(dot(n,h),0.0),94.0); + return vec3(0.008,0.020,0.026)*(0.42+ndl*0.16)+cyan*(rim*0.105+glow*0.024)+ice*spec*0.060; + } + if(id<4.18){ + float rim=pow(1.0-facing,2.7),pulse=0.82+0.045*uMotion*sin(uTime*.90+p.y*4.0); + return vec3(0.012,0.052,0.065)*(0.78+0.20*ndl)*pulse+cyan*(rim*0.18+glow*0.022); } - if(id<4.5){ - float rim=pow(1.0-facing,2.85); - float phase=0.75+0.055*uMotion*sin(uTime*1.08+p.y*5.0)+uStage*0.018; - float wave=0.5+0.5*sin(p.x*10.0+p.y*13.0-p.z*7.0+uTime*0.52*uMotion); - float filament=pow(wave,9.0); - float spec=pow(max(dot(n,h),0.0),72.0); - vec3 inner=vec3(0.010,0.042,0.052)*(0.82+0.18*ndl)*phase; - inner+=cyan*(rim*0.20+filament*0.095+glow*0.030); - inner+=ice*spec*0.050; - return inner; + if(id<4.40){ + float rim=pow(1.0-facing,3.0),spec=pow(max(dot(n,h2),0.0),80.0); + return vec3(0.018,0.075,0.090)*(0.72+0.12*ndl)+cyan*(rim*0.21+spec*0.075+glow*0.030); + } + if(id<4.75){ + float wave=0.5+0.5*sin(p.x*13.0+p.y*10.0-p.z*8.0+uTime*.48*uMotion),filament=pow(wave,10.0),rim=pow(1.0-facing,2.8); + return vec3(0.015,0.085,0.105)*(0.80+0.08*ndl)+cyan*(0.055+rim*0.24+filament*0.090+glow*0.035); } if(id<5.5){ - float spec=pow(max(dot(n,h),0.0),80.0); - vec3 base=darkSteel*(0.50+0.70*ndl*shadow)*ao; - base+=ice*spec*0.22+cyan*fres*0.055; + float spec=pow(max(dot(n,h),0.0),88.0); + return darkSteel*(0.46+0.72*ndl*shadow)*ao+ice*spec*0.20+cyan*fres*0.052; + } + if(id<6.5){ + float spec=pow(max(dot(n,h),0.0),74.0),pool=exp(-2.9*(p.x*p.x+(p.z+0.05)*(p.z+0.05))); + return vec3(0.018,0.024,0.027)*(0.62+0.58*ndl3+0.16*ndl)+vec3(0.17,0.22,0.24)*spec*0.18+cyan*pool*(0.018+0.008*uStage); + } + if(id<7.5){ + float spec=pow(max(dot(n,h2),0.0),96.0),mark=brandMark(p); + vec3 base=vec3(0.052,0.067,0.075)*(0.45+0.88*ndl*shadow)*ao; + base+=ice*spec*(0.20+mark*0.18)+cyan*fres*0.040; + base*=1.0-mark*0.055; return base; } - return vec3(0.006,0.009,0.010); + return vec3(0.004,0.006,0.007); } vec2 curveDistance(vec2 p,vec2 a,vec2 b,vec2 c,vec2 d){ float md=10.0,mt=0.0; vec2 prev=a; - for(int i=1;i<=32;i++){ - float t=float(i)/32.0,s=1.0-t; + for(int i=1;i<=34;i++){ + float t=float(i)/34.0,s=1.0-t; vec2 cur=s*s*s*a+3.0*s*s*t*b+3.0*s*t*t*c+t*t*t*d; - vec2 pa=p-prev,ba=cur-prev; - float h=clamp(dot(pa,ba)/max(dot(ba,ba),0.00001),0.0,1.0); - float dd=length(pa-ba*h); - if(dd0.84){ + vec2 cell=floor((uv+1.5)*vec2(40.0,34.0)); + float rnd=hash21(cell),rnd2=hash21(cell+17.7); + vec2 fp=fract((uv+1.5)*vec2(40.0,34.0))-0.5; + float dust=(1.0-smoothstep(0.018,0.065,length(fp)))*step(0.975,rnd); + float corridor=exp(-36.0*min(min(a.x,b.x),c.x)); + float ds=dust*corridor*(0.55+0.45*sin(uTime*0.40+rnd2*6.283))*(0.010+0.012*prog); + col+=ice*ds; alpha+=ds*1.5; + } + return vec4(col,clamp(alpha,0.0,0.58)); } - vec3 aces(vec3 x){ - float a=2.51,b=0.03,c=2.43,d=0.59,e=0.14; - return clamp((x*(a*x+b))/(x*(c*x+d)+e),0.0,1.0); - } + vec3 aces(vec3 x){ float a=2.51,b=0.03,c=2.43,d=0.59,e=0.14; return clamp((x*(a*x+b))/(x*(c*x+d)+e),0.0,1.0); } void main(){ vec2 frag=gl_FragCoord.xy; vec2 p=(2.0*frag-uResolution.xy)/uResolution.y; - p.x+=0.02; - vec3 ro=vec3(0.02+uPointer.x*0.05*uMotion,0.07+uPointer.y*0.03*uMotion,4.12); - vec3 ta=vec3(0.06,-0.015,0.0); + p.x+=0.015; + vec3 ro=vec3(0.02+uPointer.x*0.045*uMotion,0.06+uPointer.y*0.028*uMotion,4.02); + vec3 ta=vec3(0.055,-0.02,0.0); vec3 ww=normalize(ta-ro),uu=normalize(cross(ww,vec3(0.0,1.0,0.0))),vv=cross(uu,ww); - vec3 rd=normalize(uu*p.x+vv*p.y+ww*2.36); - + vec3 rd=normalize(uu*p.x+vv*p.y+ww*2.38); float t=0.0,id=0.0,glow=0.0; bool hit=false; - int maxSteps=int(mix(48.0,70.0,uQuality)); - for(int i=0;i<72;i++){ + int maxSteps=int(mix(46.0,74.0,uQuality)); + for(int i=0;i<76;i++){ if(i>maxSteps)break; vec3 pos=ro+rd*t; vec2 h=mapScene(pos); - vec3 q=objectSpace(pos); - float innerD=innerDistanceFromObject(q); - glow+=exp(-11.5*abs(innerD))*0.0070*exp(-0.08*t); + vec2 inner=mapInternal(objectSpace(pos)); + glow+=exp(-12.5*abs(inner.x))*0.0068*exp(-0.075*t); if(h.x<0.0017){hit=true;id=h.y;break;} - t+=max(h.x*0.78,0.0095); - if(t>9.2)break; + t+=max(h.x*0.77,0.0092); + if(t>9.3)break; } - vec3 color=vec3(0.0); float alpha=0.0; if(hit){ vec3 pos=ro+rd*t; - if(id<5.5){ - vec3 n=calcNormal(pos); - color=materialColor(id,pos,n,rd,glow); - float fog=1.0-exp(-0.03*t*t); - color*=1.0-fog*0.18; - alpha=1.0; + if(id<7.6){ + vec3 n=calcNormal(pos); color=materialColor(id,pos,n,rd,glow); + float fog=1.0-exp(-0.028*t*t); color*=1.0-fog*0.16; alpha=1.0; }else{ - float shadow=exp(-1.45*(pos.x*pos.x+pos.z*pos.z)); - float light=exp(-3.5*(pos.x*pos.x+pos.z*pos.z)); - color=vec3(0.002,0.005,0.006)+vec3(0.18,0.54,0.62)*light*0.007; - alpha=shadow*0.26; + float shadow=exp(-1.50*(pos.x*pos.x+(pos.z+0.04)*(pos.z+0.04))); + float light=exp(-3.4*(pos.x*pos.x+(pos.z+0.02)*(pos.z+0.02))); + color=vec3(0.0015,0.003,0.004)+vec3(0.16,0.46,0.54)*light*0.006; + alpha=shadow*0.22; } } - - float halo=exp(-2.25*dot(p-vec2(0.05,-0.02),p-vec2(0.05,-0.02))); - color+=vec3(0.035,0.11,0.13)*halo*(0.055+min(glow,0.28)*0.12); - alpha=max(alpha,halo*0.042); - color+=vec3(0.18,0.62,0.76)*min(glow,0.40)*(0.13+0.04*uStage); - alpha=max(alpha,min(glow,0.40)*0.15); - - vec4 signals=signalField(p*vec2(0.92,0.92),hit&&id<5.5,t); - color+=signals.rgb; alpha=max(alpha,signals.a); - float grain=hash21(frag+floor(uTime*1.5*uMotion)); - color+=(grain-0.5)*0.0020*alpha; - color=aces(color*1.32); color=pow(color,vec3(0.95)); + float halo=exp(-2.05*dot(p-vec2(0.04,-0.01),p-vec2(0.04,-0.01))); + float lowerHalo=exp(-9.0*((p.x-0.04)*(p.x-0.04)+(p.y+0.47)*(p.y+0.47))); + color+=vec3(0.028,0.105,0.132)*halo*(0.060+min(glow,0.32)*0.13)*uFxMix; + color+=vec3(0.025,0.115,0.145)*lowerHalo*(0.035+0.010*uStage)*uFxMix; + alpha=max(alpha,(halo*0.045+lowerHalo*0.055)*uFxMix); + color+=vec3(0.16,0.59,0.75)*min(glow,0.42)*(0.14+0.035*uStage); + alpha=max(alpha,min(glow,0.42)*0.15); + vec4 signals=signalField(p*vec2(0.93,0.93),hit&&id<7.6,t); + color+=signals.rgb*uSignalMix; alpha=max(alpha,signals.a*uSignalMix); + float grain=hash21(frag+floor(uTime*1.4*uMotion)); + color+=(grain-0.5)*0.0018*alpha; + color=aces(color*1.36); color=pow(color,vec3(0.95)); outColor=vec4(color,clamp(alpha,0.0,1.0)); } `; - const compile=(type,source)=>{ - const shader=gl.createShader(type); - gl.shaderSource(shader,source); + const compile = (type, source) => { + const shader = gl.createShader(type); + gl.shaderSource(shader, source); gl.compileShader(shader); - if(!gl.getShaderParameter(shader,gl.COMPILE_STATUS)){ - const message=gl.getShaderInfoLog(shader)||'Unknown shader compile failure'; + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + const message = gl.getShaderInfoLog(shader) || 'Unknown shader compile failure'; gl.deleteShader(shader); throw new Error(message); } @@ -419,88 +467,117 @@ }; let program; - try{ - const vertex=compile(gl.VERTEX_SHADER,vertexSource); - const fragment=compile(gl.FRAGMENT_SHADER,fragmentSource); - program=gl.createProgram(); - gl.attachShader(program,vertex); gl.attachShader(program,fragment); gl.linkProgram(program); - gl.deleteShader(vertex); gl.deleteShader(fragment); - if(!gl.getProgramParameter(program,gl.LINK_STATUS))throw new Error(gl.getProgramInfoLog(program)||'Hero Core 2.0 program link failed'); - }catch(error){ - console.error('[Hero Core 2.0 material refinement]',error); + try { + const vertex = compile(gl.VERTEX_SHADER, vertexSource); + const fragment = compile(gl.FRAGMENT_SHADER, fragmentSource); + program = gl.createProgram(); + gl.attachShader(program, vertex); + gl.attachShader(program, fragment); + gl.linkProgram(program); + gl.deleteShader(vertex); + gl.deleteShader(fragment); + if (!gl.getProgramParameter(program, gl.LINK_STATUS)) throw new Error(gl.getProgramInfoLog(program) || 'Hero Core 2.0 R2 program link failed'); + } catch (error) { + console.error('[Hero Core 2.0 R2 art direction]', error); root.classList.add('hero-core2--fallback'); return; } gl.useProgram(program); - const uniforms={ - resolution:gl.getUniformLocation(program,'uResolution'), - pointer:gl.getUniformLocation(program,'uPointer'), - time:gl.getUniformLocation(program,'uTime'), - stage:gl.getUniformLocation(program,'uStage'), - motion:gl.getUniformLocation(program,'uMotion'), - quality:gl.getUniformLocation(program,'uQuality') + const uniforms = { + resolution: gl.getUniformLocation(program, 'uResolution'), + pointer: gl.getUniformLocation(program, 'uPointer'), + time: gl.getUniformLocation(program, 'uTime'), + stage: gl.getUniformLocation(program, 'uStage'), + motion: gl.getUniformLocation(program, 'uMotion'), + quality: gl.getUniformLocation(program, 'uQuality'), + signalMix: gl.getUniformLocation(program, 'uSignalMix'), + fxMix: gl.getUniformLocation(program, 'uFxMix') }; - let pointer={x:0,y:0},pointerTarget={x:0,y:0}; - let visible=true,renderScale=1,quality=1,firstFrame=true; - let frameSamples=[],lastFrame=performance.now(); - const mobileViewport=()=>window.innerWidth<=700; - - const resize=()=>{ - const rect=visual.getBoundingClientRect(); - const cssWidth=Math.max(1,Math.round(rect.width)),cssHeight=Math.max(1,Math.round(rect.height)); - const dprCap=mobileViewport()?1.10:1.48; - const dpr=Math.min(window.devicePixelRatio||1,dprCap)*renderScale; - const width=Math.max(2,Math.round(cssWidth*dpr)),height=Math.max(2,Math.round(cssHeight*dpr)); - if(canvas.width!==width||canvas.height!==height){ canvas.width=width; canvas.height=height; gl.viewport(0,0,width,height); } + let pointer = { x: 0, y: 0 }; + let pointerTarget = { x: 0, y: 0 }; + let visible = true; + let renderScale = 1; + let quality = 1; + let firstFrame = true; + let frameSamples = []; + let lastFrame = performance.now(); + const mobileViewport = () => window.innerWidth <= 700; + + const resize = () => { + const rect = visual.getBoundingClientRect(); + const cssWidth = Math.max(1, Math.round(rect.width)); + const cssHeight = Math.max(1, Math.round(rect.height)); + const dprCap = mobileViewport() ? 1.08 : 1.48; + const dpr = Math.min(window.devicePixelRatio || 1, dprCap) * renderScale; + const width = Math.max(2, Math.round(cssWidth * dpr)); + const height = Math.max(2, Math.round(cssHeight * dpr)); + if (canvas.width !== width || canvas.height !== height) { + canvas.width = width; + canvas.height = height; + gl.viewport(0, 0, width, height); + } }; - const resizeObserver=new ResizeObserver(resize); + const resizeObserver = new ResizeObserver(resize); resizeObserver.observe(visual); - window.addEventListener('resize',resize,{passive:true}); + window.addEventListener('resize', resize, { passive: true }); resize(); - const updatePointer=(event)=>{ - if(motionReduced||coarsePointer.matches)return; - const rect=visual.getBoundingClientRect(); - const x=(event.clientX-rect.left)/Math.max(rect.width,1),y=(event.clientY-rect.top)/Math.max(rect.height,1); - pointerTarget.x=(Math.max(0,Math.min(1,x))-0.5)*2; - pointerTarget.y=(0.5-Math.max(0,Math.min(1,y)))*2; + const updatePointer = (event) => { + if (motionReduced || coarsePointer.matches) return; + const rect = visual.getBoundingClientRect(); + const x = (event.clientX - rect.left) / Math.max(rect.width, 1); + const y = (event.clientY - rect.top) / Math.max(rect.height, 1); + pointerTarget.x = (Math.max(0, Math.min(1, x)) - 0.5) * 2; + pointerTarget.y = (0.5 - Math.max(0, Math.min(1, y))) * 2; }; - visual.addEventListener('pointermove',updatePointer,{passive:true}); - visual.addEventListener('pointerleave',()=>{pointerTarget.x=0;pointerTarget.y=0;}); + visual.addEventListener('pointermove', updatePointer, { passive: true }); + visual.addEventListener('pointerleave', () => { pointerTarget.x = 0; pointerTarget.y = 0; }); - const visibilityObserver=new IntersectionObserver((entries)=>{ visible=entries.some((entry)=>entry.isIntersecting); },{threshold:0.02}); + const visibilityObserver = new IntersectionObserver((entries) => { visible = entries.some((entry) => entry.isIntersecting); }, { threshold: 0.02 }); visibilityObserver.observe(visual); - const adaptPerformance=(delta)=>{ - if(firstFrame||motionReduced)return; + const adaptPerformance = (delta) => { + if (firstFrame || motionReduced) return; frameSamples.push(delta); - if(frameSamples.length<70)return; - const avg=frameSamples.reduce((s,v)=>s+v,0)/frameSamples.length; - frameSamples=[]; - if(avg>26&&renderScale>0.72){ renderScale=Math.max(0.72,renderScale*0.86); quality=Math.max(0.60,quality-0.16); resize(); } + if (frameSamples.length < 68) return; + const avg = frameSamples.reduce((sum, value) => sum + value, 0) / frameSamples.length; + frameSamples = []; + if (avg > 27 && renderScale > 0.70) { + renderScale = Math.max(0.70, renderScale * 0.85); + quality = Math.max(0.58, quality - 0.15); + resize(); + } }; - const start=performance.now(); - const render=(now)=>{ + const start = performance.now(); + const render = (now) => { requestAnimationFrame(render); - if(!visible||document.hidden)return; - const delta=now-lastFrame; lastFrame=now; adaptPerformance(delta); - pointer.x+=(pointerTarget.x-pointer.x)*0.034; - pointer.y+=(pointerTarget.y-pointer.y)*0.034; - const elapsed=motionReduced?7.1:(now-start)*0.001; - gl.clearColor(0,0,0,0); gl.clear(gl.COLOR_BUFFER_BIT); + if (!visible || document.hidden) return; + const delta = now - lastFrame; + lastFrame = now; + adaptPerformance(delta); + pointer.x += (pointerTarget.x - pointer.x) * 0.032; + pointer.y += (pointerTarget.y - pointer.y) * 0.032; + const elapsed = motionReduced ? 7.4 : (now - start) * 0.001; + const mobileQuality = mobileViewport() ? Math.min(quality, 0.68) : quality; + const coreOnly = reviewMode === 'core'; + const materialsOnly = reviewMode === 'materials'; + gl.clearColor(0, 0, 0, 0); + gl.clear(gl.COLOR_BUFFER_BIT); gl.useProgram(program); - gl.uniform2f(uniforms.resolution,canvas.width,canvas.height); - gl.uniform2f(uniforms.pointer,pointer.x,pointer.y); - gl.uniform1f(uniforms.time,elapsed); - gl.uniform1f(uniforms.stage,activeStage); - gl.uniform1f(uniforms.motion,motionReduced?0:1); - gl.uniform1f(uniforms.quality,mobileViewport()?Math.min(quality,0.76):quality); - gl.drawArrays(gl.TRIANGLES,0,3); - if(firstFrame){ firstFrame=false; root.classList.add('hero-core2--ready'); } + gl.uniform2f(uniforms.resolution, canvas.width, canvas.height); + gl.uniform2f(uniforms.pointer, pointer.x, pointer.y); + gl.uniform1f(uniforms.time, elapsed); + gl.uniform1f(uniforms.stage, activeStage); + gl.uniform1f(uniforms.motion, motionReduced ? 0 : 1); + gl.uniform1f(uniforms.quality, mobileQuality); + gl.uniform1f(uniforms.signalMix, coreOnly || materialsOnly ? 0 : 1); + gl.uniform1f(uniforms.fxMix, coreOnly ? 0.28 : materialsOnly ? 0.55 : 1); + gl.drawArrays(gl.TRIANGLES, 0, 3); + if (firstFrame) { firstFrame = false; root.classList.add('hero-core2--ready'); } }; requestAnimationFrame(render); -})(); +})(); \ No newline at end of file From a6d41436e75114272f6b54875a8995c7df31e050 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 03:21:36 -0700 Subject: [PATCH 38/69] Upgrade Premium Core 2.0 stage plates grounding and responsive art direction --- assets/css/hero-premium-core-2-r2.css | 359 ++++++++++++++++++++------ 1 file changed, 279 insertions(+), 80 deletions(-) diff --git a/assets/css/hero-premium-core-2-r2.css b/assets/css/hero-premium-core-2-r2.css index b88602a1..c5242c54 100644 --- a/assets/css/hero-premium-core-2-r2.css +++ b/assets/css/hero-premium-core-2-r2.css @@ -7,25 +7,24 @@ } .hero-core2__shell { - grid-template-columns: minmax(0, .9fr) minmax(620px, 1.1fr); - gap: clamp(22px, 3vw, 54px); + grid-template-columns: minmax(0, .88fr) minmax(640px, 1.12fr); + gap: clamp(18px, 2.6vw, 48px); } .hero-core2__visual { - height: min(78vh, 775px); - min-height: 620px; - margin-right: clamp(-54px, -3vw, -12px); + height: min(80vh, 790px); + min-height: 635px; + margin-right: clamp(-62px, -3.5vw, -14px); + transform-style: preserve-3d; } .hero-core2__canvas { - filter: saturate(.90) contrast(1.075); + filter: saturate(.93) contrast(1.09); } -/* Loading/fallback state follows the same open sculptural language as the live Core. - It deliberately avoids the rejected closed-box silhouette. */ .hero-core2__fallback { - transform: translate(-48%, -50%) rotate(-7deg); - opacity: .70; + transform: translate(-48%, -50%) rotate(-6deg); + opacity: .68; } .hero-core2__fallback::before, .hero-core2__fallback::after, @@ -34,68 +33,244 @@ box-shadow: inset 0 1px rgba(255,255,255,.10), 0 26px 70px rgba(0,0,0,.38); } .hero-core2__fallback::before { - inset: 11% 19% 65% 8%; - border-radius: 15px 26px 12px 19px; - clip-path: polygon(0 16%, 74% 0, 100% 34%, 88% 100%, 19% 82%); + inset: 8% 18% 67% 7%; + border-radius: 16px 28px 12px 20px; + clip-path: polygon(0 20%, 71% 0, 100% 31%, 87% 100%, 18% 80%); background: linear-gradient(142deg, rgba(76,87,92,.78), rgba(13,17,19,.92)); - transform: rotate(-7deg); + transform: rotate(-8deg); } .hero-core2__fallback::after { - inset: 28% 9% 20% 70%; - border-radius: 18px 12px 24px 13px; - clip-path: polygon(22% 0, 100% 16%, 86% 84%, 36% 100%, 0 72%, 10% 18%); + inset: 25% 8% 17% 72%; + border-radius: 18px 12px 26px 13px; + clip-path: polygon(18% 0, 100% 14%, 88% 85%, 34% 100%, 0 71%, 10% 17%); background: linear-gradient(155deg, rgba(48,57,61,.84), rgba(9,12,14,.95)); - transform: rotate(8deg); + transform: rotate(9deg); filter: none; } .hero-core2__fallback span { - inset: 29% 31% 23% 31%; - border: 1px solid rgba(103,225,250,.12); - border-radius: 48% 52% 45% 55% / 55% 47% 53% 45%; - clip-path: none; - background: radial-gradient(circle at 45% 48%, rgba(95,225,250,.46), rgba(8,42,50,.58) 34%, rgba(5,13,16,.90) 72%); - box-shadow: 0 0 34px rgba(75,211,239,.13), inset 0 0 28px rgba(83,220,246,.08); - transform: rotate(13deg); + inset: 28% 32% 22% 32%; + border: 1px solid rgba(103,225,250,.10); + border-radius: 23% 34% 27% 31%; + clip-path: polygon(12% 4%, 83% 0, 100% 24%, 89% 86%, 63% 100%, 8% 89%, 0 43%); + background: + linear-gradient(145deg, rgba(20,62,72,.42), rgba(5,16,20,.86)), + radial-gradient(circle at 45% 48%, rgba(95,225,250,.38), rgba(8,42,50,.46) 34%, rgba(5,13,16,.90) 72%); + box-shadow: 0 0 36px rgba(75,211,239,.12), inset 0 0 28px rgba(83,220,246,.08); + transform: rotate(11deg); } .hero-core2__visual::before { - inset: 5% 0 1% 1%; + inset: 2% -1% 0 -1%; + border-radius: 44%; background: - radial-gradient(circle at 50% 48%, rgba(91, 219, 246, .055), transparent 24%), - radial-gradient(circle at 61% 52%, rgba(255, 226, 184, .016), transparent 18%); - filter: blur(34px); + radial-gradient(ellipse at 51% 49%, rgba(78, 210, 239, .082), transparent 24%), + radial-gradient(ellipse at 56% 56%, rgba(67, 143, 159, .036), transparent 37%), + radial-gradient(circle at 67% 43%, rgba(255, 226, 184, .014), transparent 18%); + filter: blur(38px); } .hero-core2__visual::after { content: ""; position: absolute; z-index: 1; - left: 24%; - right: 8%; - bottom: 8.5%; - height: 15%; + left: 20%; + right: 5%; + bottom: 7.4%; + height: 17%; pointer-events: none; - background: radial-gradient(ellipse at center, rgba(0, 0, 0, .58) 0 18%, rgba(18, 75, 88, .10) 34%, transparent 72%); - filter: blur(18px); - opacity: .78; + border-radius: 50%; + background: + radial-gradient(ellipse at 50% 48%, rgba(0,0,0,.68) 0 20%, rgba(11,42,49,.22) 37%, rgba(44,145,168,.055) 51%, transparent 73%); + filter: blur(17px); + opacity: .86; +} + +html[data-hero-core2-review="core"] .hero-core2__stage-list, +html[data-hero-core2-review="materials"] .hero-core2__stage-list { display: none; } +html[data-hero-core2-review="core"] .hero-core2__visual::before { opacity: .25; } +html[data-hero-core2-review="core"] .hero-core2__visual::after { opacity: .52; } +html[data-hero-core2-review="materials"] .hero-core2__visual::before { opacity: .62; } + +.hero-core2__stage-list { z-index: 9; } +.hero-core2__stage:nth-child(1) { left: 0; top: 13%; } +.hero-core2__stage:nth-child(2) { left: 4%; bottom: 12%; } +.hero-core2__stage:nth-child(3) { right: 0; top: 22%; } +.hero-core2__stage:nth-child(4) { right: 1%; bottom: 11%; } + +.hero-core2__stage-button { + --plate-edge: rgba(188, 214, 221, .16); + --plate-fill: rgba(9, 14, 17, .47); + width: clamp(138px, 10.8vw, 172px); + min-height: 70px; + grid-template-columns: 31px 1fr; + grid-template-areas: + "num label" + "num detail" + "line line"; + column-gap: 10px; + row-gap: 4px; + padding: 12px 13px 10px; + border: 1px solid var(--plate-edge); + border-radius: 4px 15px 4px 11px; + color: rgba(224,235,238,.67); + background: + linear-gradient(145deg, rgba(255,255,255,.036), rgba(255,255,255,.006) 43%), + linear-gradient(105deg, var(--plate-fill), rgba(5,9,11,.26)); + box-shadow: + inset 0 1px rgba(255,255,255,.045), + inset 16px 0 34px rgba(112,210,231,.012), + 0 16px 42px rgba(0,0,0,.18); + -webkit-backdrop-filter: blur(12px) saturate(.85); + backdrop-filter: blur(12px) saturate(.85); + clip-path: polygon(0 0, calc(100% - 13px) 0, 100% 13px, 100% 100%, 8px 100%, 0 calc(100% - 8px)); + transition: + color .45s ease, + transform .55s cubic-bezier(.2,.8,.2,1), + border-color .45s ease, + background .45s ease, + box-shadow .55s ease, + opacity .45s ease; + opacity: .74; +} + +.hero-core2__stage-button::before { + content: ""; + position: absolute; + left: -5px; + top: 50%; + width: 9px; + height: 9px; + border-radius: 50%; + border: 1px solid rgba(188,219,226,.22); + background: #091014; + box-shadow: 0 0 0 4px rgba(7,12,14,.50); + transform: translateY(-50%); + transition: border-color .45s ease, box-shadow .45s ease, background .45s ease; +} + +.hero-core2__stage-button::after { + grid-area: line; + width: 100%; + height: 1px; + margin-top: 4px; + transform: scaleX(.32); + opacity: .72; + background: linear-gradient(90deg, rgba(194,218,224,.28), rgba(114,230,255,0)); +} + +.hero-core2__stage-num { + grid-area: num; + align-self: start; + padding-top: 1px; + color: rgba(174,198,204,.42); + font-size: 18px; + line-height: .92; + font-weight: 590; + letter-spacing: -.03em; +} + +.hero-core2__stage-label { + grid-area: label; + align-self: end; + font-size: 10.5px; + line-height: 1.05; + font-weight: 760; + letter-spacing: .14em; } -.hero-core2__stage-button::after { width: 62px; opacity: .82; } -.hero-core2__stage:nth-child(1) { left: 3%; top: 15%; } -.hero-core2__stage:nth-child(2) { left: 8%; bottom: 16%; } -.hero-core2__stage:nth-child(3) { right: 2%; top: 25%; } -.hero-core2__stage:nth-child(4) { right: 4%; bottom: 14%; } +.hero-core2__stage-detail { + grid-area: detail; + display: block; + min-height: 12px; + color: rgba(204,221,225,.32); + font-size: 8.5px; + line-height: 1.25; + font-weight: 500; + letter-spacing: .055em; + text-transform: uppercase; + transition: color .45s ease, opacity .45s ease, transform .45s ease; + opacity: .64; +} + +.hero-core2__stage:nth-child(3) .hero-core2__stage-button, +.hero-core2__stage:nth-child(4) .hero-core2__stage-button { + grid-template-columns: 1fr 31px; + grid-template-areas: + "label num" + "detail num" + "line line"; + text-align: right; + border-radius: 15px 4px 11px 4px; + clip-path: polygon(13px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 13px); +} +.hero-core2__stage:nth-child(3) .hero-core2__stage-button::before, +.hero-core2__stage:nth-child(4) .hero-core2__stage-button::before { + left: auto; + right: -5px; +} +.hero-core2__stage:nth-child(3) .hero-core2__stage-button::after, +.hero-core2__stage:nth-child(4) .hero-core2__stage-button::after { + transform-origin: right center; + background: linear-gradient(270deg, rgba(194,218,224,.28), rgba(114,230,255,0)); +} + +.hero-core2__stage.is-active .hero-core2__stage-button, +.hero-core2__stage-button:hover, +.hero-core2__stage-button:focus-visible { + --plate-edge: rgba(118, 221, 244, .40); + --plate-fill: rgba(10, 25, 30, .63); + color: rgba(244,251,252,.96); + transform: translate3d(6px,-3px,14px) scale(1.035); + opacity: 1; + box-shadow: + inset 0 1px rgba(255,255,255,.075), + inset 18px 0 38px rgba(91,219,246,.028), + 0 18px 48px rgba(0,0,0,.30), + 0 0 28px rgba(89,218,244,.055); +} +.hero-core2__stage:nth-child(3).is-active .hero-core2__stage-button, +.hero-core2__stage:nth-child(4).is-active .hero-core2__stage-button, +.hero-core2__stage:nth-child(3) .hero-core2__stage-button:hover, +.hero-core2__stage:nth-child(4) .hero-core2__stage-button:hover, +.hero-core2__stage:nth-child(3) .hero-core2__stage-button:focus-visible, +.hero-core2__stage:nth-child(4) .hero-core2__stage-button:focus-visible { + transform: translate3d(-6px,-3px,14px) scale(1.035); +} +.hero-core2__stage.is-active .hero-core2__stage-button::before, +.hero-core2__stage-button:hover::before, +.hero-core2__stage-button:focus-visible::before { + border-color: rgba(120,226,249,.78); + background: rgba(80,206,235,.40); + box-shadow: 0 0 0 4px rgba(7,12,14,.50), 0 0 18px rgba(92,222,248,.25); +} +.hero-core2__stage.is-active .hero-core2__stage-button::after, +.hero-core2__stage-button:hover::after, +.hero-core2__stage-button:focus-visible::after { + transform: scaleX(1); + background: linear-gradient(90deg, rgba(114,230,255,.80), rgba(114,230,255,.04)); + box-shadow: 0 0 12px rgba(114,230,255,.17); +} +.hero-core2__stage:nth-child(3).is-active .hero-core2__stage-button::after, +.hero-core2__stage:nth-child(4).is-active .hero-core2__stage-button::after, +.hero-core2__stage:nth-child(3) .hero-core2__stage-button:hover::after, +.hero-core2__stage:nth-child(4) .hero-core2__stage-button:hover::after { + background: linear-gradient(270deg, rgba(114,230,255,.80), rgba(114,230,255,.04)); +} +.hero-core2__stage.is-active .hero-core2__stage-num { color: rgba(116,225,249,.90); } +.hero-core2__stage.is-active .hero-core2__stage-detail { color: rgba(205,232,238,.58); opacity: 1; transform: translateY(-1px); } +.hero-core2__stage-button:focus-visible { outline: 1px solid rgba(114,230,255,.46); outline-offset: 5px; } @media (max-width: 1220px) { - .hero-core2__shell { grid-template-columns: minmax(0, .94fr) minmax(510px, 1.06fr); } + .hero-core2__shell { grid-template-columns: minmax(0, .94fr) minmax(520px, 1.06fr); } .hero-core2__title { max-width: 13ch; font-size: clamp(50px, 4.8vw, 67px); } - .hero-core2__visual { min-height: 570px; } + .hero-core2__visual { min-height: 580px; } + .hero-core2__stage-button { width: 142px; } } @media (max-width: 980px) { .hero-core2__shell { grid-template-columns: 1fr; } .hero-core2__title { max-width: 14ch; font-size: clamp(47px, 7.7vw, 67px); } - .hero-core2__visual { width: min(100%, 880px); min-height: 510px; } + .hero-core2__visual { width: min(100%, 890px); min-height: 520px; } } @media (max-width: 700px) { @@ -105,30 +280,54 @@ .hero-core2__lead { margin-top: 16px; font-size: 14px; line-height: 1.47; } .hero-core2__actions { margin-top: 18px; } .hero-core2__accountability { margin-top: 13px; } - .hero-core2__visual { - height: 390px; - min-height: 390px; - margin-top: -8px; + .hero-core2__visual { height: 390px; min-height: 390px; margin-top: -8px; } + .hero-core2__visual::after { left: 12%; right: 8%; bottom: 5%; height: 13%; opacity: .62; } + + .hero-core2__stage-list { + inset: auto 3px 4px 3px; + display: grid; + grid-template-columns: repeat(4,minmax(0,1fr)); + gap: 4px; + } + .hero-core2__stage { position: static; min-width: 0; } + .hero-core2__stage-button, + .hero-core2__stage:nth-child(3) .hero-core2__stage-button, + .hero-core2__stage:nth-child(4) .hero-core2__stage-button { + width: 100%; + min-height: 45px; + display: grid; + grid-template-columns: 1fr; + grid-template-areas: "num" "label" "line"; + gap: 3px; + justify-items: center; + padding: 6px 3px 4px; + border-radius: 4px 8px 4px 7px; + clip-path: polygon(0 0,calc(100% - 7px) 0,100% 7px,100% 100%,0 100%); + text-align: center; + background: linear-gradient(180deg,rgba(12,20,23,.47),rgba(4,8,10,.28)); } - .hero-core2__visual::after { - left: 14%; - right: 10%; - bottom: 6%; - height: 13%; - opacity: .62; + .hero-core2__stage-button::before { display: none; } + .hero-core2__stage-button::after, + .hero-core2__stage:nth-child(3) .hero-core2__stage-button::after, + .hero-core2__stage:nth-child(4) .hero-core2__stage-button::after { + width: 80%; max-width: 52px; margin-top: 0; transform-origin: center; background: linear-gradient(90deg,transparent,rgba(190,218,225,.22),transparent); + } + .hero-core2__stage-num { font-size: 8px; padding: 0; } + .hero-core2__stage-label { font-size: 7.7px; letter-spacing: .075em; } + .hero-core2__stage-detail { display: none; } + .hero-core2__stage.is-active .hero-core2__stage-button, + .hero-core2__stage:nth-child(3).is-active .hero-core2__stage-button, + .hero-core2__stage:nth-child(4).is-active .hero-core2__stage-button, + .hero-core2__stage-button:hover, + .hero-core2__stage-button:focus-visible { + transform: translateY(-3px) scale(1.02); } } -/* 390-class mobile browsers may expose a ~400–430px layout viewport in headless/device emulation. - Keep the complete Core + 01–04 journey inside the first physical capture in both EN and RU. */ @media (max-width: 430px) { - .hero-core2__visual { - height: 250px; - min-height: 250px; - margin-top: -10px; - } - .hero-core2__stage-list { inset: 0; } - .hero-core2__stage-button { padding-top: 5px; padding-bottom: 2px; } + .hero-core2__visual { height: 252px; min-height: 252px; margin-top: -10px; } + .hero-core2__stage-list { inset: auto 0 0 0; } + .hero-core2__stage-button { min-height: 41px; padding-top: 4px; padding-bottom: 3px; } } @media (max-width: 390px) { @@ -138,11 +337,7 @@ } @media (max-width: 340px) { - .hero-core2__shell { - padding-top: calc(var(--core2-header) + 12px); - padding-left: 14px; - padding-right: 14px; - } + .hero-core2__shell { padding-top: calc(var(--core2-header) + 12px); padding-left: 14px; padding-right: 14px; } .hero-core2__eyebrow { margin-bottom: 8px; font-size: 9px; } .hero-core2__title { max-width: 13.8ch; font-size: 35px; line-height: .97; } .hero-core2__lead { margin-top: 11px; font-size: 12.4px; line-height: 1.40; } @@ -152,19 +347,19 @@ .hero-core2__microcopy { width: 172px; font-size: 9.2px; line-height: 1.35; } .hero-core2__button--secondary { align-self: start; } .hero-core2__accountability { margin-top: 8px; font-size: 7.7px; line-height: 1.35; } - .hero-core2__visual { height: 190px; min-height: 190px; margin-top: -6px; } - .hero-core2__stage-button { padding-top: 4px; padding-bottom: 2px; } - .hero-core2__stage-label { font-size: 6.8px; letter-spacing: .055em; } - .hero-core2__stage-num { font-size: 7px; } - .hero-core2__stage-button::after { max-width: 46px; } + .hero-core2__visual { height: 194px; min-height: 194px; margin-top: -6px; } + .hero-core2__stage-button { min-height: 36px; padding-top: 3px; padding-bottom: 2px; } + .hero-core2__stage-label { font-size: 6.7px; letter-spacing: .05em; } + .hero-core2__stage-num { font-size: 6.8px; } + .hero-core2__stage-button::after { max-width: 44px; } } @media (max-height: 500px) and (min-width: 701px) { .hero-core2__shell { - grid-template-columns: minmax(0, 1fr) minmax(390px, .92fr); + grid-template-columns: minmax(0, 1fr) minmax(390px, .94fr); padding-top: calc(var(--core2-header) + 6px); padding-bottom: 6px; - gap: 10px; + gap: 8px; } .hero-core2__copy { max-width: 470px; } .hero-core2__eyebrow { margin-bottom: 6px; font-size: 9px; } @@ -175,9 +370,13 @@ .hero-core2__button { min-height: 36px; padding: 0 14px; font-size: 9.4px; } .hero-core2__microcopy { width: 225px; font-size: 8.6px; line-height: 1.25; } .hero-core2__accountability { margin-top: 6px; font-size: 7.5px; line-height: 1.25; } - .hero-core2__visual { height: 66vh; min-height: 250px; margin-right: -12px; } - .hero-core2__stage:nth-child(1) { top: 11%; } - .hero-core2__stage:nth-child(2) { bottom: 8%; } - .hero-core2__stage:nth-child(3) { top: 19%; } - .hero-core2__stage:nth-child(4) { bottom: 7%; } + .hero-core2__visual { height: 67vh; min-height: 252px; margin-right: -12px; } + .hero-core2__stage-button { width: 116px; min-height: 52px; padding: 8px 9px 6px; } + .hero-core2__stage-num { font-size: 14px; } + .hero-core2__stage-label { font-size: 8.2px; } + .hero-core2__stage-detail { font-size: 6.8px; } + .hero-core2__stage:nth-child(1) { top: 7%; } + .hero-core2__stage:nth-child(2) { bottom: 5%; } + .hero-core2__stage:nth-child(3) { top: 14%; } + .hero-core2__stage:nth-child(4) { bottom: 4%; } } \ No newline at end of file From a5f5376158c426a3efd2af01c7c530dadecb4219 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 03:21:58 -0700 Subject: [PATCH 39/69] Refine EN Premium Core 2.0 stage plates without changing locked Hero copy --- hero-premium-core-2-preview/index.html | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hero-premium-core-2-preview/index.html b/hero-premium-core-2-preview/index.html index 0a22d04a..6a4bcef9 100644 --- a/hero-premium-core-2-preview/index.html +++ b/hero-premium-core-2-preview/index.html @@ -13,7 +13,7 @@ - + Skip to main content @@ -52,22 +52,22 @@

From first impression to res
@@ -77,6 +77,6 @@

From first impression to res - + - + \ No newline at end of file From a011b94f150a5feb1244a77b926801d1e3ec6560 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 03:22:19 -0700 Subject: [PATCH 40/69] Refine RU Premium Core 2.0 stage plates without changing locked Hero copy --- ru/hero-premium-core-2-preview/index.html | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ru/hero-premium-core-2-preview/index.html b/ru/hero-premium-core-2-preview/index.html index ee3f35ae..1894713b 100644 --- a/ru/hero-premium-core-2-preview/index.html +++ b/ru/hero-premium-core-2-preview/index.html @@ -13,7 +13,7 @@ - + Перейти к содержимому @@ -52,22 +52,22 @@

От первого впеч
@@ -77,6 +77,6 @@

От первого впеч - + - + \ No newline at end of file From 1d45473eaa41071f91d19dfad02fc62b203d18f2 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 03:23:02 -0700 Subject: [PATCH 41/69] Update Premium Core 2.0 owner-review guards for R2 architecture --- .github/workflows/hero-premium-core-2-owner-review.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/hero-premium-core-2-owner-review.yml b/.github/workflows/hero-premium-core-2-owner-review.yml index 9f0317d1..1ffee572 100644 --- a/.github/workflows/hero-premium-core-2-owner-review.yml +++ b/.github/workflows/hero-premium-core-2-owner-review.yml @@ -133,8 +133,13 @@ jobs: grep -q 'sdRoundBox' assets/js/hero-premium-core-2-r2.js grep -q 'sdCapsule' assets/js/hero-premium-core-2-r2.js grep -q 'curveDistance' assets/js/hero-premium-core-2-r2.js - grep -q 'innerDistanceFromObject' assets/js/hero-premium-core-2-r2.js + grep -q 'mapInternal' assets/js/hero-premium-core-2-r2.js + grep -q 'brandMark' assets/js/hero-premium-core-2-r2.js + grep -q 'uSignalMix' assets/js/hero-premium-core-2-r2.js + grep -q 'platformP' assets/js/hero-premium-core-2-r2.js grep -q 'requestAnimationFrame' assets/js/hero-premium-core-2-r2.js + grep -q 'hero-core2__stage-detail' hero-premium-core-2-preview/index.html + grep -q 'hero-core2__stage-detail' ru/hero-premium-core-2-preview/index.html grep -q "hero-premium-core-2-r2.js" hero-premium-core-2-preview/index.html grep -q "hero-premium-core-2-r2.js" ru/hero-premium-core-2-preview/index.html if grep -Eq 'THREE\.BoxGeometry|new THREE\.BoxGeometry|stroke-dasharray: *4, *12' assets/js/hero-premium-core-2-r2.js assets/css/hero-premium-core-2-r2.css; then @@ -155,4 +160,4 @@ jobs: shell: bash run: | cat /tmp/core2-http.log || true - if test -f premium-core-2-owner-review/diagnostics.json; then cat premium-core-2-owner-review/diagnostics.json; fi + if test -f premium-core-2-owner-review/diagnostics.json; then cat premium-core-2-owner-review/diagnostics.json; fi \ No newline at end of file From 83b29949d583722a91207dc72ae40c7e11a43b4a Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 03:38:54 -0700 Subject: [PATCH 42/69] Add one-shot Premium Core R2 second-pass patcher --- tools/apply_premium_core_r2_second_pass.py | 107 +++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 tools/apply_premium_core_r2_second_pass.py diff --git a/tools/apply_premium_core_r2_second_pass.py b/tools/apply_premium_core_r2_second_pass.py new file mode 100644 index 00000000..9d2c0ada --- /dev/null +++ b/tools/apply_premium_core_r2_second_pass.py @@ -0,0 +1,107 @@ +from pathlib import Path +import re + +path = Path('assets/js/hero-premium-core-2-r2.js') +s = path.read_text(encoding='utf-8') + + +def replace_once(old: str, new: str, label: str): + global s + count = s.count(old) + if count != 1: + raise SystemExit(f'{label}: expected exactly 1 match, found {count}') + s = s.replace(old, new, 1) + +# Bring the architectural intelligence stack forward so it reads as nested processing, +# not a hidden central glow. +replace_once('vec3 a=q-vec3(0.08,0.00,0.015);', 'vec3 a=q-vec3(0.07,0.00,0.105);', 'internal outer position') +replace_once('vec3 b=q-vec3(0.045,-0.015,0.00);', 'vec3 b=q-vec3(0.035,-0.015,0.085);', 'internal mid position') +replace_once('vec3 c=q-vec3(0.075,-0.02,0.012);', 'vec3 c=q-vec3(0.060,-0.02,0.105);', 'internal kernel position') +replace_once('vec3 r=q-vec3(0.05,-0.01,-0.06);', 'vec3 r=q-vec3(0.04,-0.01,0.015);', 'internal rails position') + +# Stronger front shell masses. +replace_once( +'''vec3 upper=q-vec3(-0.03,0.34,0.42+0.025*shellMotion*sin(uTime*.24+0.3)); + upper.xy=rot(-0.34+0.025*shellMotion*sin(uTime*.14))*upper.xy; upper.xz=rot(0.10)*upper.xz; + float upperD=sdRoundBox(upper,vec3(0.34,0.090,0.055),0.052);''', +'''vec3 upper=q-vec3(-0.05,0.38,0.44+0.028*shellMotion*sin(uTime*.24+0.3)); + upper.xy=rot(-0.34+0.025*shellMotion*sin(uTime*.14))*upper.xy; upper.xz=rot(0.10)*upper.xz; + float upperD=sdRoundBox(upper,vec3(0.39,0.105,0.060),0.058);''', +'upper shell') +replace_once( +'''vec3 lower=q-vec3(0.29,-0.29,0.39-0.020*shellMotion*sin(uTime*.18+1.7)); + lower.xy=rot(0.13-0.018*shellMotion*sin(uTime*.15))*lower.xy; lower.xz=rot(-0.13)*lower.xz; + float lowerD=sdRoundBox(lower,vec3(0.38,0.10,0.060),0.055);''', +'''vec3 lower=q-vec3(0.27,-0.31,0.405-0.022*shellMotion*sin(uTime*.18+1.7)); + lower.xy=rot(0.13-0.018*shellMotion*sin(uTime*.15))*lower.xy; lower.xz=rot(-0.13)*lower.xz; + float lowerD=sdRoundBox(lower,vec3(0.42,0.11,0.066),0.060);''', +'lower shell') + +# Broad asymmetric rear sail + integrated graphite brand plate: these break the rounded-beam demo read. +anchor = ''' if(bridgeD0.74){''' +insert = ''' if(bridgeD0.74){''' +replace_once(anchor, insert, 'sail + brand insertion') + +# Replace the enclosing glass shell with a smaller asymmetric smoked aperture, exposing the nested system. +pattern = re.compile(r''' vec3 glassQ=q-vec3\(0\.09,0\.0,0\.03\);\n glassQ\.xy=rot\(0\.08\)\*glassQ\.xy;\n float glass=abs\(sdRoundBox\(glassQ,vec3\(0\.355,0\.455,0\.255\),0\.155\)\)-0\.018;\n glass=max\(glass,0\.105-glassQ\.z\);\n glass=max\(glass,glassQ\.x-0\.285\);\n glass=max\(glass,-glassQ\.x-0\.135\);\n if\(glass Date: Tue, 11 Aug 2026 03:39:07 -0700 Subject: [PATCH 43/69] Add one-shot workflow for Premium Core R2 second pass --- .../apply-premium-core-r2-second-pass.yml | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 .github/workflows/apply-premium-core-r2-second-pass.yml diff --git a/.github/workflows/apply-premium-core-r2-second-pass.yml b/.github/workflows/apply-premium-core-r2-second-pass.yml new file mode 100644 index 00000000..2a0eb284 --- /dev/null +++ b/.github/workflows/apply-premium-core-r2-second-pass.yml @@ -0,0 +1,42 @@ +name: Apply Premium Core R2 second pass + +on: + push: + branches: + - agent/hero-premium-core-2-r1 + paths: + - tools/apply_premium_core_r2_second_pass.py + - .github/workflows/apply-premium-core-r2-second-pass.yml + workflow_dispatch: + +permissions: + contents: write + +jobs: + apply: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: agent/hero-premium-core-2-r1 + fetch-depth: 0 + - name: Apply asserted R2 geometry patch + run: python3 tools/apply_premium_core_r2_second_pass.py + - name: Validate JavaScript syntax + run: node --check assets/js/hero-premium-core-2-r2.js + - name: Guard production routes + run: | + set -euo pipefail + if git diff --name-only | grep -Eq '^(index\.html|ru/index\.html)$'; then + echo 'Production route changed unexpectedly' >&2 + exit 1 + fi + - name: Commit second-pass shader refinement + run: | + set -euo pipefail + git config user.name 'ProAI Hero Agent' + git config user.email 'actions@users.noreply.github.com' + git add assets/js/hero-premium-core-2-r2.js + git diff --cached --quiet && { echo 'No second-pass changes to commit'; exit 1; } + git commit -m 'Refine Premium Core R2 silhouette and internal intelligence' + git push origin HEAD:agent/hero-premium-core-2-r1 From 239643b6963ae58ed9eaf10bcc78d77d879b848a Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 03:40:44 -0700 Subject: [PATCH 44/69] Make Premium Core R2 second-pass patcher idempotent --- tools/apply_premium_core_r2_second_pass.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/tools/apply_premium_core_r2_second_pass.py b/tools/apply_premium_core_r2_second_pass.py index 9d2c0ada..646849f1 100644 --- a/tools/apply_premium_core_r2_second_pass.py +++ b/tools/apply_premium_core_r2_second_pass.py @@ -4,6 +4,10 @@ path = Path('assets/js/hero-premium-core-2-r2.js') s = path.read_text(encoding='utf-8') +if 'vec3 sail=q-vec3(-0.18,0.16,-0.34' in s and 'platformTopD' in s: + print('Premium Core R2 second pass already applied') + raise SystemExit(0) + def replace_once(old: str, new: str, label: str): global s @@ -12,14 +16,11 @@ def replace_once(old: str, new: str, label: str): raise SystemExit(f'{label}: expected exactly 1 match, found {count}') s = s.replace(old, new, 1) -# Bring the architectural intelligence stack forward so it reads as nested processing, -# not a hidden central glow. replace_once('vec3 a=q-vec3(0.08,0.00,0.015);', 'vec3 a=q-vec3(0.07,0.00,0.105);', 'internal outer position') replace_once('vec3 b=q-vec3(0.045,-0.015,0.00);', 'vec3 b=q-vec3(0.035,-0.015,0.085);', 'internal mid position') replace_once('vec3 c=q-vec3(0.075,-0.02,0.012);', 'vec3 c=q-vec3(0.060,-0.02,0.105);', 'internal kernel position') replace_once('vec3 r=q-vec3(0.05,-0.01,-0.06);', 'vec3 r=q-vec3(0.04,-0.01,0.015);', 'internal rails position') -# Stronger front shell masses. replace_once( '''vec3 upper=q-vec3(-0.03,0.34,0.42+0.025*shellMotion*sin(uTime*.24+0.3)); upper.xy=rot(-0.34+0.025*shellMotion*sin(uTime*.14))*upper.xy; upper.xz=rot(0.10)*upper.xz; @@ -37,7 +38,6 @@ def replace_once(old: str, new: str, label: str): float lowerD=sdRoundBox(lower,vec3(0.42,0.11,0.066),0.060);''', 'lower shell') -# Broad asymmetric rear sail + integrated graphite brand plate: these break the rounded-beam demo read. anchor = ''' if(bridgeD0.74){''' insert = ''' if(bridgeD0.74){''' replace_once(anchor, insert, 'sail + brand insertion') -# Replace the enclosing glass shell with a smaller asymmetric smoked aperture, exposing the nested system. pattern = re.compile(r''' vec3 glassQ=q-vec3\(0\.09,0\.0,0\.03\);\n glassQ\.xy=rot\(0\.08\)\*glassQ\.xy;\n float glass=abs\(sdRoundBox\(glassQ,vec3\(0\.355,0\.455,0\.255\),0\.155\)\)-0\.018;\n glass=max\(glass,0\.105-glassQ\.z\);\n glass=max\(glass,glassQ\.x-0\.285\);\n glass=max\(glass,-glassQ\.x-0\.135\);\n if\(glass Date: Tue, 11 Aug 2026 03:41:30 -0700 Subject: [PATCH 45/69] Apply asserted Premium Core R2 second pass before owner review --- .../hero-premium-core-2-owner-review.yml | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/.github/workflows/hero-premium-core-2-owner-review.yml b/.github/workflows/hero-premium-core-2-owner-review.yml index 1ffee572..2c09ac0c 100644 --- a/.github/workflows/hero-premium-core-2-owner-review.yml +++ b/.github/workflows/hero-premium-core-2-owner-review.yml @@ -12,6 +12,7 @@ on: - hero-premium-core-2-preview/** - ru/hero-premium-core-2-preview/** - tools/hero_premium_core_2_owner_review.mjs + - tools/apply_premium_core_r2_second_pass.py - .github/workflows/hero-premium-core-2-owner-review.yml - .github/hero-premium-core-2-run.txt pull_request: @@ -29,7 +30,7 @@ on: workflow_dispatch: permissions: - contents: read + contents: write actions: read jobs: @@ -43,6 +44,27 @@ jobs: fetch-depth: 0 ref: agent/hero-premium-core-2-r1 + - name: Apply asserted R2 second-pass refinement when needed + shell: bash + run: | + set -euo pipefail + python3 tools/apply_premium_core_r2_second_pass.py + node --check assets/js/hero-premium-core-2-r2.js + + - name: Persist second-pass runtime when patch changed it + shell: bash + run: | + set -euo pipefail + if git diff --quiet -- assets/js/hero-premium-core-2-r2.js; then + echo 'Second-pass runtime already persisted.' + exit 0 + fi + git config user.name 'ProAI Hero Agent' + git config user.email 'actions@users.noreply.github.com' + git add assets/js/hero-premium-core-2-r2.js + git commit -m 'Refine Premium Core R2 silhouette and internal intelligence' + git push origin HEAD:agent/hero-premium-core-2-r1 + - name: Guard production and unrelated systems shell: bash run: | @@ -135,8 +157,9 @@ jobs: grep -q 'curveDistance' assets/js/hero-premium-core-2-r2.js grep -q 'mapInternal' assets/js/hero-premium-core-2-r2.js grep -q 'brandMark' assets/js/hero-premium-core-2-r2.js + grep -q 'vec3 sail=' assets/js/hero-premium-core-2-r2.js + grep -q 'platformTopD' assets/js/hero-premium-core-2-r2.js grep -q 'uSignalMix' assets/js/hero-premium-core-2-r2.js - grep -q 'platformP' assets/js/hero-premium-core-2-r2.js grep -q 'requestAnimationFrame' assets/js/hero-premium-core-2-r2.js grep -q 'hero-core2__stage-detail' hero-premium-core-2-preview/index.html grep -q 'hero-core2__stage-detail' ru/hero-premium-core-2-preview/index.html From 5387dc975950233d94373e854d14ccec475a0662 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 03:42:55 -0700 Subject: [PATCH 46/69] Correct asserted Premium Core R2 second-pass patcher --- tools/apply_premium_core_r2_second_pass_v2.py | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 tools/apply_premium_core_r2_second_pass_v2.py diff --git a/tools/apply_premium_core_r2_second_pass_v2.py b/tools/apply_premium_core_r2_second_pass_v2.py new file mode 100644 index 00000000..05db9370 --- /dev/null +++ b/tools/apply_premium_core_r2_second_pass_v2.py @@ -0,0 +1,82 @@ +from pathlib import Path +import re + +path = Path('assets/js/hero-premium-core-2-r2.js') +s = path.read_text(encoding='utf-8') + +if 'vec3 sail=q-vec3(-0.18,0.16,-0.34' in s and 'platformTopD' in s: + print('Premium Core R2 second pass already applied') + raise SystemExit(0) + + +def one(old, new, label): + global s + n = s.count(old) + if n != 1: + raise SystemExit(f'{label}: expected 1 match, found {n}') + s = s.replace(old, new, 1) + +one('vec3 a=q-vec3(0.08,0.00,0.015);','vec3 a=q-vec3(0.07,0.00,0.105);','internal outer') +one('vec3 b=q-vec3(0.045,-0.015,0.00);','vec3 b=q-vec3(0.035,-0.015,0.085);','internal mid') +one('vec3 c=q-vec3(0.075,-0.02,0.012);','vec3 c=q-vec3(0.060,-0.02,0.105);','internal kernel') +one('vec3 r=q-vec3(0.05,-0.01,-0.06);','vec3 r=q-vec3(0.04,-0.01,0.015);','internal rails') + +one('''vec3 upper=q-vec3(-0.03,0.34,0.42+0.025*shellMotion*sin(uTime*.24+0.3)); + upper.xy=rot(-0.34+0.025*shellMotion*sin(uTime*.14))*upper.xy; upper.xz=rot(0.10)*upper.xz; + float upperD=sdRoundBox(upper,vec3(0.34,0.090,0.055),0.052);''','''vec3 upper=q-vec3(-0.05,0.38,0.44+0.028*shellMotion*sin(uTime*.24+0.3)); + upper.xy=rot(-0.34+0.025*shellMotion*sin(uTime*.14))*upper.xy; upper.xz=rot(0.10)*upper.xz; + float upperD=sdRoundBox(upper,vec3(0.39,0.105,0.060),0.058);''','upper shell') +one('''vec3 lower=q-vec3(0.29,-0.29,0.39-0.020*shellMotion*sin(uTime*.18+1.7)); + lower.xy=rot(0.13-0.018*shellMotion*sin(uTime*.15))*lower.xy; lower.xz=rot(-0.13)*lower.xz; + float lowerD=sdRoundBox(lower,vec3(0.38,0.10,0.060),0.055);''','''vec3 lower=q-vec3(0.27,-0.31,0.405-0.022*shellMotion*sin(uTime*.18+1.7)); + lower.xy=rot(0.13-0.018*shellMotion*sin(uTime*.15))*lower.xy; lower.xz=rot(-0.13)*lower.xz; + float lowerD=sdRoundBox(lower,vec3(0.42,0.11,0.066),0.060);''','lower shell') + +anchor=''' if(bridgeD0.74){''' +insert=''' if(bridgeD0.74){''' +one(anchor,insert,'sail/brand insertion') + +pat=re.compile(r''' vec3 glassQ=q-vec3\(0\.09,0\.0,0\.03\);\n glassQ\.xy=rot\(0\.08\)\*glassQ\.xy;\n float glass=abs\(sdRoundBox\(glassQ,vec3\(0\.355,0\.455,0\.255\),0\.155\)\)-0\.018;\n glass=max\(glass,0\.105-glassQ\.z\);\n glass=max\(glass,glassQ\.x-0\.285\);\n glass=max\(glass,-glassQ\.x-0\.135\);\n if\(glass Date: Tue, 11 Aug 2026 03:43:12 -0700 Subject: [PATCH 47/69] Route Premium Core R2 asserted patch to corrected v2 patcher --- tools/apply_premium_core_r2_second_pass.py | 102 +-------------------- 1 file changed, 2 insertions(+), 100 deletions(-) diff --git a/tools/apply_premium_core_r2_second_pass.py b/tools/apply_premium_core_r2_second_pass.py index 646849f1..eafaa8f6 100644 --- a/tools/apply_premium_core_r2_second_pass.py +++ b/tools/apply_premium_core_r2_second_pass.py @@ -1,101 +1,3 @@ -from pathlib import Path -import re +from runpy import run_path -path = Path('assets/js/hero-premium-core-2-r2.js') -s = path.read_text(encoding='utf-8') - -if 'vec3 sail=q-vec3(-0.18,0.16,-0.34' in s and 'platformTopD' in s: - print('Premium Core R2 second pass already applied') - raise SystemExit(0) - - -def replace_once(old: str, new: str, label: str): - global s - count = s.count(old) - if count != 1: - raise SystemExit(f'{label}: expected exactly 1 match, found {count}') - s = s.replace(old, new, 1) - -replace_once('vec3 a=q-vec3(0.08,0.00,0.015);', 'vec3 a=q-vec3(0.07,0.00,0.105);', 'internal outer position') -replace_once('vec3 b=q-vec3(0.045,-0.015,0.00);', 'vec3 b=q-vec3(0.035,-0.015,0.085);', 'internal mid position') -replace_once('vec3 c=q-vec3(0.075,-0.02,0.012);', 'vec3 c=q-vec3(0.060,-0.02,0.105);', 'internal kernel position') -replace_once('vec3 r=q-vec3(0.05,-0.01,-0.06);', 'vec3 r=q-vec3(0.04,-0.01,0.015);', 'internal rails position') - -replace_once( -'''vec3 upper=q-vec3(-0.03,0.34,0.42+0.025*shellMotion*sin(uTime*.24+0.3)); - upper.xy=rot(-0.34+0.025*shellMotion*sin(uTime*.14))*upper.xy; upper.xz=rot(0.10)*upper.xz; - float upperD=sdRoundBox(upper,vec3(0.34,0.090,0.055),0.052);''', -'''vec3 upper=q-vec3(-0.05,0.38,0.44+0.028*shellMotion*sin(uTime*.24+0.3)); - upper.xy=rot(-0.34+0.025*shellMotion*sin(uTime*.14))*upper.xy; upper.xz=rot(0.10)*upper.xz; - float upperD=sdRoundBox(upper,vec3(0.39,0.105,0.060),0.058);''', -'upper shell') -replace_once( -'''vec3 lower=q-vec3(0.29,-0.29,0.39-0.020*shellMotion*sin(uTime*.18+1.7)); - lower.xy=rot(0.13-0.018*shellMotion*sin(uTime*.15))*lower.xy; lower.xz=rot(-0.13)*lower.xz; - float lowerD=sdRoundBox(lower,vec3(0.38,0.10,0.060),0.055);''', -'''vec3 lower=q-vec3(0.27,-0.31,0.405-0.022*shellMotion*sin(uTime*.18+1.7)); - lower.xy=rot(0.13-0.018*shellMotion*sin(uTime*.15))*lower.xy; lower.xz=rot(-0.13)*lower.xz; - float lowerD=sdRoundBox(lower,vec3(0.42,0.11,0.066),0.060);''', -'lower shell') - -anchor = ''' if(bridgeD0.74){''' -insert = ''' if(bridgeD0.74){''' -replace_once(anchor, insert, 'sail + brand insertion') - -pattern = re.compile(r''' vec3 glassQ=q-vec3\(0\.09,0\.0,0\.03\);\n glassQ\.xy=rot\(0\.08\)\*glassQ\.xy;\n float glass=abs\(sdRoundBox\(glassQ,vec3\(0\.355,0\.455,0\.255\),0\.155\)\)-0\.018;\n glass=max\(glass,0\.105-glassQ\.z\);\n glass=max\(glass,glassQ\.x-0\.285\);\n glass=max\(glass,-glassQ\.x-0\.135\);\n if\(glass Date: Tue, 11 Aug 2026 10:43:25 +0000 Subject: [PATCH 48/69] Refine Premium Core R2 silhouette and internal intelligence --- assets/js/hero-premium-core-2-r2.js | 69 ++++++++++++++++++----------- 1 file changed, 43 insertions(+), 26 deletions(-) diff --git a/assets/js/hero-premium-core-2-r2.js b/assets/js/hero-premium-core-2-r2.js index 9722b6ca..1a012fc7 100644 --- a/assets/js/hero-premium-core-2-r2.js +++ b/assets/js/hero-premium-core-2-r2.js @@ -138,28 +138,28 @@ float detail=detailMix(); vec2 res=vec2(1000.0,0.0); - vec3 a=q-vec3(0.08,0.00,0.015); + vec3 a=q-vec3(0.07,0.00,0.105); a.xy=rot(0.16+uMotion*0.030*sin(uTime*0.23))*a.xy; a.xz=rot(-0.18-uMotion*0.018*sin(uTime*0.17+0.6))*a.xz; float outer=abs(sdRoundBox(a,vec3(0.315,0.410,0.220),0.135))-0.027; outer=max(outer,-sdRoundBox(a-vec3(0.23,0.02,0.16),vec3(0.20,0.20,0.13),0.08)); if(outer0.74){ vec3 rear=q-vec3(0.08,0.02,-0.50-0.025*shellMotion*sin(uTime*.12)); rear.xy=rot(0.09+0.012*shellMotion*sin(uTime*.09))*rear.xy; rear.xz=rot(-0.10)*rear.xz; @@ -236,12 +250,11 @@ if(jawD0.84){ @@ -412,7 +428,8 @@ vec3 ro=vec3(0.02+uPointer.x*0.045*uMotion,0.06+uPointer.y*0.028*uMotion,4.02); vec3 ta=vec3(0.055,-0.02,0.0); vec3 ww=normalize(ta-ro),uu=normalize(cross(ww,vec3(0.0,1.0,0.0))),vv=cross(uu,ww); - vec3 rd=normalize(uu*p.x+vv*p.y+ww*2.38); + float focal=mix(2.82,2.42,detailMix()); + vec3 rd=normalize(uu*p.x+vv*p.y+ww*focal); float t=0.0,id=0.0,glow=0.0; bool hit=false; int maxSteps=int(mix(46.0,74.0,uQuality)); for(int i=0;i<76;i++){ From 1b46965cc963b30b4102076b450c1de29f968d0f Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 03:50:16 -0700 Subject: [PATCH 49/69] Harden Premium Core R2 owner-review capture gates --- tools/hero_premium_core_2_owner_review.mjs | 30 ++++++++++++---------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/tools/hero_premium_core_2_owner_review.mjs b/tools/hero_premium_core_2_owner_review.mjs index bb42bc05..f999faa1 100644 --- a/tools/hero_premium_core_2_owner_review.mjs +++ b/tools/hero_premium_core_2_owner_review.mjs @@ -9,6 +9,7 @@ const routes = { en: '/hero-premium-core-2-preview/', ru: '/ru/hero-premium-core-2-preview/' }; +const screenshotTimeout = 120000; fs.rmSync(out, { recursive: true, force: true }); fs.mkdirSync(out, { recursive: true }); @@ -32,12 +33,12 @@ async function ready(page, route, reducedMotion = 'no-preference') { await page.emulateMedia({ reducedMotion }); await page.goto(`${base}${route}`, { waitUntil: 'networkidle' }); await page.evaluate(async () => { if (document.fonts?.ready) await document.fonts.ready; }); - await page.waitForFunction(() => document.documentElement.classList.contains('hero-core2--ready'), null, { timeout: 20000 }); - await page.waitForTimeout(550); + await page.waitForFunction(() => document.documentElement.classList.contains('hero-core2--ready'), null, { timeout: 30000 }); + await page.waitForTimeout(650); if (errors.length) throw new Error(errors.join('\n')); } -async function captureStatic({ locale, width, height, mobile, file, minVisualRatio = 0 }) { +async function captureStatic({ locale, width, height, mobile, file, minVisualRatio = 0, review = '' }) { const context = await browser.newContext({ viewport: { width, height }, deviceScaleFactor: 1, @@ -45,7 +46,8 @@ async function captureStatic({ locale, width, height, mobile, file, minVisualRat hasTouch: mobile }); const page = await context.newPage(); - await ready(page, routes[locale]); + const route = review ? `${routes[locale]}?review=${encodeURIComponent(review)}` : routes[locale]; + await ready(page, route); const diagnostics = await page.evaluate(() => { const visual = document.querySelector('[data-hero-core2-visual]'); const rect = visual?.getBoundingClientRect(); @@ -53,6 +55,7 @@ async function captureStatic({ locale, width, height, mobile, file, minVisualRat return { ready: document.documentElement.classList.contains('hero-core2--ready'), fallback: document.documentElement.classList.contains('hero-core2--fallback'), + review: document.documentElement.dataset.heroCore2Review || '', scrollWidth: document.documentElement.scrollWidth, innerWidth: window.innerWidth, innerHeight: window.innerHeight, @@ -76,12 +79,14 @@ async function captureStatic({ locale, width, height, mobile, file, minVisualRat if (!diagnostics.ready || diagnostics.fallback || !diagnostics.canvas.webgl2) throw new Error(`${locale} ${width}x${height}: WebGL2 did not reach ready state`); if (diagnostics.scrollWidth > diagnostics.innerWidth + 1) throw new Error(`${locale} ${width}x${height}: horizontal overflow ${diagnostics.scrollWidth} > ${diagnostics.innerWidth}`); if (minVisualRatio && (diagnostics.visual?.viewportRatio || 0) < minVisualRatio) throw new Error(`${locale} ${width}x${height}: Core visibility ratio ${(diagnostics.visual?.viewportRatio || 0)} < ${minVisualRatio}`); - await page.screenshot({ path: path.join(out, file), fullPage: false }); + await page.screenshot({ path: path.join(out, file), fullPage: false, timeout: screenshotTimeout }); await context.close(); return diagnostics; } const diagnostics = { + gate1CoreOnly: await captureStatic({ locale: 'en', width: 1440, height: 900, mobile: false, file: 'CORE2_GATE1_CORE_ONLY_1440x900.png', review: 'core' }), + gate2Materials: await captureStatic({ locale: 'en', width: 1440, height: 900, mobile: false, file: 'CORE2_GATE2_MATERIALS_1440x900.png', review: 'materials' }), enDesktop: await captureStatic({ locale: 'en', width: 1440, height: 900, mobile: false, file: 'CORE2_EN_DESKTOP_1440x900.png' }), ruDesktop: await captureStatic({ locale: 'ru', width: 1440, height: 900, mobile: false, file: 'CORE2_RU_DESKTOP_1440x900.png' }), enMobile: await captureStatic({ locale: 'en', width: 390, height: 844, mobile: true, file: 'CORE2_EN_MOBILE_390x844.png', minVisualRatio: 0.54 }), @@ -90,7 +95,6 @@ const diagnostics = { enLandscape: await captureStatic({ locale: 'en', width: 844, height: 390, mobile: true, file: 'CORE2_EN_LANDSCAPE_844x390.png', minVisualRatio: 0.78 }) }; -// Reduced-motion runtime gate: WebGL remains available but the final/result state is static. { const context = await browser.newContext({ viewport: { width: 390, height: 844 }, deviceScaleFactor: 1, isMobile: true, hasTouch: true }); const page = await context.newPage(); @@ -100,11 +104,10 @@ const diagnostics = { ready: document.documentElement.classList.contains('hero-core2--ready') })); if (!reduced.ready || reduced.active !== 3) throw new Error(`Reduced-motion state invalid: ${JSON.stringify(reduced)}`); - await page.screenshot({ path: path.join(out, 'CORE2_EN_REDUCED_MOTION_390x844.png'), fullPage: false }); + await page.screenshot({ path: path.join(out, 'CORE2_EN_REDUCED_MOTION_390x844.png'), fullPage: false, timeout: screenshotTimeout }); await context.close(); } -// Autonomous narrative gate: without interaction the normal sequence must resolve to 04 RESULT. { const context = await browser.newContext({ viewport: { width: 1440, height: 900 }, deviceScaleFactor: 1 }); const page = await context.newPage(); @@ -116,7 +119,6 @@ const diagnostics = { await context.close(); } -// Deterministic owner-review captures for all four stage-driven states. { const names = ['TRUST', 'INQUIRY', 'RESPONSE', 'RESULT']; const context = await browser.newContext({ viewport: { width: 1440, height: 900 }, deviceScaleFactor: 1 }); @@ -125,16 +127,14 @@ const diagnostics = { const stages = page.locator('[data-hero-core2-stage-button]'); for (let i = 0; i < names.length; i += 1) { await stages.nth(i).click(); - await page.waitForTimeout(550); + await page.waitForTimeout(650); const active = await page.evaluate(() => [...document.querySelectorAll('[data-hero-core2-stage]')].findIndex(el => el.classList.contains('is-active'))); if (active !== i) throw new Error(`Stage review capture mismatch for ${names[i]}: active ${active}`); - await page.screenshot({ path: path.join(out, `CORE2_EN_STAGE_0${i + 1}_${names[i]}.png`), fullPage: false }); + await page.screenshot({ path: path.join(out, `CORE2_EN_STAGE_0${i + 1}_${names[i]}.png`), fullPage: false, timeout: screenshotTimeout }); } await context.close(); } -// Browser-native motion sample. Stage-state stills above are the deterministic visual authority; -// the autonomous sequence is independently verified above. const videoDir = path.join(out, '.video-tmp'); fs.mkdirSync(videoDir, { recursive: true }); let webmPath; @@ -208,6 +208,8 @@ fs.rmSync(videoDir, { recursive: true, force: true }); fs.writeFileSync(path.join(out, 'diagnostics.json'), JSON.stringify(diagnostics, null, 2) + '\n'); for (const file of [ + 'CORE2_GATE1_CORE_ONLY_1440x900.png', + 'CORE2_GATE2_MATERIALS_1440x900.png', 'CORE2_EN_DESKTOP_1440x900.png', 'CORE2_RU_DESKTOP_1440x900.png', 'CORE2_EN_MOBILE_390x844.png', @@ -226,4 +228,4 @@ for (const file of [ if (!fs.existsSync(p) || fs.statSync(p).size < (file.endsWith('.json') ? 100 : 1000)) throw new Error(`Missing/empty owner-review output: ${p}`); } -console.log('Premium Core 2.0 owner-review package complete:', fs.readdirSync(out)); +console.log('Premium Core 2.0 owner-review package complete:', fs.readdirSync(out)); \ No newline at end of file From 3e6e6a12c2eb05fa977f297e58a6ac0b7082d81a Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 03:56:36 -0700 Subject: [PATCH 50/69] Add one-shot capture freeze patch for R2 owner review --- tools/apply_premium_core_r2_capture_freeze.py | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 tools/apply_premium_core_r2_capture_freeze.py diff --git a/tools/apply_premium_core_r2_capture_freeze.py b/tools/apply_premium_core_r2_capture_freeze.py new file mode 100644 index 00000000..b0c62249 --- /dev/null +++ b/tools/apply_premium_core_r2_capture_freeze.py @@ -0,0 +1,53 @@ +from pathlib import Path + +js_path = Path('assets/js/hero-premium-core-2-r2.js') +tool_path = Path('tools/hero_premium_core_2_owner_review.mjs') +js = js_path.read_text(encoding='utf-8') +tool = tool_path.read_text(encoding='utf-8') +changed = False + +if 'let captureFreeze = false;' not in js: + old = ''' let visible = true;\n let renderScale = 1;''' + new = ''' let visible = true;\n let captureFreeze = false;\n let renderScale = 1;''' + if old not in js: raise SystemExit('JS capture freeze state anchor missing') + js = js.replace(old, new, 1) + + old = ''' const visibilityObserver = new IntersectionObserver((entries) => { visible = entries.some((entry) => entry.isIntersecting); }, { threshold: 0.02 });\n visibilityObserver.observe(visual);''' + new = ''' const visibilityObserver = new IntersectionObserver((entries) => { visible = entries.some((entry) => entry.isIntersecting); }, { threshold: 0.02 });\n visibilityObserver.observe(visual);\n\n window.addEventListener('hero-core2:capture-freeze', (event) => {\n captureFreeze = Boolean(event.detail);\n });''' + if old not in js: raise SystemExit('JS visibility anchor missing') + js = js.replace(old, new, 1) + + old = ''' requestAnimationFrame(render);\n if (!visible || document.hidden) return;\n const delta = now - lastFrame;''' + new = ''' requestAnimationFrame(render);\n if (!visible || document.hidden) return;\n if (captureFreeze && !firstFrame) return;\n const delta = now - lastFrame;''' + if old not in js: raise SystemExit('JS render anchor missing') + js = js.replace(old, new, 1) + changed = True + +if "hero-core2:capture-freeze" not in tool: + old = ''' if (minVisualRatio && (diagnostics.visual?.viewportRatio || 0) < minVisualRatio) throw new Error(`${locale} ${width}x${height}: Core visibility ratio ${(diagnostics.visual?.viewportRatio || 0)} < ${minVisualRatio}`);\n await page.screenshot({ path: path.join(out, file), fullPage: false, timeout: screenshotTimeout });''' + new = ''' if (minVisualRatio && (diagnostics.visual?.viewportRatio || 0) < minVisualRatio) throw new Error(`${locale} ${width}x${height}: Core visibility ratio ${(diagnostics.visual?.viewportRatio || 0)} < ${minVisualRatio}`);\n await page.evaluate(() => window.dispatchEvent(new CustomEvent('hero-core2:capture-freeze', { detail: true })));\n await page.waitForTimeout(80);\n await page.screenshot({ path: path.join(out, file), fullPage: false, timeout: screenshotTimeout });''' + if old not in tool: raise SystemExit('captureStatic freeze anchor missing') + tool = tool.replace(old, new, 1) + + old = ''' if (!reduced.ready || reduced.active !== 3) throw new Error(`Reduced-motion state invalid: ${JSON.stringify(reduced)}`);\n await page.screenshot({ path: path.join(out, 'CORE2_EN_REDUCED_MOTION_390x844.png'), fullPage: false, timeout: screenshotTimeout });''' + new = ''' if (!reduced.ready || reduced.active !== 3) throw new Error(`Reduced-motion state invalid: ${JSON.stringify(reduced)}`);\n await page.evaluate(() => window.dispatchEvent(new CustomEvent('hero-core2:capture-freeze', { detail: true })));\n await page.waitForTimeout(80);\n await page.screenshot({ path: path.join(out, 'CORE2_EN_REDUCED_MOTION_390x844.png'), fullPage: false, timeout: screenshotTimeout });''' + if old not in tool: raise SystemExit('reduced freeze anchor missing') + tool = tool.replace(old, new, 1) + + old = ''' for (let i = 0; i < names.length; i += 1) {\n await stages.nth(i).click();\n await page.waitForTimeout(650);''' + new = ''' for (let i = 0; i < names.length; i += 1) {\n await page.evaluate(() => window.dispatchEvent(new CustomEvent('hero-core2:capture-freeze', { detail: false })));\n await stages.nth(i).click();\n await page.waitForTimeout(650);''' + if old not in tool: raise SystemExit('stage unfreeze anchor missing') + tool = tool.replace(old, new, 1) + + old = ''' if (active !== i) throw new Error(`Stage review capture mismatch for ${names[i]}: active ${active}`);\n await page.screenshot({ path: path.join(out, `CORE2_EN_STAGE_0${i + 1}_${names[i]}.png`), fullPage: false, timeout: screenshotTimeout });''' + new = ''' if (active !== i) throw new Error(`Stage review capture mismatch for ${names[i]}: active ${active}`);\n await page.evaluate(() => window.dispatchEvent(new CustomEvent('hero-core2:capture-freeze', { detail: true })));\n await page.waitForTimeout(80);\n await page.screenshot({ path: path.join(out, `CORE2_EN_STAGE_0${i + 1}_${names[i]}.png`), fullPage: false, timeout: screenshotTimeout });''' + if old not in tool: raise SystemExit('stage freeze anchor missing') + tool = tool.replace(old, new, 1) + changed = True + +if changed: + js_path.write_text(js, encoding='utf-8') + tool_path.write_text(tool, encoding='utf-8') + print('Capture freeze hook applied') +else: + print('Capture freeze hook already applied') From 075980c4f4861f165cd8bc7222fcfb45e11f599f Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 04:00:03 -0700 Subject: [PATCH 51/69] Apply R2 capture freeze hook with second-pass assertion --- tools/apply_premium_core_r2_second_pass.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/apply_premium_core_r2_second_pass.py b/tools/apply_premium_core_r2_second_pass.py index eafaa8f6..e4ae0b9f 100644 --- a/tools/apply_premium_core_r2_second_pass.py +++ b/tools/apply_premium_core_r2_second_pass.py @@ -1,3 +1,9 @@ from runpy import run_path -run_path('tools/apply_premium_core_r2_second_pass_v2.py', run_name='__main__') +try: + run_path('tools/apply_premium_core_r2_second_pass_v2.py', run_name='__main__') +except SystemExit as exc: + if exc.code not in (0, None): + raise + +run_path('tools/apply_premium_core_r2_capture_freeze.py', run_name='__main__') From 655183810f572bd8b676e963e4e057a46522d475 Mon Sep 17 00:00:00 2001 From: ProAI Hero Agent Date: Tue, 11 Aug 2026 11:00:17 +0000 Subject: [PATCH 52/69] Refine Premium Core R2 silhouette and internal intelligence --- assets/js/hero-premium-core-2-r2.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/assets/js/hero-premium-core-2-r2.js b/assets/js/hero-premium-core-2-r2.js index 1a012fc7..835ca476 100644 --- a/assets/js/hero-premium-core-2-r2.js +++ b/assets/js/hero-premium-core-2-r2.js @@ -515,6 +515,7 @@ let pointer = { x: 0, y: 0 }; let pointerTarget = { x: 0, y: 0 }; let visible = true; + let captureFreeze = false; let renderScale = 1; let quality = 1; let firstFrame = true; @@ -556,6 +557,10 @@ const visibilityObserver = new IntersectionObserver((entries) => { visible = entries.some((entry) => entry.isIntersecting); }, { threshold: 0.02 }); visibilityObserver.observe(visual); + window.addEventListener('hero-core2:capture-freeze', (event) => { + captureFreeze = Boolean(event.detail); + }); + const adaptPerformance = (delta) => { if (firstFrame || motionReduced) return; frameSamples.push(delta); @@ -573,6 +578,7 @@ const render = (now) => { requestAnimationFrame(render); if (!visible || document.hidden) return; + if (captureFreeze && !firstFrame) return; const delta = now - lastFrame; lastFrame = now; adaptPerformance(delta); From 9383097c49d565c6d9d3f7fe5d1fc1a5b812af7d Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 04:01:47 -0700 Subject: [PATCH 53/69] Freeze R2 WebGL between owner-review still captures --- tools/hero_premium_core_2_owner_review.mjs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/hero_premium_core_2_owner_review.mjs b/tools/hero_premium_core_2_owner_review.mjs index f999faa1..d2917f45 100644 --- a/tools/hero_premium_core_2_owner_review.mjs +++ b/tools/hero_premium_core_2_owner_review.mjs @@ -10,6 +10,10 @@ const routes = { ru: '/ru/hero-premium-core-2-preview/' }; const screenshotTimeout = 120000; +const freeze = async (page, state = true) => { + await page.evaluate((detail) => window.dispatchEvent(new CustomEvent('hero-core2:capture-freeze', { detail })), state); + await page.waitForTimeout(state ? 80 : 40); +}; fs.rmSync(out, { recursive: true, force: true }); fs.mkdirSync(out, { recursive: true }); @@ -79,6 +83,7 @@ async function captureStatic({ locale, width, height, mobile, file, minVisualRat if (!diagnostics.ready || diagnostics.fallback || !diagnostics.canvas.webgl2) throw new Error(`${locale} ${width}x${height}: WebGL2 did not reach ready state`); if (diagnostics.scrollWidth > diagnostics.innerWidth + 1) throw new Error(`${locale} ${width}x${height}: horizontal overflow ${diagnostics.scrollWidth} > ${diagnostics.innerWidth}`); if (minVisualRatio && (diagnostics.visual?.viewportRatio || 0) < minVisualRatio) throw new Error(`${locale} ${width}x${height}: Core visibility ratio ${(diagnostics.visual?.viewportRatio || 0)} < ${minVisualRatio}`); + await freeze(page, true); await page.screenshot({ path: path.join(out, file), fullPage: false, timeout: screenshotTimeout }); await context.close(); return diagnostics; @@ -104,6 +109,7 @@ const diagnostics = { ready: document.documentElement.classList.contains('hero-core2--ready') })); if (!reduced.ready || reduced.active !== 3) throw new Error(`Reduced-motion state invalid: ${JSON.stringify(reduced)}`); + await freeze(page, true); await page.screenshot({ path: path.join(out, 'CORE2_EN_REDUCED_MOTION_390x844.png'), fullPage: false, timeout: screenshotTimeout }); await context.close(); } @@ -126,10 +132,12 @@ const diagnostics = { await ready(page, routes.en); const stages = page.locator('[data-hero-core2-stage-button]'); for (let i = 0; i < names.length; i += 1) { + await freeze(page, false); await stages.nth(i).click(); await page.waitForTimeout(650); const active = await page.evaluate(() => [...document.querySelectorAll('[data-hero-core2-stage]')].findIndex(el => el.classList.contains('is-active'))); if (active !== i) throw new Error(`Stage review capture mismatch for ${names[i]}: active ${active}`); + await freeze(page, true); await page.screenshot({ path: path.join(out, `CORE2_EN_STAGE_0${i + 1}_${names[i]}.png`), fullPage: false, timeout: screenshotTimeout }); } await context.close(); @@ -146,6 +154,7 @@ let webmPath; }); const page = await context.newPage(); await ready(page, routes.en); + await freeze(page, false); const video = page.video(); await page.evaluate(() => { From b8298842ccfa9b01c17901bd5e8dfa391b0d09a7 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 04:08:08 -0700 Subject: [PATCH 54/69] Add asserted Premium Core R2 sculptural third-pass patcher --- tools/apply_premium_core_r2_third_pass.py | 140 ++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 tools/apply_premium_core_r2_third_pass.py diff --git a/tools/apply_premium_core_r2_third_pass.py b/tools/apply_premium_core_r2_third_pass.py new file mode 100644 index 00000000..97b77de2 --- /dev/null +++ b/tools/apply_premium_core_r2_third_pass.py @@ -0,0 +1,140 @@ +from pathlib import Path + +path = Path('assets/js/hero-premium-core-2-r2.js') +s = path.read_text(encoding='utf-8') + +if 'sdFacetedSlab' in s and 'float lamella1=' in s: + print('Premium Core R2 third pass already applied') + raise SystemExit(0) + + +def one(old, new, label): + global s + n = s.count(old) + if n != 1: + raise SystemExit(f'{label}: expected 1 match, found {n}') + s = s.replace(old, new, 1) + +one( +' float sdRoundBox(vec3 p,vec3 b,float r){ vec3 q=abs(p)-b+r; return min(max(q.x,max(q.y,q.z)),0.0)+length(max(q,0.0))-r; }', +''' float sdRoundBox(vec3 p,vec3 b,float r){ vec3 q=abs(p)-b+r; return min(max(q.x,max(q.y,q.z)),0.0)+length(max(q,0.0))-r; } + float sdFacetedSlab(vec3 p,vec3 b,float r,float cut){ + float d=sdRoundBox(p,b,r); + d=max(d,(abs(p.x)+abs(p.y)-b.x-b.y)*0.7071-cut); + return d; + }''', +'faceted helper') + +# Architectural intelligence stack: thinner shells, layered lamellae, stronger negative space. +one('float outer=abs(sdRoundBox(a,vec3(0.315,0.410,0.220),0.135))-0.027;', + 'float outer=abs(sdFacetedSlab(a,vec3(0.335,0.400,0.105),0.050,0.040))-0.020;', + 'outer intelligence frame') +one('outer=max(outer,-sdRoundBox(a-vec3(0.23,0.02,0.16),vec3(0.20,0.20,0.13),0.08));', + 'outer=max(outer,-sdRoundBox(a-vec3(0.20,0.02,0.075),vec3(0.18,0.23,0.075),0.050));', + 'outer intelligence opening') +one('float mid=abs(sdRoundBox(b,vec3(0.235,0.315,0.165),0.105))-0.022;', + 'float mid=abs(sdFacetedSlab(b,vec3(0.255,0.305,0.082),0.042,0.032))-0.018;', + 'mid intelligence frame') +one('mid=max(mid,-sdRoundBox(b-vec3(-0.16,-0.02,0.12),vec3(0.13,0.18,0.11),0.07));', + 'mid=max(mid,-sdRoundBox(b-vec3(-0.13,-0.02,0.060),vec3(0.12,0.18,0.065),0.043));', + 'mid intelligence opening') +one('float kernel=sdRoundBox(c,vec3(0.125,0.215,0.105),0.072);', + 'float kernel=sdFacetedSlab(c,vec3(0.135,0.210,0.064),0.036,0.024);', + 'kernel faceting') +one('kernel=max(kernel,-sdRoundBox(c-vec3(0.00,0.015,0.08),vec3(0.052,0.130,0.055),0.035));', + 'kernel=max(kernel,-sdRoundBox(c-vec3(0.00,0.015,0.045),vec3(0.055,0.125,0.042),0.028));', + 'kernel aperture')\nanchor=''' if(kernel Date: Tue, 11 Aug 2026 04:08:21 -0700 Subject: [PATCH 55/69] Route Premium Core R2 through sculptural third pass --- tools/apply_premium_core_r2_second_pass.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/tools/apply_premium_core_r2_second_pass.py b/tools/apply_premium_core_r2_second_pass.py index e4ae0b9f..3cdbec13 100644 --- a/tools/apply_premium_core_r2_second_pass.py +++ b/tools/apply_premium_core_r2_second_pass.py @@ -1,9 +1,12 @@ from runpy import run_path -try: - run_path('tools/apply_premium_core_r2_second_pass_v2.py', run_name='__main__') -except SystemExit as exc: - if exc.code not in (0, None): - raise - -run_path('tools/apply_premium_core_r2_capture_freeze.py', run_name='__main__') +for script in ( + 'tools/apply_premium_core_r2_second_pass_v2.py', + 'tools/apply_premium_core_r2_capture_freeze.py', + 'tools/apply_premium_core_r2_third_pass.py', +): + try: + run_path(script, run_name='__main__') + except SystemExit as exc: + if exc.code not in (0, None): + raise From 74fc09f140538b57f5da35dab51416764dc28d74 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 04:09:13 -0700 Subject: [PATCH 56/69] Normalize sculptural third-pass helper before execution --- tools/apply_premium_core_r2_second_pass.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/apply_premium_core_r2_second_pass.py b/tools/apply_premium_core_r2_second_pass.py index 3cdbec13..d02e663a 100644 --- a/tools/apply_premium_core_r2_second_pass.py +++ b/tools/apply_premium_core_r2_second_pass.py @@ -1,12 +1,20 @@ +from pathlib import Path from runpy import run_path for script in ( 'tools/apply_premium_core_r2_second_pass_v2.py', 'tools/apply_premium_core_r2_capture_freeze.py', - 'tools/apply_premium_core_r2_third_pass.py', ): try: run_path(script, run_name='__main__') except SystemExit as exc: if exc.code not in (0, None): raise + +third = Path('tools/apply_premium_core_r2_third_pass.py') +source = third.read_text(encoding='utf-8').replace(" 'kernel aperture')\\nanchor=", " 'kernel aperture')\nanchor=") +try: + exec(compile(source, str(third), 'exec'), {'__name__': '__main__', '__file__': str(third)}) +except SystemExit as exc: + if exc.code not in (0, None): + raise From bc7c5ecd2b6cd89afe32b64a1e7ae809c9d928b3 Mon Sep 17 00:00:00 2001 From: ProAI Hero Agent Date: Tue, 11 Aug 2026 11:09:28 +0000 Subject: [PATCH 57/69] Refine Premium Core R2 silhouette and internal intelligence --- assets/js/hero-premium-core-2-r2.js | 75 +++++++++++++++++++---------- 1 file changed, 50 insertions(+), 25 deletions(-) diff --git a/assets/js/hero-premium-core-2-r2.js b/assets/js/hero-premium-core-2-r2.js index 835ca476..df893f31 100644 --- a/assets/js/hero-premium-core-2-r2.js +++ b/assets/js/hero-premium-core-2-r2.js @@ -109,6 +109,11 @@ mat2 rot(float a){ float c=cos(a),s=sin(a); return mat2(c,-s,s,c); } float hash21(vec2 p){ p=fract(p*vec2(123.34,456.21)); p+=dot(p,p+45.32); return fract(p.x*p.y); } float sdRoundBox(vec3 p,vec3 b,float r){ vec3 q=abs(p)-b+r; return min(max(q.x,max(q.y,q.z)),0.0)+length(max(q,0.0))-r; } + float sdFacetedSlab(vec3 p,vec3 b,float r,float cut){ + float d=sdRoundBox(p,b,r); + d=max(d,(abs(p.x)+abs(p.y)-b.x-b.y)*0.7071-cut); + return d; + } float sdCapsule(vec3 p,vec3 a,vec3 b,float r){ vec3 pa=p-a,ba=b-a; float h=clamp(dot(pa,ba)/dot(ba,ba),0.0,1.0); return length(pa-ba*h)-r; } float sdPlane(vec3 p,vec3 n,float h){ return dot(p,n)+h; } float sdSeg2(vec2 p,vec2 a,vec2 b){ vec2 pa=p-a,ba=b-a; float h=clamp(dot(pa,ba)/max(dot(ba,ba),.00001),0.0,1.0); return length(pa-ba*h); } @@ -141,24 +146,41 @@ vec3 a=q-vec3(0.07,0.00,0.105); a.xy=rot(0.16+uMotion*0.030*sin(uTime*0.23))*a.xy; a.xz=rot(-0.18-uMotion*0.018*sin(uTime*0.17+0.6))*a.xz; - float outer=abs(sdRoundBox(a,vec3(0.315,0.410,0.220),0.135))-0.027; - outer=max(outer,-sdRoundBox(a-vec3(0.23,0.02,0.16),vec3(0.20,0.20,0.13),0.08)); + float outer=abs(sdFacetedSlab(a,vec3(0.335,0.400,0.105),0.050,0.040))-0.020; + outer=max(outer,-sdRoundBox(a-vec3(0.20,0.02,0.075),vec3(0.18,0.23,0.075),0.050)); if(outer0.74){ vec3 rear=q-vec3(0.08,0.02,-0.50-0.025*shellMotion*sin(uTime*.12)); rear.xy=rot(0.09+0.012*shellMotion*sin(uTime*.09))*rear.xy; rear.xz=rot(-0.10)*rear.xz; - float rearD=sdRoundBox(rear,vec3(0.46,0.46,0.055),0.070); + float rearD=sdFacetedSlab(rear,vec3(0.480,0.470,0.036),0.036,0.034); rearD=max(rearD,-sdRoundBox(rear-vec3(0.15,0.00,0.03),vec3(0.31,0.30,0.05),0.055)); if(rearD0.84){ vec3 jaw=q-vec3(0.50,0.43,0.12+0.030*shellMotion*sin(uTime*.22+2.5)); jaw.xy=rot(0.38+0.018*shellMotion*sin(uTime*.13))*jaw.xy; jaw.xz=rot(0.24)*jaw.xz; - float jawD=sdRoundBox(jaw,vec3(0.22,0.095,0.17),0.060); + float jawD=sdFacetedSlab(jaw,vec3(0.235,0.110,0.105),0.038,0.026); if(jawD Date: Tue, 11 Aug 2026 04:10:12 -0700 Subject: [PATCH 58/69] Retrigger Premium Core R2 sculptural pass on latest head --- .github/hero-premium-core-2-run.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/hero-premium-core-2-run.txt b/.github/hero-premium-core-2-run.txt index d66c96c8..b48606ca 100644 --- a/.github/hero-premium-core-2-run.txt +++ b/.github/hero-premium-core-2-run.txt @@ -1 +1 @@ -2026-08-11T02:16:00-07:00 owner-review QA trigger R2 +2026-08-11T04:14:00-07:00 owner-review QA trigger R2 sculptural pass From fa2f467c190aaf0408635c913be448289b7497fb Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 04:18:36 -0700 Subject: [PATCH 59/69] Finalize Premium Core R2 read-only owner review workflow --- .../hero-premium-core-2-owner-review.yml | 27 +++---------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/.github/workflows/hero-premium-core-2-owner-review.yml b/.github/workflows/hero-premium-core-2-owner-review.yml index 2c09ac0c..57f0183b 100644 --- a/.github/workflows/hero-premium-core-2-owner-review.yml +++ b/.github/workflows/hero-premium-core-2-owner-review.yml @@ -12,7 +12,6 @@ on: - hero-premium-core-2-preview/** - ru/hero-premium-core-2-preview/** - tools/hero_premium_core_2_owner_review.mjs - - tools/apply_premium_core_r2_second_pass.py - .github/workflows/hero-premium-core-2-owner-review.yml - .github/hero-premium-core-2-run.txt pull_request: @@ -30,7 +29,7 @@ on: workflow_dispatch: permissions: - contents: write + contents: read actions: read jobs: @@ -44,27 +43,6 @@ jobs: fetch-depth: 0 ref: agent/hero-premium-core-2-r1 - - name: Apply asserted R2 second-pass refinement when needed - shell: bash - run: | - set -euo pipefail - python3 tools/apply_premium_core_r2_second_pass.py - node --check assets/js/hero-premium-core-2-r2.js - - - name: Persist second-pass runtime when patch changed it - shell: bash - run: | - set -euo pipefail - if git diff --quiet -- assets/js/hero-premium-core-2-r2.js; then - echo 'Second-pass runtime already persisted.' - exit 0 - fi - git config user.name 'ProAI Hero Agent' - git config user.email 'actions@users.noreply.github.com' - git add assets/js/hero-premium-core-2-r2.js - git commit -m 'Refine Premium Core R2 silhouette and internal intelligence' - git push origin HEAD:agent/hero-premium-core-2-r1 - - name: Guard production and unrelated systems shell: bash run: | @@ -153,13 +131,16 @@ jobs: run: | set -euo pipefail grep -q 'sdRoundBox' assets/js/hero-premium-core-2-r2.js + grep -q 'sdFacetedSlab' assets/js/hero-premium-core-2-r2.js grep -q 'sdCapsule' assets/js/hero-premium-core-2-r2.js grep -q 'curveDistance' assets/js/hero-premium-core-2-r2.js grep -q 'mapInternal' assets/js/hero-premium-core-2-r2.js + grep -q 'float lamella1=' assets/js/hero-premium-core-2-r2.js grep -q 'brandMark' assets/js/hero-premium-core-2-r2.js grep -q 'vec3 sail=' assets/js/hero-premium-core-2-r2.js grep -q 'platformTopD' assets/js/hero-premium-core-2-r2.js grep -q 'uSignalMix' assets/js/hero-premium-core-2-r2.js + grep -q 'hero-core2:capture-freeze' assets/js/hero-premium-core-2-r2.js grep -q 'requestAnimationFrame' assets/js/hero-premium-core-2-r2.js grep -q 'hero-core2__stage-detail' hero-premium-core-2-preview/index.html grep -q 'hero-core2__stage-detail' ru/hero-premium-core-2-preview/index.html From 411fd080cfb2ba251a94599c437a8a3506cb333d Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 04:19:08 -0700 Subject: [PATCH 60/69] Remove temporary Premium Core R2 patch helper --- tools/apply_premium_core_r2_second_pass.py | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 tools/apply_premium_core_r2_second_pass.py diff --git a/tools/apply_premium_core_r2_second_pass.py b/tools/apply_premium_core_r2_second_pass.py deleted file mode 100644 index d02e663a..00000000 --- a/tools/apply_premium_core_r2_second_pass.py +++ /dev/null @@ -1,20 +0,0 @@ -from pathlib import Path -from runpy import run_path - -for script in ( - 'tools/apply_premium_core_r2_second_pass_v2.py', - 'tools/apply_premium_core_r2_capture_freeze.py', -): - try: - run_path(script, run_name='__main__') - except SystemExit as exc: - if exc.code not in (0, None): - raise - -third = Path('tools/apply_premium_core_r2_third_pass.py') -source = third.read_text(encoding='utf-8').replace(" 'kernel aperture')\\nanchor=", " 'kernel aperture')\nanchor=") -try: - exec(compile(source, str(third), 'exec'), {'__name__': '__main__', '__file__': str(third)}) -except SystemExit as exc: - if exc.code not in (0, None): - raise From 199c3f513f51507a53ce9b3335177da8b6b740a0 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 04:19:15 -0700 Subject: [PATCH 61/69] Remove temporary Premium Core R2 patch helper v2 --- tools/apply_premium_core_r2_second_pass_v2.py | 82 ------------------- 1 file changed, 82 deletions(-) delete mode 100644 tools/apply_premium_core_r2_second_pass_v2.py diff --git a/tools/apply_premium_core_r2_second_pass_v2.py b/tools/apply_premium_core_r2_second_pass_v2.py deleted file mode 100644 index 05db9370..00000000 --- a/tools/apply_premium_core_r2_second_pass_v2.py +++ /dev/null @@ -1,82 +0,0 @@ -from pathlib import Path -import re - -path = Path('assets/js/hero-premium-core-2-r2.js') -s = path.read_text(encoding='utf-8') - -if 'vec3 sail=q-vec3(-0.18,0.16,-0.34' in s and 'platformTopD' in s: - print('Premium Core R2 second pass already applied') - raise SystemExit(0) - - -def one(old, new, label): - global s - n = s.count(old) - if n != 1: - raise SystemExit(f'{label}: expected 1 match, found {n}') - s = s.replace(old, new, 1) - -one('vec3 a=q-vec3(0.08,0.00,0.015);','vec3 a=q-vec3(0.07,0.00,0.105);','internal outer') -one('vec3 b=q-vec3(0.045,-0.015,0.00);','vec3 b=q-vec3(0.035,-0.015,0.085);','internal mid') -one('vec3 c=q-vec3(0.075,-0.02,0.012);','vec3 c=q-vec3(0.060,-0.02,0.105);','internal kernel') -one('vec3 r=q-vec3(0.05,-0.01,-0.06);','vec3 r=q-vec3(0.04,-0.01,0.015);','internal rails') - -one('''vec3 upper=q-vec3(-0.03,0.34,0.42+0.025*shellMotion*sin(uTime*.24+0.3)); - upper.xy=rot(-0.34+0.025*shellMotion*sin(uTime*.14))*upper.xy; upper.xz=rot(0.10)*upper.xz; - float upperD=sdRoundBox(upper,vec3(0.34,0.090,0.055),0.052);''','''vec3 upper=q-vec3(-0.05,0.38,0.44+0.028*shellMotion*sin(uTime*.24+0.3)); - upper.xy=rot(-0.34+0.025*shellMotion*sin(uTime*.14))*upper.xy; upper.xz=rot(0.10)*upper.xz; - float upperD=sdRoundBox(upper,vec3(0.39,0.105,0.060),0.058);''','upper shell') -one('''vec3 lower=q-vec3(0.29,-0.29,0.39-0.020*shellMotion*sin(uTime*.18+1.7)); - lower.xy=rot(0.13-0.018*shellMotion*sin(uTime*.15))*lower.xy; lower.xz=rot(-0.13)*lower.xz; - float lowerD=sdRoundBox(lower,vec3(0.38,0.10,0.060),0.055);''','''vec3 lower=q-vec3(0.27,-0.31,0.405-0.022*shellMotion*sin(uTime*.18+1.7)); - lower.xy=rot(0.13-0.018*shellMotion*sin(uTime*.15))*lower.xy; lower.xz=rot(-0.13)*lower.xz; - float lowerD=sdRoundBox(lower,vec3(0.42,0.11,0.066),0.060);''','lower shell') - -anchor=''' if(bridgeD0.74){''' -insert=''' if(bridgeD0.74){''' -one(anchor,insert,'sail/brand insertion') - -pat=re.compile(r''' vec3 glassQ=q-vec3\(0\.09,0\.0,0\.03\);\n glassQ\.xy=rot\(0\.08\)\*glassQ\.xy;\n float glass=abs\(sdRoundBox\(glassQ,vec3\(0\.355,0\.455,0\.255\),0\.155\)\)-0\.018;\n glass=max\(glass,0\.105-glassQ\.z\);\n glass=max\(glass,glassQ\.x-0\.285\);\n glass=max\(glass,-glassQ\.x-0\.135\);\n if\(glass Date: Tue, 11 Aug 2026 04:19:22 -0700 Subject: [PATCH 62/69] Remove temporary Premium Core R2 capture patch helper --- tools/apply_premium_core_r2_capture_freeze.py | 53 ------------------- 1 file changed, 53 deletions(-) delete mode 100644 tools/apply_premium_core_r2_capture_freeze.py diff --git a/tools/apply_premium_core_r2_capture_freeze.py b/tools/apply_premium_core_r2_capture_freeze.py deleted file mode 100644 index b0c62249..00000000 --- a/tools/apply_premium_core_r2_capture_freeze.py +++ /dev/null @@ -1,53 +0,0 @@ -from pathlib import Path - -js_path = Path('assets/js/hero-premium-core-2-r2.js') -tool_path = Path('tools/hero_premium_core_2_owner_review.mjs') -js = js_path.read_text(encoding='utf-8') -tool = tool_path.read_text(encoding='utf-8') -changed = False - -if 'let captureFreeze = false;' not in js: - old = ''' let visible = true;\n let renderScale = 1;''' - new = ''' let visible = true;\n let captureFreeze = false;\n let renderScale = 1;''' - if old not in js: raise SystemExit('JS capture freeze state anchor missing') - js = js.replace(old, new, 1) - - old = ''' const visibilityObserver = new IntersectionObserver((entries) => { visible = entries.some((entry) => entry.isIntersecting); }, { threshold: 0.02 });\n visibilityObserver.observe(visual);''' - new = ''' const visibilityObserver = new IntersectionObserver((entries) => { visible = entries.some((entry) => entry.isIntersecting); }, { threshold: 0.02 });\n visibilityObserver.observe(visual);\n\n window.addEventListener('hero-core2:capture-freeze', (event) => {\n captureFreeze = Boolean(event.detail);\n });''' - if old not in js: raise SystemExit('JS visibility anchor missing') - js = js.replace(old, new, 1) - - old = ''' requestAnimationFrame(render);\n if (!visible || document.hidden) return;\n const delta = now - lastFrame;''' - new = ''' requestAnimationFrame(render);\n if (!visible || document.hidden) return;\n if (captureFreeze && !firstFrame) return;\n const delta = now - lastFrame;''' - if old not in js: raise SystemExit('JS render anchor missing') - js = js.replace(old, new, 1) - changed = True - -if "hero-core2:capture-freeze" not in tool: - old = ''' if (minVisualRatio && (diagnostics.visual?.viewportRatio || 0) < minVisualRatio) throw new Error(`${locale} ${width}x${height}: Core visibility ratio ${(diagnostics.visual?.viewportRatio || 0)} < ${minVisualRatio}`);\n await page.screenshot({ path: path.join(out, file), fullPage: false, timeout: screenshotTimeout });''' - new = ''' if (minVisualRatio && (diagnostics.visual?.viewportRatio || 0) < minVisualRatio) throw new Error(`${locale} ${width}x${height}: Core visibility ratio ${(diagnostics.visual?.viewportRatio || 0)} < ${minVisualRatio}`);\n await page.evaluate(() => window.dispatchEvent(new CustomEvent('hero-core2:capture-freeze', { detail: true })));\n await page.waitForTimeout(80);\n await page.screenshot({ path: path.join(out, file), fullPage: false, timeout: screenshotTimeout });''' - if old not in tool: raise SystemExit('captureStatic freeze anchor missing') - tool = tool.replace(old, new, 1) - - old = ''' if (!reduced.ready || reduced.active !== 3) throw new Error(`Reduced-motion state invalid: ${JSON.stringify(reduced)}`);\n await page.screenshot({ path: path.join(out, 'CORE2_EN_REDUCED_MOTION_390x844.png'), fullPage: false, timeout: screenshotTimeout });''' - new = ''' if (!reduced.ready || reduced.active !== 3) throw new Error(`Reduced-motion state invalid: ${JSON.stringify(reduced)}`);\n await page.evaluate(() => window.dispatchEvent(new CustomEvent('hero-core2:capture-freeze', { detail: true })));\n await page.waitForTimeout(80);\n await page.screenshot({ path: path.join(out, 'CORE2_EN_REDUCED_MOTION_390x844.png'), fullPage: false, timeout: screenshotTimeout });''' - if old not in tool: raise SystemExit('reduced freeze anchor missing') - tool = tool.replace(old, new, 1) - - old = ''' for (let i = 0; i < names.length; i += 1) {\n await stages.nth(i).click();\n await page.waitForTimeout(650);''' - new = ''' for (let i = 0; i < names.length; i += 1) {\n await page.evaluate(() => window.dispatchEvent(new CustomEvent('hero-core2:capture-freeze', { detail: false })));\n await stages.nth(i).click();\n await page.waitForTimeout(650);''' - if old not in tool: raise SystemExit('stage unfreeze anchor missing') - tool = tool.replace(old, new, 1) - - old = ''' if (active !== i) throw new Error(`Stage review capture mismatch for ${names[i]}: active ${active}`);\n await page.screenshot({ path: path.join(out, `CORE2_EN_STAGE_0${i + 1}_${names[i]}.png`), fullPage: false, timeout: screenshotTimeout });''' - new = ''' if (active !== i) throw new Error(`Stage review capture mismatch for ${names[i]}: active ${active}`);\n await page.evaluate(() => window.dispatchEvent(new CustomEvent('hero-core2:capture-freeze', { detail: true })));\n await page.waitForTimeout(80);\n await page.screenshot({ path: path.join(out, `CORE2_EN_STAGE_0${i + 1}_${names[i]}.png`), fullPage: false, timeout: screenshotTimeout });''' - if old not in tool: raise SystemExit('stage freeze anchor missing') - tool = tool.replace(old, new, 1) - changed = True - -if changed: - js_path.write_text(js, encoding='utf-8') - tool_path.write_text(tool, encoding='utf-8') - print('Capture freeze hook applied') -else: - print('Capture freeze hook already applied') From 8000cc00c3632f4f2862e3c533d27f662d350253 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 04:19:29 -0700 Subject: [PATCH 63/69] Remove temporary Premium Core R2 sculptural patch helper --- tools/apply_premium_core_r2_third_pass.py | 140 ---------------------- 1 file changed, 140 deletions(-) delete mode 100644 tools/apply_premium_core_r2_third_pass.py diff --git a/tools/apply_premium_core_r2_third_pass.py b/tools/apply_premium_core_r2_third_pass.py deleted file mode 100644 index 97b77de2..00000000 --- a/tools/apply_premium_core_r2_third_pass.py +++ /dev/null @@ -1,140 +0,0 @@ -from pathlib import Path - -path = Path('assets/js/hero-premium-core-2-r2.js') -s = path.read_text(encoding='utf-8') - -if 'sdFacetedSlab' in s and 'float lamella1=' in s: - print('Premium Core R2 third pass already applied') - raise SystemExit(0) - - -def one(old, new, label): - global s - n = s.count(old) - if n != 1: - raise SystemExit(f'{label}: expected 1 match, found {n}') - s = s.replace(old, new, 1) - -one( -' float sdRoundBox(vec3 p,vec3 b,float r){ vec3 q=abs(p)-b+r; return min(max(q.x,max(q.y,q.z)),0.0)+length(max(q,0.0))-r; }', -''' float sdRoundBox(vec3 p,vec3 b,float r){ vec3 q=abs(p)-b+r; return min(max(q.x,max(q.y,q.z)),0.0)+length(max(q,0.0))-r; } - float sdFacetedSlab(vec3 p,vec3 b,float r,float cut){ - float d=sdRoundBox(p,b,r); - d=max(d,(abs(p.x)+abs(p.y)-b.x-b.y)*0.7071-cut); - return d; - }''', -'faceted helper') - -# Architectural intelligence stack: thinner shells, layered lamellae, stronger negative space. -one('float outer=abs(sdRoundBox(a,vec3(0.315,0.410,0.220),0.135))-0.027;', - 'float outer=abs(sdFacetedSlab(a,vec3(0.335,0.400,0.105),0.050,0.040))-0.020;', - 'outer intelligence frame') -one('outer=max(outer,-sdRoundBox(a-vec3(0.23,0.02,0.16),vec3(0.20,0.20,0.13),0.08));', - 'outer=max(outer,-sdRoundBox(a-vec3(0.20,0.02,0.075),vec3(0.18,0.23,0.075),0.050));', - 'outer intelligence opening') -one('float mid=abs(sdRoundBox(b,vec3(0.235,0.315,0.165),0.105))-0.022;', - 'float mid=abs(sdFacetedSlab(b,vec3(0.255,0.305,0.082),0.042,0.032))-0.018;', - 'mid intelligence frame') -one('mid=max(mid,-sdRoundBox(b-vec3(-0.16,-0.02,0.12),vec3(0.13,0.18,0.11),0.07));', - 'mid=max(mid,-sdRoundBox(b-vec3(-0.13,-0.02,0.060),vec3(0.12,0.18,0.065),0.043));', - 'mid intelligence opening') -one('float kernel=sdRoundBox(c,vec3(0.125,0.215,0.105),0.072);', - 'float kernel=sdFacetedSlab(c,vec3(0.135,0.210,0.064),0.036,0.024);', - 'kernel faceting') -one('kernel=max(kernel,-sdRoundBox(c-vec3(0.00,0.015,0.08),vec3(0.052,0.130,0.055),0.035));', - 'kernel=max(kernel,-sdRoundBox(c-vec3(0.00,0.015,0.045),vec3(0.055,0.125,0.042),0.028));', - 'kernel aperture')\nanchor=''' if(kernel Date: Tue, 11 Aug 2026 04:19:36 -0700 Subject: [PATCH 64/69] Remove temporary Premium Core R2 apply workflow --- .../apply-premium-core-r2-second-pass.yml | 42 ------------------- 1 file changed, 42 deletions(-) delete mode 100644 .github/workflows/apply-premium-core-r2-second-pass.yml diff --git a/.github/workflows/apply-premium-core-r2-second-pass.yml b/.github/workflows/apply-premium-core-r2-second-pass.yml deleted file mode 100644 index 2a0eb284..00000000 --- a/.github/workflows/apply-premium-core-r2-second-pass.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: Apply Premium Core R2 second pass - -on: - push: - branches: - - agent/hero-premium-core-2-r1 - paths: - - tools/apply_premium_core_r2_second_pass.py - - .github/workflows/apply-premium-core-r2-second-pass.yml - workflow_dispatch: - -permissions: - contents: write - -jobs: - apply: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - ref: agent/hero-premium-core-2-r1 - fetch-depth: 0 - - name: Apply asserted R2 geometry patch - run: python3 tools/apply_premium_core_r2_second_pass.py - - name: Validate JavaScript syntax - run: node --check assets/js/hero-premium-core-2-r2.js - - name: Guard production routes - run: | - set -euo pipefail - if git diff --name-only | grep -Eq '^(index\.html|ru/index\.html)$'; then - echo 'Production route changed unexpectedly' >&2 - exit 1 - fi - - name: Commit second-pass shader refinement - run: | - set -euo pipefail - git config user.name 'ProAI Hero Agent' - git config user.email 'actions@users.noreply.github.com' - git add assets/js/hero-premium-core-2-r2.js - git diff --cached --quiet && { echo 'No second-pass changes to commit'; exit 1; } - git commit -m 'Refine Premium Core R2 silhouette and internal intelligence' - git push origin HEAD:agent/hero-premium-core-2-r1 From 8caf87cc14ac16f604d61a3936f3952e2552cad4 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 04:20:08 -0700 Subject: [PATCH 65/69] Restore Premium Core owner-review trigger marker --- .github/hero-premium-core-2-run.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/hero-premium-core-2-run.txt b/.github/hero-premium-core-2-run.txt index b48606ca..d66c96c8 100644 --- a/.github/hero-premium-core-2-run.txt +++ b/.github/hero-premium-core-2-run.txt @@ -1 +1 @@ -2026-08-11T04:14:00-07:00 owner-review QA trigger R2 sculptural pass +2026-08-11T02:16:00-07:00 owner-review QA trigger R2 From 82b104a9d0223b002e175638ad621d8c1eb75521 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 04:21:04 -0700 Subject: [PATCH 66/69] Remove stale Premium Core owner-review status record --- ...M_CORE_2_OWNER_REVIEW_STATUS_2026-08-11.md | 254 ------------------ 1 file changed, 254 deletions(-) delete mode 100644 docs/site-evolution/PROAI_HERO_PREMIUM_CORE_2_OWNER_REVIEW_STATUS_2026-08-11.md diff --git a/docs/site-evolution/PROAI_HERO_PREMIUM_CORE_2_OWNER_REVIEW_STATUS_2026-08-11.md b/docs/site-evolution/PROAI_HERO_PREMIUM_CORE_2_OWNER_REVIEW_STATUS_2026-08-11.md deleted file mode 100644 index 40f3de54..00000000 --- a/docs/site-evolution/PROAI_HERO_PREMIUM_CORE_2_OWNER_REVIEW_STATUS_2026-08-11.md +++ /dev/null @@ -1,254 +0,0 @@ -# ProAI Expert Hero — Premium Core 2.0 — Owner Review Status - -Date: 2026-08-11 -Status: **READY FOR OWNER REVIEW — NOT PRODUCTION AUTHORIZED** -Scope: **HERO ONLY / ISOLATED PREVIEW ONLY** - -Repository: `proaiexpert/proaiexpert.github.io` -Source/research branch: `agent/hero-layered-25d-static-r1` -Implementation branch: `agent/hero-premium-core-2-r1` -Draft owner-review PR: `#117` — base is the research/archive branch only - -## 1. Source of truth - -Implementation follows: - -- `docs/site-evolution/PROAI_HERO_NEXT_CHAT_PREMIUM_CORE_100K_BUILD_BRIEF_2026-08-11.md` -- `docs/site-evolution/PROAI_HERO_EN_COPY_LOCK_2026-08-11.md` -- `docs/site-evolution/PROAI_HERO_RU_COPY_LOCK_2026-08-11.md` - -The rejected simple machined/closed box direction was not reused as the active art direction. - -## 2. Copy lock execution — completed first - -Final EN/RU Hero copy and CTA locks were applied before Premium Core visual development. - -H1 remains one authored continuous string in both languages; no authored `
` or split slogan markup was introduced. - -Locked stage chains remain: - -- EN: `TRUST → INQUIRY → RESPONSE → RESULT` -- RU: `ДОВЕРИЕ → ОБРАЩЕНИЕ → ОТВЕТ → РЕЗУЛЬТАТ` - -Primary CTA locks remain: - -- EN: `Request a Review` -- RU: `Запросить разбор` - -## 3. Active owner-review routes - -- EN: `/hero-premium-core-2-preview/` -- RU: `/ru/hero-premium-core-2-preview/` - -These routes are isolated candidates only. They are not production `/` or `/ru/`. - -## 4. Active implementation - -### DOM / layout ownership - -- `hero-premium-core-2-preview/index.html` -- `ru/hero-premium-core-2-preview/index.html` -- `assets/css/hero-premium-core-2.css` -- `assets/css/hero-premium-core-2-r2.css` - -DOM owns: - -- header/navigation; -- eyebrow; -- H1/support copy; -- CTA/microcopy/accountability; -- accessible `01–04` stage typography; -- responsive/mobile composition. - -### WebGL2 ownership - -Active renderer: - -- `assets/js/hero-premium-core-2-r2.js` - -The active scene is procedural WebGL2 rather than the prior flattened Layered 2.5D PNG compositor. - -It contains: - -- asymmetric multi-mass sculptural Core geometry; -- open negative space rather than a closed product box; -- rear graphite spine, crown/upper shell mass, lower keel, detached output fin and floating collector/front masses; -- graphite / dark-steel material families; -- a restrained smoked aperture rather than a large rectangular screen; -- a contained internal intelligence volume with localized cyan rim/filament response; -- internal structural ribs/depth layers; -- transparent scene integration into one near-black Hero environment; -- non-concentric spline-derived signal trajectories; -- fragmented-to-resolved signal behavior; -- localized moving pulses and sparse data marks; -- Core/signal occlusion behavior; -- stage-driven orientation/state changes; -- pointer micro-parallax on fine-pointer devices; -- adaptive render scale / quality reduction under sustained slow frames; -- reduced-motion final-state behavior. - -## 5. Abstract Signal Field - -The rejected simple dotted ellipse/orbit treatment was not reused. - -The active field uses: - -- multiple non-concentric cubic trajectory families; -- broken-to-continuous line phases; -- localized pulses rather than uniform neon glow; -- depth/occlusion around the Core; -- restrained branching and sparse data marks; -- visual progression from fragmented input toward cleaner output/result states. - -## 6. Motion / journey behavior - -The normal Hero remains immediately readable; copy is not hidden behind an intro. - -The active choreography supports: - -1. `01 TRUST` -2. `02 INQUIRY` -3. `03 RESPONSE` -4. `04 RESULT` -5. continuing authored idle motion after resolution - -Stage changes affect DOM emphasis plus Core orientation/signal state. - -The four stages can also be activated by hover/focus/click/tap. The final QA independently verifies that the autonomous sequence resolves to stage index `3`, i.e. `04 RESULT`. - -Reduced-motion mode keeps the scene available but parks it in the stable final/result state rather than replaying the full sequence. - -## 7. Mobile recomposition - -Mobile is not a desktop shrink. - -The active mobile pass includes: - -- 390-class composition; -- 320px/narrow composition; -- short-landscape compaction; -- compact `01–04` journey row integrated with the mobile visual field; -- smaller Core visual zone on 390-class widths so copy, CTA, accountability, all four stages and the Core remain visible in the first owner-review frame in both EN and RU; -- reduced rendering scale/quality budget on small devices; -- no horizontal document overflow in browser QA. - -Manual review after the automated run specifically caught and corrected a 390px issue where stage labels could fall below the physical screenshot despite the WebGL area technically intersecting the viewport. The final 390-class captures now visibly include all `01–04` labels in both languages. - -## 8. Loading / fallback behavior - -The initial loading fallback was also reviewed against the rejection gate. - -A box-like fallback was rejected and replaced with an open asymmetric fallback composition so the page does not briefly regress to the rejected closed-box silhouette before WebGL becomes ready. - -## 9. Final automated/browser QA - -Final tested implementation commit: - -`b514e9ed74df63291614730c13c53dff5b5eae13` - -GitHub Actions run: - -`31481180408` - -Result: - -**SUCCESS** - -Final artifact: - -- name: `PROAI_HERO_PREMIUM_CORE_2_OWNER_REVIEW` -- artifact id: `9097364475` -- SHA-256 digest: `b375eea58a70c827a5f1141272a3208e6b06f01233d5add1a756cb71a5b6ee71` -- artifact size: `3,125,751` bytes -- retention: 14 days from the run - -The final package contains: - -- `CORE2_EN_DESKTOP_1440x900.png` -- `CORE2_RU_DESKTOP_1440x900.png` -- `CORE2_EN_MOBILE_390x844.png` -- `CORE2_RU_MOBILE_390x844.png` -- `CORE2_EN_MOBILE_320x780.png` -- `CORE2_EN_LANDSCAPE_844x390.png` -- `CORE2_EN_REDUCED_MOTION_390x844.png` -- `CORE2_EN_STAGE_01_TRUST.png` -- `CORE2_EN_STAGE_02_INQUIRY.png` -- `CORE2_EN_STAGE_03_RESPONSE.png` -- `CORE2_EN_STAGE_04_RESULT.png` -- `CORE2_EN_DESKTOP_MOTION.mp4` -- `diagnostics.json` - -Automated gates passed for: - -- production-route protection; -- exact EN/RU copy locks; -- no authored H1 hard split; -- Jekyll build; -- WebGL2 ready state; -- no fallback on tested Chromium captures after ready; -- no page/console errors in capture flow; -- no horizontal document overflow in tested viewports; -- desktop EN/RU captures; -- 390-class EN/RU captures; -- 320px narrow capture; -- 844×390 short-landscape capture; -- reduced-motion final-state behavior; -- autonomous narrative resolution to `04 RESULT`; -- four deterministic stage-state captures; -- desktop browser-native motion sample; -- active R2 implementation/static rejection guards. - -## 10. Final diagnostics summary - -Final browser diagnostics report: - -- EN desktop 1440×900: WebGL2 ready, fallback false, visual viewport ratio `1.0`, no horizontal overflow; -- RU desktop 1440×900: WebGL2 ready, fallback false, visual viewport ratio `1.0`, no horizontal overflow; -- EN 390-class capture: visual viewport ratio `1.0`, all `01–04` visible in manual capture review; -- RU 390-class capture: visual viewport ratio `1.0`, all `01–04` visible in manual capture review; -- EN 320/narrow capture: visual viewport ratio `1.0`; -- EN short-landscape capture: visual viewport ratio `1.0`; -- autonomous final stage: `3` = `04 RESULT`. - -## 11. Internal visual quality gate - -The first Premium Core implementation was not accepted merely because technical QA passed. It was revised because it still read too much like rounded box components around a cyan insert and exposed a visible WebGL panel boundary. - -Subsequent internal review also corrected: - -- overly closed Core readings in some angles; -- 320px composition; -- short-landscape fit; -- box-like loading fallback; -- 390-class stage visibility; -- owner-review motion/stage evidence. - -The active candidate now: - -- avoids a closed rectangular Core silhouette; -- avoids simple dotted ellipse/orbit graphics; -- avoids four floating glass feature cards; -- avoids a visible rectangular WebGL panel boundary; -- keeps cyan localized as intelligence/signal light rather than broad neon treatment; -- integrates the Core, signal field and stage journey into one near-black environment; -- preserves an open sculptural silhouette across the stage states; -- is materially richer and more authored than the older cube/orbit Hero engineering DNA. - -This is an **owner-review candidate** targeting the brief's bespoke premium digital / AI studio standard. The monetary `$100k+` class is an art-direction target, not an objectively measurable QA fact. - -## 12. Production safety — confirmed - -Comparison against `agent/hero-layered-25d-static-r1` confirms this implementation branch contains isolated Hero preview/assets/docs/workflow changes only. - -- Production `/index.html` was not modified by this Premium Core 2.0 pass. -- Production `/ru/index.html` was not modified by this Premium Core 2.0 pass. -- No production merge was performed. -- No production deploy was performed. -- No production-target PR was opened. -- Draft PR `#117` targets `agent/hero-layered-25d-static-r1`, not `main`. -- Existing C-shape/recovery/history files were not deleted. -- Financial Stream was not touched. - -Do not merge, retarget to production or deploy without explicit owner approval. - -**READY FOR OWNER REVIEW — NOT PRODUCTION AUTHORIZED** From 0284d1cce5b6587a180f1a99e29cb98fc78a819c Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 04:21:43 -0700 Subject: [PATCH 67/69] Bump isolated Premium Core R2 EN owner-review assets --- hero-premium-core-2-preview/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hero-premium-core-2-preview/index.html b/hero-premium-core-2-preview/index.html index 6a4bcef9..6510fbcc 100644 --- a/hero-premium-core-2-preview/index.html +++ b/hero-premium-core-2-preview/index.html @@ -13,7 +13,7 @@ - + Skip to main content @@ -77,6 +77,6 @@

From first impression to res - + \ No newline at end of file From 818f729165bf98e937e92d00cfa2510034f79c6d Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 04:22:08 -0700 Subject: [PATCH 68/69] Bump isolated Premium Core R2 RU owner-review assets --- ru/hero-premium-core-2-preview/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ru/hero-premium-core-2-preview/index.html b/ru/hero-premium-core-2-preview/index.html index 1894713b..79b35f6e 100644 --- a/ru/hero-premium-core-2-preview/index.html +++ b/ru/hero-premium-core-2-preview/index.html @@ -13,7 +13,7 @@ - + Перейти к содержимому @@ -77,6 +77,6 @@

От первого впеч - + \ No newline at end of file From 94b4be04aa090b6c2c916ce318f216ddd4cb9d94 Mon Sep 17 00:00:00 2001 From: Ihor Horb Date: Tue, 11 Aug 2026 10:37:29 -0700 Subject: [PATCH 69/69] Add Hero R3 visual breakthrough next-chat brief --- ...BREAKTHROUGH_NEXT_CHAT_BRIEF_2026-08-11.md | 735 ++++++++++++++++++ 1 file changed, 735 insertions(+) create mode 100644 docs/site-evolution/PROAI_HERO_R3_VISUAL_BREAKTHROUGH_NEXT_CHAT_BRIEF_2026-08-11.md diff --git a/docs/site-evolution/PROAI_HERO_R3_VISUAL_BREAKTHROUGH_NEXT_CHAT_BRIEF_2026-08-11.md b/docs/site-evolution/PROAI_HERO_R3_VISUAL_BREAKTHROUGH_NEXT_CHAT_BRIEF_2026-08-11.md new file mode 100644 index 00000000..9fdc4c94 --- /dev/null +++ b/docs/site-evolution/PROAI_HERO_R3_VISUAL_BREAKTHROUGH_NEXT_CHAT_BRIEF_2026-08-11.md @@ -0,0 +1,735 @@ +# PROAI EXPERT HERO — R3 VISUAL BREAKTHROUGH — NEXT CHAT BUILD BRIEF + +Date: 2026-08-11 +Repository: `proaiexpert/proaiexpert.github.io` +Current source branch: `agent/hero-premium-core-2-r1` +Current R2 owner-review commit: `818f729165bf98e937e92d00cfa2510034f79c6d` +Current R2 owner-review Actions run: `31486321055` +Current R2 owner-review artifact: `9099403801` + +## 0. PURPOSE OF THIS BRIEF + +This is a fresh-chat handoff for the next Hero pass. + +Do **not** restart the whole website, do **not** reopen the copy, and do **not** do another cautious micro-refinement of R2. + +The next pass is: + +**R3 — VISUAL BREAKTHROUGH PASS** + +The goal is to break out of the current loop where the implementation becomes technically more complex but the visual result still looks almost the same and too simple. + +The owner’s current judgment is clear: + +- current production Hero still feels richer and more alive than the proposed replacements; +- R1/R2 Core candidates are technically competent but visually too thin, too cautious, too simple, and not sufficiently premium; +- stage plates are too small / weak; +- the Core lacks depth, layered geometry, material richness, visible motion, halo/grounding, and a convincing signature-object presence; +- the next version must create a **large perceptual jump**, not a 5–10% polish pass. + +Target quality: + +**bespoke premium digital / AI studio Hero at the level expected from a $100k+ custom interactive website.** + +This does NOT mean sterile minimalism. It means strong art direction, authored 3D, real depth, rich but controlled effects, excellent materials, meaningful motion, and a clear hierarchy. + +--- + +# 1. HARD LOCKS — DO NOT CHANGE + +## 1.1 Production + +Do not change, merge, or deploy production `/index.html` or `/ru/index.html`. + +R3 must remain an isolated owner-review candidate until explicit owner approval. + +## 1.2 Header / left-side Hero communication + +Keep the real existing Header System. + +Do not invent a new navigation, new claims, new stats, new technology logo rows, new service sections, new proof blocks, or any other page content. + +The left editorial side is already approved structurally. The work is primarily the **3D visual system + stage presentation + motion/effects integration**. + +## 1.3 RU copy lock — exact + +Eyebrow: +`AI-СИСТЕМЫ · АВТОМАТИЗАЦИЯ · ПРЕМИАЛЬНЫЕ САЙТЫ` + +H1: +`От первого впечатления до результата — одна система.` + +Support: +`Создаём премиальные сайты для компаний сферы услуг и соединяем их с AI и автоматизацией. Клиенту проще понять ваши услуги и обратиться с нужной информацией, вам — быстрее ответить и меньше заниматься рутиной. Ключевые решения — за вами.` + +Primary CTA: +`Запросить разбор` + +Microcopy: +`Коротко опишите задачу. Мы предложим, с чего разумнее начать.` + +Secondary CTA: +`Смотреть проекты` + +Accountability: +`Штат Вашингтон · Работаем по всей США · EN / RU / UA` + +Stages: +`01 ДОВЕРИЕ` +`02 ОБРАЩЕНИЕ` +`03 ОТВЕТ` +`04 РЕЗУЛЬТАТ` + +## 1.4 EN copy lock — exact + +Eyebrow: +`AI SYSTEMS · AUTOMATION · PREMIUM WEBSITES` + +H1: +`From first impression to result — one system.` + +Support: +`We build premium websites for service businesses and connect them with AI and automation. Customers understand your services and reach out with the right information; you respond faster and spend less time on routine work. Key decisions stay with you.` + +Primary CTA: +`Request a Review` + +Microcopy: +`Briefly describe the challenge. We’ll recommend where to start.` + +Secondary CTA: +`View Work` + +Accountability: +`Washington-based · Working across the U.S. · EN / RU / UA` + +Stages: +`01 TRUST` +`02 INQUIRY` +`03 RESPONSE` +`04 RESULT` + +No artificial `
` in the H1. + +--- + +# 2. WHAT TO PRESERVE FROM R2 + +Preserve what is already useful: + +- isolated EN/RU preview architecture; +- real DOM for all copy, CTAs, accessibility, and stages; +- current responsive / reduced-motion discipline; +- current QA approach and owner-review artifact generation; +- near-black ProAI world; +- graphite / gunmetal / smoked-material family; +- cyan as the main intelligence / signal accent; +- 4-stage customer journey meaning; +- the idea of a central signature Core; +- depth/occlusion and signal-flow logic; +- the good parts of the R2 runtime/fallback if they remain useful. + +But **do not preserve R2 geometry merely because it already exists**. + +Preserve architecture, copy, meaning, accessibility, QA discipline and production safety — **not the current silhouette**. + +--- + +# 3. CREATIVE FREEDOM — IMPORTANT + +This pass must not be over-constrained into another safe result. + +You have explicit permission to make **large visual changes** inside the visual zone. + +You may: + +- redesign the Core geometry substantially; +- replace the current SDF Core if it limits premium material / motion / layered-object quality; +- move to a procedural Three.js mesh-based Core if that gives a materially better browser result; +- build the scene from multiple synchronized 3D groups rather than one monolithic object; +- redesign the stage plates substantially while preserving their exact locked text; +- use glow, halo, pulses, fragmented lines, micro-particles, glass, metal, multiple moving layers, light spills, optical effects and post-processing where they improve the result; +- invent a stronger visual system as long as it remains recognizably ProAI, browser-realistic, performant, and faithful to the customer-journey story. + +Do **not** interpret earlier recommendations such as “avoid particles / orbit / glow / rotation” as absolute bans. + +The real rule is: + +**avoid generic or cheap execution, not visual richness.** + +The scene may be visually rich and animated. It must simply have hierarchy and authored intent. + +--- + +# 4. PRIMARY VISUAL DIRECTION — PROAI CORE 3.0 + +The preferred direction is a **near-black sculptural system object with cube lineage**, not a closed cube and not an arbitrary organic blob. + +The object should feel like a proprietary ProAI signature device / architecture — something that could only belong to this brand. + +It should be visually understandable as one coherent system, but physically composed from several moving sub-systems. + +## 4.1 Three visual layers + +Use this as a conceptual architecture, not a rigid mesh recipe. + +### Layer A — Outer Architecture + +Create a strong outer silhouette from approximately 8–12 large authored masses, for example: + +- broad rear sail / back mass; +- crown / upper architecture; +- keel / lower architecture; +- asymmetric side shell masses; +- one or two front plates; +- structural bridge / spine; +- independent output element; +- integrated branded surface. + +Requirements: + +- clear cube / engineered-object ancestry; +- substantial negative space between masses; +- real depth separation; +- strong faceting / bevel language; +- no random “stack of phones” look; +- no closed-box silhouette; +- no hundreds of tiny meaningless mechanical details. + +The silhouette must be premium **before effects are added**. + +### Layer B — Inner Intelligence Architecture + +Inside the shell, create a separate architectural intelligence system such as: + +- 4–6 nested rectangular / faceted frames; +- 2–4 suspended smoked-glass lamellae; +- internal rails / bridge structures; +- a restrained cyan kernel / intelligence volume; +- layered depth, not one glowing blob. + +The inner architecture must be visibly separate from the outer shell and capable of independent motion. + +Avoid: + +- egg / lens / reactor look; +- one bright cyan cube; +- “500 cubes inside a cube.” + +The goal is **layered intelligence**, not visual clutter. + +### Layer C — Optical / Signal System + +Use a third visual layer for motion and information flow: + +- approximately 3 main asymmetric spatial trajectories; +- 2–3 secondary fragments; +- moving signal pulses; +- selective segmented/dotted sections; +- limited micro-points / particles; +- local halo / atmospheric spill; +- platform reflection / contact light; +- depth-based occlusion around / behind the Core. + +Do not make one giant planet-orbit ellipse. + +Do not eliminate trajectories simply because orbit clichés exist. Transform them into a more authored **abstract signal field**. + +--- + +# 5. MATERIAL QUALITY — MUST CREATE REAL DEPTH + +The R2 material language is too flat / cautious. + +The R3 object should read as physically plausible premium material under moving light. + +If using Three.js / mesh-based rendering, prefer physically based materials and studio-style image-based lighting / environment reflections. + +Target material families: + +- almost-black graphite metal; +- darker gunmetal; +- selected cold-steel edges / facets; +- smoked glass / dark transmission where useful; +- controlled cyan emissive intelligence; +- microscopic silver / warm physical reflection only as natural light response, not as a second brand color. + +Important: + +- moving specular highlights should reveal form; +- bevels / edge catches matter more than decorative detail count; +- metal surfaces must not read like matte plastic; +- glass must have depth and should not become a generic transparent neon cube. + +Post-processing may be used **after** geometry/materials/motion work: + +- selective cyan bloom; +- restrained AO / SSAO if performant; +- subtle tone mapping / filmic response; +- micro grain if it improves integration; +- extremely subtle chromatic aberration only if genuinely beneficial. + +Post effects must never be used to hide weak geometry. + +--- + +# 6. MOTION — MUST BE VISIBLY REAL, NOT BRIGHTNESS ANIMATION + +The owner reviewed the R2 motion and perceived the Core as almost static. + +R3 must contain **obvious physical 3D movement**. + +A 20–30 second owner-review video must clearly show angular change, internal parallax and changing depth — not merely changing brightness or active cards. + +Use multiple motion systems with different inertia / timing, for example: + +- slow weighty rotation / drift of the outer Core; +- independent inner-frame counter-motion; +- lamellae separation / breathing / depth shift; +- independent output-element movement; +- stage-driven orientation targets; +- soft camera parallax from pointer on capable desktop devices; +- moving signal pulses and optical response. + +As a starting point, not a hard lock: + +- outer architecture can take roughly 30–45 seconds for a full-equivalent rotation / major cycle; +- inner architecture can use a different 22–35 second cycle or partial counter-rotation; +- small sub-elements should move less and more slowly than the main Core; +- pointer/camera response should have inertia / spring-like damping, not direct mouse-follow. + +The object should feel heavy, expensive and alive. + +Do not make frantic spinning or gaming motion. + +Do not reduce motion until it becomes visually irrelevant. + +--- + +# 7. SCALE / PRESENCE — R3 MUST FEEL BIGGER + +On desktop, the Core and its immediate aura should dominate the right visual field. + +As a target range, the Core + immediate halo can occupy roughly **65–75% of the visual zone** when viewed at 1440×900. + +This is not a hard pixel lock; use visual judgment. + +The important criterion: + +**the Core must be the unmistakable hero object, not a small illustration surrounded by empty canvas.** + +The scene can use depth overflow, foreground fragments and rear layers to feel larger than the object itself. + +--- + +# 8. GROUNDING / PLATFORM / HALO — MUST BE VISIBLE + +R2 contains grounding in code but it is too weak to materially affect perception. + +R3 should have a visible but elegant grounding system. + +Possible direction: + +- low graphite receiver / platform; +- 2 restrained layered levels; +- subtle bevel / ring geometry; +- deep contact shadow; +- cyan reflection / light pool under the Core; +- local atmosphere / halo around and behind the object. + +Do not create a giant spaceship pedestal. + +But the platform / grounding must be **visually present in the screenshot**, not merely detectable in CSS or shader parameters. + +Likewise, halo / aura must be visible to the eye while remaining premium and controlled. + +--- + +# 9. PROAI BRAND MARK — KEEP IT BESPOKE + +Integrate a subtle ProAI mark into one external surface. + +Preferred behavior: + +- etched / embossed / inset mark; +- graphite-on-graphite / dark silver; +- not a bright glowing billboard; +- catches a specular highlight during rotation and becomes clearly readable for a few seconds, then recedes again. + +A small brand mark is preferable to a large `ProAI Expert` label painted on the object. + +--- + +# 10. STAGE PLATES — REDESIGN THEM AS PREMIUM OBJECTS + +R2 plates are still visually too small / weak. + +Do not merely increase them by 5%. + +On desktop, target perceived scale roughly in this range: + +- inactive plate width: approximately 200–220 px; +- active perceived width: approximately 225–245 px via size / scale / depth; +- active scale can be around 1.07–1.10 rather than ~1.035; +- number: approximately 22–26 px; +- heading: approximately 13–15 px; +- microcopy: approximately 11–12 px with readable line-height. + +These are starting targets, not rigid design tokens. Adjust if composition demands it. + +The plates should feel like **pieces of the same material system as the Core**, for example: + +- graphite outer plate; +- smoked inset / depth layer; +- metallic edge / bevel cue; +- cyan active seam / anchor; +- meaningful shadow / depth response; +- no generic SaaS icons. + +Inactive plates should remain readable and premium. + +Active plate should visibly lift / move / brighten / deepen enough that the state change is obvious. + +Do not use 8–9 px uppercase microcopy on desktop. + +--- + +# 11. STAGE COMPOSITION — CREATIVE CHOICE, BUT MEANING MUST BE CLEAR + +There are two credible directions: + +### Direction A — 2 + 2 spatial journey (preferred if executed well) + +Left / input side: +`01 TRUST / ДОВЕРИЕ` +↓ +`02 INQUIRY / ОБРАЩЕНИЕ` + +Then through the Core. + +Right / output side: +`03 RESPONSE / ОТВЕТ` +↓ +`04 RESULT / РЕЗУЛЬТАТ` + +This can be more bespoke and integrated than a generic vertical timeline. + +If using 2+2, make the meaning explicit with a visible progression layer: + +`01 → 02 → CORE → 03 → 04` + +The top/bottom relationship must feel intentional, not decorative. + +### Direction B — right-side sequential stack + +A vertical sequence may be used if it proves clearly stronger in actual composition. + +Do not select it merely because it is safer. + +### Requirement + +The agent may quickly test both layouts in a temporary comparison, but should choose and ship the one that best balances: + +- immediate 01→04 comprehension; +- premium composition; +- Core prominence; +- integration with signal flow; +- desktop/mobile adaptability. + +Do not ask the owner to decide before making a strong recommendation. + +--- + +# 12. ENGINE / IMPLEMENTATION FREEDOM + +The current R2 is a live WebGL2 SDF/ray-marched implementation, not a pre-rendered video. + +Do not misdiagnose it as a video. + +However, the owner and reviewers see a real problem: technical SDF complexity is not translating into enough visible premium complexity. + +Therefore: + +**R3 is allowed to replace the visual engine inside the canvas if that materially improves the result.** + +Recommended default to evaluate: + +**DOM + procedural Three.js mesh Core + layered WebGL effects** + +because it can provide: + +- real separate 3D groups; +- independent transform/motion per group; +- PBR material response; +- environment reflections; +- better specular / bevel readability; +- easier real camera parallax; +- clearer separation between outer shell, inner intelligence and optical layers. + +But this is a recommendation, not dogma. + +If the current WebGL2/SDF engine can genuinely produce the stronger target, it may be retained. + +The decision criterion is **browser result quality**, not sunk cost or framework preference. + +Do not use a pre-rendered video as the main Hero visual. + +Do not require Blender or a manually sculpted external asset for the first R3 pass. Prefer code-authored / procedural browser-real geometry so the result is actually maintainable by this project. + +If a small GLB asset later proves necessary, treat that as a future option, not an excuse to block R3. + +--- + +# 13. DOM + WEBGL INTEGRATION + +All real text remains DOM. + +Stage plates remain DOM / accessible controls, even if visually tied to 3D anchors. + +Prefer stronger visual integration between DOM and 3D: + +- project 3D anchor positions to screen coordinates if useful; +- share active-stage state between Core and plates; +- allow Core intensity / stage state to influence plate edge-light / CSS variables; +- use short physical connectors / signal transitions rather than huge decorative arcs. + +The visual should feel like one scene, not “WebGL picture + HTML cards pasted on top.” + +--- + +# 14. SIGNAL FLOW / NARRATIVE + +The visual meaning remains: + +`TRUST → INQUIRY → RESPONSE → RESULT` + +or + +`ДОВЕРИЕ → ОБРАЩЕНИЕ → ОТВЕТ → РЕЗУЛЬТАТ` + +The system should visually suggest: + +1. premium digital presence / trust; +2. useful inquiry / context entering the system; +3. AI + automation organizing / processing inside the Core; +4. faster, clearer response; +5. completion / result. + +A short autonomous narrative may run, followed by a living idle state. + +Do not let stage animation become the only visible motion. + +The Core itself must remain visibly alive throughout. + +--- + +# 15. PERFORMANCE / MOBILE / REDUCED MOTION + +Premium does not excuse a broken runtime. + +Maintain production-safe discipline: + +- adaptive DPR if needed; +- pause / reduce rendering when offscreen or hidden; +- desktop may use richer geometry/effects than mobile; +- mobile should be deliberately recomposed, not simply scaled down; +- reduced-motion should preserve a premium static composition and stable Stage 04 result state; +- no horizontal overflow; +- no unreadable stage text; +- no blocking main-thread animation loops. + +But do not design desktop to the visual limitations of the weakest mobile tier. + +Desktop is allowed to be substantially richer. + +--- + +# 16. PROCESS — DO NOT SPEND HOURS BEFORE PROVING THE VISUAL JUMP + +## Gate 0 — Baseline + +Capture / retain R2 desktop reference and current production Hero reference. + +The new pass must not accidentally become visually weaker than current production in motion/depth/energy. + +## Gate 1 — Core-only breakthrough + +Before stage plates and signal field, create the new Core with: + +- final-ish silhouette; +- basic premium material response; +- real multi-layer motion; +- camera/framing. + +Capture 1440×900 still + short motion sample. + +If the Core alone still looks like a small simple abstract object, **stop and redesign it**. + +Do not hide a weak Core with effects. + +## Gate 2 — Materials / internal intelligence / grounding + +Add: + +- material separation; +- inner architecture; +- platform / contact light; +- visible halo; +- ProAI mark. + +Again evaluate visually before stages. + +## Gate 3 — stage composition + +Add premium plates and choose 2+2 vs right stack based on actual result. + +## Gate 4 — signal / optical layer + +Add trajectories, pulses, fragments, micro-particles, selective bloom / optical effects. + +## Gate 5 — final motion and responsive QA + +Tune full narrative / idle / pointer / reduced motion / mobile. + +--- + +# 17. PERCEPTUAL ACCEPTANCE CRITERIA — MOST IMPORTANT + +R3 is NOT accepted merely because code changed a lot. + +The pass succeeds only if the **visual difference is large and immediate**. + +## Side-by-side rule + +Place R2 and R3 desktop screenshots side by side. + +If a normal viewer cannot see a substantial premium upgrade within **1–2 seconds**, R3 has failed. + +The expected first-glance difference should include most of the following: + +- Core is larger / more authoritative; +- silhouette is clearly more bespoke; +- real layered depth is visible; +- outer / inner systems are distinguishable; +- physical motion is obvious in video; +- material response is richer; +- platform / grounding is visible; +- halo / optical atmosphere is visible; +- stage plates are materially larger and more premium; +- signal flow is clearer; +- ProAI branding is integrated; +- the scene feels richer than current R2 and at least as alive as the older production Hero. + +Do not report “added X” if X is visually imperceptible. + +The owner judges the **screen**, not the source code. + +--- + +# 18. ART-DIRECTION HIERARCHY + +Multiple effects are allowed, but their hierarchy should remain: + +1. **Core / signature object** +2. **Inner intelligence / material depth** +3. **Journey / stage plates** +4. **Signal field / flow** +5. **Halo / particles / optical micro-effects** + +This is the difference between rich premium work and visual noise. + +Do not reduce the scene to one effect. + +Do not let every effect shout at equal volume. + +--- + +# 19. THINGS TO AVOID + +Avoid these outcomes, not creativity itself: + +- another nearly identical R2 screenshot with slightly changed opacity; +- closed simple box; +- random pile of disconnected slabs; +- 500 small cubes inside a cube; +- static Core with only text-card cycling; +- giant planet-orbit ellipse; +- particle soup; +- Tron / gaming neon; +- large gold secondary palette; +- generic SaaS cards/icons; +- giant machinery with meaningless detail; +- post-processing used as a substitute for shape/material quality; +- pre-rendered loop replacing real interaction; +- production merge/deploy without owner approval. + +--- + +# 20. FINAL DELIVERABLES + +Work on a new isolated branch created from R2 commit `818f729165bf98e937e92d00cfa2510034f79c6d`. + +Suggested branch name: + +`agent/hero-premium-core-3-breakthrough-r1` + +Create separate R3 isolated preview routes rather than overwriting production. + +At minimum deliver: + +- RU desktop 1440×900 screenshot; +- EN desktop 1440×900 screenshot; +- R2 vs R3 side-by-side desktop comparison; +- Core-only Gate 1 screenshot; +- materials/grounding Gate 2 screenshot; +- all four stage states; +- RU mobile 390×844; +- EN mobile 390×844; +- 320×780; +- short landscape 844×390; +- reduced-motion screenshot; +- 25–35 second desktop motion capture where actual Core motion is clearly visible; +- diagnostic / QA report. + +Final response must state: + +- branch; +- final commit SHA; +- Actions run ID / status; +- artifact ID; +- exact changed files; +- visual engine chosen and why; +- what was deliberately removed / replaced from R2; +- what was preserved; +- what makes the perceptual delta visibly larger than R2; +- confirmation that production was not changed / merged / deployed. + +--- + +# 21. FINAL OWNER INTENT + +Do not approach R3 as a conservative engineer polishing a finished object. + +Approach it as a senior creative developer / 3D art director who has a working technical foundation but has been told that the visual result is not yet strong enough. + +The owner explicitly wants: + +- more depth; +- more layering; +- more motion; +- stronger premium materials; +- more substantial stage plates; +- more visible atmosphere / halo / grounding; +- more sophisticated 3D composition; +- more creative ambition; +- a result that feels bespoke rather than safe. + +Use the constraints as **guardrails**, not as an excuse to simplify. + +You are expected to make creative decisions, test them in the browser, reject weak ideas yourself, and deliver the strongest feasible R3 candidate without asking the owner to re-provide earlier research or handoffs. + +**The objective is not “R2, but slightly better.”** + +The objective is: + +**a clearly new visual tier while preserving the already-approved ProAI Hero communication and system meaning.**