",
"@type": "SoftwareApplication",
"name": "MCP Bridge",
"description": "Auto-generate Model Context Protocol tool definitions from any REST, GraphQL, SOAP, or gRPC API. Connect any API to any AI agent without creating long-term technical debt.",
"url": "/",
"applicationCategory": "DeveloperApplication",
"operatingSystem": "Docker, AWS ECS, Azure Container Apps",
"offers": {
"@type": "Offer",
"price": "0",
"priceCurrency": "USD",
"description": "Free trial available, no credit card required"
},
"featureList": [
"Auto-generate MCP tools from OpenAPI, GraphQL, WSDL, and gRPC schemas",
"Self-hosted Docker container deployment",
"Code Mode reduces context window usage by 98%",
"Enterprise authentication (OAuth2, AWS Cognito, OIDC)",
"Tool curation and response post-processing",
"Analytics dashboard with latency, throughput, and token usage metrics",
"Semantic tool search with pgvector",
"Built in Rust for memory safety and high throughput"
],
"softwareRequirements": "Docker, AWS ECS, Azure Container Apps, or any container orchestrator",
"inLanguage": "en",
"provider": {
"@type": "Organization",
"name": "AppFactor"
},
"availableOnDevice": [
"AWS Marketplace",
"Microsoft Azure Marketplace"
]
}
[data-accordion-status="active"] .accordion-css__item-bottom {
grid-template-rows: 1fr;
}
/* Animate Icon */
.accordion-css__item-icon {
transition: transform 0.6s cubic-bezier(0.625, 0.05, 0, 1);
}
[data-accordion-status="active"] .accordion-css__item-icon {
transform: rotate(45deg);
}
a {
color: inherit;
}
@media only screen and (max-width: 999px) {
a {
cursor: default;
}
}
*:focus {
outline: 0 !important;
}
{
-webkit-tap-highlight-color: transparent;
}
/* Для Chrome/Safari/Opera /
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:-webkit-autofill:active {
-webkit-box-shadow: 0 0 0 0px var(--dark-grey) inset !important; / Цвет фона /
-webkit-text-fill-color: var(--black) !important; / Цвет текста /
transition: background-color 5000s ease-in-out 0s; / Долгая transition предотвращает мгновенное изменение стиля */
}
/* Для Firefox */
input:autofill,
input:autofill:hover,
input:autofill:focus,
input:autofill:active {
box-shadow: 0 0 0 0px var(--dark-grey) inset !important;
-webkit-text-fill-color: var(--black) !important;
}
.is__ov-h {
-webkit-mask-image: -webkit-radial-gradient(white, black);
}
/* To get this shitty padding-bottom/padding-right 75px bug removed */
.wf-design-mode .wf-empty,
.wf-editor-mode .wf-empty {
padding: 0;
}
/* General sizes */
:root {
font-size: clamp(12px, 1.1111vw, 20px);
}
/* Min Font Size */
@media screen and (max-width: 991px) {
:root {
font-size: 2.0833333333333335vw;
}
}
@media screen and (max-width: 479px) {
:root {
font-size: 4.266666666666667vw;
}
}
/* Container Max Width */
.container {
max-width: 90rem;
}
/* Max Font Size */
@media screen and (min-width: 1440px) {
:root {
font-size: 16px;
}
}
/* Easings */
:root {
--elastic-ease-out: linear(
0,
0.5737 7.6%,
0.8382 11.87%,
0.9463 14.19%,
1.0292 16.54%,
1.0886 18.97%,
1.1258 21.53%,
1.137 22.97%,
1.1424 24.48%,
1.1423 26.1%,
1.1366 27.86%,
1.1165 31.01%,
1.0507 38.62%,
1.0219 42.57%,
0.9995 46.99%,
0.9872 51.63%,
0.9842 58.77%,
1.0011 81.26%,
1
);
--smooth-ease: cubic-bezier(0.32, 0.72, 0, 1);
--color-ease: cubic-bezier(0.215, 0.61, 0.355, 1);
}
/* Btns */
.btn_txt-hvr {
translate: 0 1.9rem;
}
.btn_txt-hvr-b {
translate: 0 1.9rem;
}
.btn_arrow-hvr {
translate: -1.9rem 1.9rem;
}
.btn_arrow-hvr-b {
translate: 1.9rem 1.9rem;
}
.btn,
.btn-s {
transition: background-color 0.65s var(--color-ease);
-webkit-tap-highlight-color: transparent;
}
.btn-outline,
.btn-s-outline,
.btn-back {
transition: border-color 0.65s var(--color-ease);
-webkit-tap-highlight-color: transparent;
}
.btn_txt,
.btn_txt-hvr,
.btn_txt-hvr-b,
.btn_arrow,
.btn_arrow-hvr,
.btn_arrow-hvr-b,
.usecases__arrow-hover,
.usecases__arrow {
transition: translate 0.95s var(--elastic-ease-out);
}
/* Use Cases Card And Blog Card*/
.usecases__arrow-hover {
translate: -1.3rem 1.3rem;
}
.usecases__border,
.pl-blog__card {
transition:
transform 0.65s var(--elastic-ease-out),
border-color 0.65s var(--color-ease);
}
/* FAQ */
.faq__item {
transition: background-color 0.65s var(--color-ease);
}
.faq__border {
transition:
transform 0.95s var(--elastic-ease-out),
border-color 0.65s var(--color-ease);
}
.faq__answ {
transition: max-height 0.95s var(--smooth-ease);
}
.faq__line-v {
transition: transform 0.95s var(--elastic-ease-out);
}
.faq__item.is-act .faq__answ {
max-height: 9rem;
}
@media screen and (max-width: 479px) {
.faq__item.is-act .faq__answ {
max-height: 14rem;
}
}
.faq__item.is-act .faq__border {
border-color: rgba(255, 255, 255, 0);
}
.faq__item.is-act .faq__line-v {
transform: rotate(90deg);
}
/* Underline Link */
.underline-link {
-webkit-tap-highlight-color: transparent;
}
.underline-link::before {
content: "";
position: absolute;
bottom: -1px;
left: 0;
width: 100%;
height: 1px;
background-color: var(--orange);
transition: transform 0.75s cubic-bezier(0.625, 0.05, 0, 1);
transform-origin: right;
transform: scaleX(0) rotate(0.001deg);
}
/* Socials */
.footer__social,
.bl-main__social {
transition: color 0.65s var(--color-ease);
}
/* Footer Form */
.footer__input {
transition:
color 0.65s var(--color-ease),
border-color 0.65s var(--color-ease);
}
.footer__btn {
transition: background-color 0.65s var(--color-ease);
}
/* Nav Cases, Nav Comapny */
.nav__dl-wrap,
.nav-dd__btm {
translate: 0 -2rem;
transition:
opacity 0.65s var(--color-ease),
translate 0.65s var(--smooth-ease);
}
.nav__dl-img {
transition: opacity 0.65s var(--color-ease);
}
.nav__dl-link {
transition:
opacity 0.65s var(--color-ease),
border-color 0.65s var(--color-ease);
}
.nav__cases .is-nav,
.txt-c-white.underline-link {
transition: color 0.65s var(--color-ease);
cursor: pointer;
}
/* Video */
.cta__video video {
position: absolute;
top: 50%;
left: 50%;
min-width: 100%;
min-height: 100%;
width: auto;
height: auto;
transform: translate(-50%, -50%);
object-fit: cover;
}
.swiper-slide.is-f-l,
.swiper-slide.is-obs-hiw-l {
transition:
color 0.65s var(--color-ease),
background-color 0.65s var(--color-ease);
}
/* Progress Bar Animation */
.features__progress {
transition: width 0.5s var(--smooth-ease);
}
@keyframes progressAnimation {
0% {
width: 0;
}
98% {
width: 100%;
}
100% {
width: 0;
}
}
.features__progress.animate-progress {
animation: progressAnimation 9.6s linear forwards;
}
.main__vid {
border: 3px solid var(--black);
border-radius: 12px;
}
/* Все hover эффекты в одном медиа-запросе /
@media (hover: hover) and (pointer: fine) {
/ Main Btn */
.btn:is(:hover, :focus-visible) {
background: var(--orange);
}
.btn:is(:hover, :focus-visible) .btn_txt {
translate: 0 -1.9rem;
}
.btn:is(:hover, :focus-visible) .btn_arrow-hvr {
translate: 0 0;
}
.btn:is(:hover, :focus-visible) .btn_arrow {
translate: 1.9rem -1.9rem;
}
.btn:is(:hover, :focus-visible) .btn_txt-hvr {
translate: 0 0;
}
/* Outline Btn */
.btn-outline:is(:hover, :focus-visible),
.btn-back:is(:hover, :focus-visible) {
border-color: var(--white-40);
}
.btn-outline:is(:hover, :focus-visible) .btn_txt,
.btn-back:is(:hover, :focus-visible) .btn_txt {
translate: 0 -1.9rem;
}
.btn-outline:is(:hover, :focus-visible) .btn_arrow-hvr,
.btn-back:is(:hover, :focus-visible) .btn_arrow-hvr-b {
translate: 0 0;
}
.btn-outline:is(:hover, :focus-visible) .btn_arrow {
translate: 1.9rem -1.9rem;
}
.btn-back:is(:hover, :focus-visible) .btn_arrow {
translate: -1.9rem -1.9rem;
}
.btn-outline:is(:hover, :focus-visible) .btn_txt-hvr,
.btn-back:is(:hover, :focus-visible) .btn_txt-hvr-b {
translate: 0 0;
}
/* Btn Small */
.btn-s:is(:hover, :focus-visible) {
background: var(--orange);
}
.btn-s:is(:hover, :focus-visible) .btn_txt {
translate: 0 -1.9rem;
}
.btn-s:is(:hover, :focus-visible) .btn_txt-hvr {
translate: 0 0;
}
/* Btn Outline Small */
.btn-s-outline:is(:hover, :focus-visible) {
border-color: var(--white-40);
}
.btn-s-outline:is(:hover, :focus-visible) .btn_txt {
translate: 0 -1.9rem;
}
.btn-s-outline:is(:hover, :focus-visible) .btn_txt-hvr {
translate: 0 0;
}
/* Use Cases Card And Blog Card */
.usecases__card:is(:hover, :focus-visible) .usecases__border,
.pl-blog__card:is(:hover, :focus-visible) .usecases__border {
border-color: var(--orange);
transform: scaleX(1.01) scaleY(1.01);
}
.usecases__card:is(:hover, :focus-visible) .usecases__arrow,
.pl-blog__card:is(:hover, :focus-visible) .usecases__arrow {
translate: 1.3rem -1.3rem;
}
.usecases__card:is(:hover, :focus-visible) .usecases__arrow-hover,
.pl-blog__card:is(:hover, :focus-visible) .usecases__arrow-hover {
translate: 0 0;
}
/* FAQ */
.faq__item:not(.is-act):is(:hover, :focus-visible) .faq__border {
border-color: var(--orange);
transform: scaleX(1.004) scaleY(1.015);
}
/* Underline Link */
.underline-link:is(:hover, :focus-visible)::before {
transform-origin: left;
transform: scaleX(1) rotate(0.001deg);
}
/* Socials */
.footer__social:is(:hover, :focus-visible),
.bl-main__social:is(:hover, :focus-visible) {
color: var(--orange);
}
/* Footer Form */
.footer__input:is(:hover, :focus-visible) {
border-color: var(--orange);
}
.footer__btn.is-act:is(:hover, :focus-visible) {
background: var(--orange);
}
.footer__btn.is-act:is(:hover, :focus-visible) .btn_txt {
translate: 0 -1.9rem;
}
.footer__btn.is-act:is(:hover, :focus-visible) .btn_txt-hvr {
translate: 0 0;
}
/* Nav Cases */
.nav__cases:is(:hover, :focus-visible) .is-nav {
color: var(--white-40);
}
.nav__cases:is(:hover, :focus-visible) .nav__dl-wrap {
pointer-events: auto;
translate: 0 0;
opacity: 1;
}
/* Nav Company */
.nav-dd:is(:hover, :focus-visible) .txt-c-white.underline-link {
color: var(--white-40);
}
.nav-dd:is(:hover, :focus-visible) .nav-dd__btm {
pointer-events: auto;
translate: 0 0;
opacity: 1;
}
/* Slider */
.swiper-slide.is-f-l:not(.swiper-slide-thumb-active):is(
:hover,
:focus-visible
),
.swiper-slide.is-obs-hiw-l:not(.swiper-slide-thumb-active):is(
:hover,
:focus-visible
) {
color: var(--white);
background: var(--dark-grey);
}
}
.nav__burger.w--open .nav__bur-clsr {
opacity: 1;
}
.nav__bur-clsr {
transition: opacity 0.65s var(--color-ease);
}
/* Animate */
[animate] {
overflow: hidden;
}
.line-wrapper {
overflow: hidden;
position: relative;
width: 100%;
display: block;
}
.split-line {
display: block;
position: relative;
width: 100%;
}
/* Оптимизация производительности */
.split-line {
will-change: transform, opacity;
backface-visibility: hidden;
}
h1 .line-wrapper {
padding: 0.08rem 0; /* Добавляем небольшой вертикальный паддинг */
overflow: hidden;
}
h1 .split-line {
padding: 0.08rem 0; /* Добавляем паддинг и для самих строк */
}
@media screen and (min-width: 991px) {
.nav__content .underline-link {
font-size: max(13px, 0.8125rem);
}
}
[data-underline-link] {
text-decoration: none;
position: relative;
}
[data-underline-link]::before {
content: "";
position: absolute;
bottom: -0.0625em;
left: 0;
width: 100%;
height: 0.0625em;
background-color: currentColor;
transition: transform 0.735s cubic-bezier(0.625, 0.05, 0, 1);
transform-origin: right;
transform: scaleX(0) rotate(0.001deg);
}
@media (hover: hover) and (pointer: fine) {
[data-hover]:hover [data-underline-link]::before,
[data-underline-link]:hover::before {
transform-origin: left;
transform: scaleX(1) rotate(0.001deg);
}
}
/* Animation */
[data-bunny-background-init] :is(.bunny-bg__placeholder, .bunny-bg__loading) {
transition: opacity 0.3s linear, visibility 0.3s linear;
}
/* Placeholder */
[data-bunny-background-init][data-player-status="playing"] .bunny-bg__placeholder,
[data-bunny-background-init][data-player-status="paused"] .bunny-bg__placeholder,
[data-bunny-background-init][data-player-activated="true"][data-player-status="ready"] .bunny-bg__placeholder {
opacity: 0;
visibility: hidden;
}
/* Play/Pause */
[data-bunny-background-init][data-player-status="playing"] .bunny-bg__play-svg,
[data-bunny-background-init][data-player-status="loading"] .bunny-bg__play-svg {
display: none;
}
[data-bunny-background-init][data-player-status="playing"] .bunny-bg__pause-svg,
[data-bunny-background-init][data-player-status="loading"] .bunny-bg__pause-svg{
display: block;
}
/* Loading /
[data-bunny-background-init][data-player-status="loading"] .bunny-bg__loading {
opacity: 1;
visibility: visible;
}
MCP/Gradient */
.api-hiv__num,
.is-or-2nd {
background: linear-gradient(154.84deg, #FF5E19 6.39%, #FF3710 95.79%);
}
.is-or-2nd {
box-shadow: 0px 0px 14px -3px rgba(255, 73, 20, 0.7);
}
.api-code__num,
.u-t-color-orange {
background: linear-gradient(154.84deg, #FF5E19 6.39%, #FF3710 95.79%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-fill-color: transparent;
}
.api-main__deploy-card {
transition: box-shadow .65s ease;
}
.api-main__deploy-card:is(:hover, :focus-visible) {
box-shadow:0 6px 16px -8px rgba(6,6,6,0.12);
}
/* Code Tabs */
.code-tab:is(:hover, :focus-visible),
.code-copy:is(:hover, :focus-visible) {
color: var(--white);
}
.code-body pre{margin:0;white-space:pre;}
.code-body .kw{color:#FF8A5C;}
.code-body .str{color:#9BD89B;}
.code-body .num{color:#7EC4F5;}
.code-body .cmt{color:rgba(255,255,255,0.35);font-style:italic;}
.code-body .var{color:#fff;}
.benef__card:hover .benef__img {
filter: grayscale(0%);
}
.use-cases__control.is-active {
color: var(--white);
}
.use-cases__control.is-active .use-cases__progress-wr {
opacity: 1;
}
.nav {
box-shadow: 0px 2px 32px 0px #0000000a;
}
.hiw__btm {
box-shadow: 0px 0px 12px 0px #0000000d;
}
.main__mid-top {
box-shadow: 0px 0px 10.33px 0px #0000000d;
}
.main__r-ic-wr.is-active {
box-shadow: 0px 10px 24px 0px #ff5e191a;
}
.main__r-ic-wr.is-active .main__r-img {
filter: grayscale(0%);
}
@media only screen and (max-width: 990px) {
.nav__links {
box-shadow: 0px 2px 32px 0px #0000000a;
}
.nav__mid.is-active .nav__links {
opacity:1;
pointer-events: auto;
transform: translate(0px, 0px);
}
/* Анимация бургера в крестик /
.nav__mid.is-active .nav-burg__line.is-1 {
/ Верхняя линия → диагональ сверху */
transform: translate(0%, 0%) rotate(45deg);
top: auto;
}
.nav__mid.is-active .nav-burg__line.is-2 {
/* Средняя линия исчезает */
opacity: 0;
}
.nav__mid.is-active .nav-burg__line.is-3 {
/* Нижняя линия → диагональ снизу */
transform: translate(0%, 0%) rotate(-45deg);
bottom: auto;
}
.benef__card.is-act .benef__img {
filter: grayscale(0%);
}
Connect any API. To any AI agent. Auto-generate Model Context Protocol tool definitions from any REST, GraphQL, SOAP, or gRPC API. Self-hosted in minutes. No glue code. No rewrites.
Self-hosted · Free trial · No credit card required
OpenAI
Claude
Mistral
Gemini
Any LLM
GraphQL
gRPC
SOAP
OpenAPI
Any API
AI that delivers Legacy and most existing APIs weren't designed for a world where the consumer is an LLM. Schemas lack semantic context, tool boundaries are ambiguous, and payloads burn through context windows. Expose, govern, and optimize LLM, MCP, and API resources through a single point of control — eliminating integration complexity without creating and maintaining hundreds of individual MCP servers. for developers Ship an MCP server in 2 minutes. Not 2 weeks. Stop writing tool definitions by hand. Point MCP Bridge at any schema URL and every operation becomes a fully typed, annotated MCP tool — ready for Claude, GPT, Gemini, or any MCP-compatible client.
# Pull and run MCP Bridge $ docker run -d <br/> --name mcp-bridge <br/> -p 8080:8080 <br/> -v ./bridge.yaml:/app/config.yaml <br/> appfactor/mcp-bridge:latest # Point any MCP client at the endpoint $ curl https://localhost:8080/mcp/tools → 42 tools generated · ready
apis : - name : "payments" protocol : "rest" schema : "https://api.acme.io/openapi.yaml " auth : type : "oauth2" flow : "client_credentials" code_mode : true # 98% less context observability : otel : true log_level : "info"
# Auto-generated tools, ready for any LLM tools_generated : 42 protocols : [rest, graphql] annotations : read_only : 28 idempotent : 31 destructive : 4 avg_tokens_per_tool : 487 code_mode_tokens : 960 # vs ~48,000 raw
OpenAPI 3, GraphQL introspection, WSDL, and .proto files — all parsed automatically.
Docker container on AWS ECS, Azure Container Apps, or any orchestrator. Your data never leaves your network.
Memory-safe, high-throughput, production-ready. Zero external SaaS dependencies at runtime.
1
Provide a schema via URL, paste content, or upload files. Supports OpenAPI (JSON/YAML), GraphQL introspection, WSDL, and gRPC (server reflection or .proto files).
2
Each operation becomes a fully described MCP tool with typed input/output schemas, parameter mappings, behavioural annotations, and documentation.
3
MCP Bridge validates inputs, maps parameters, handles authentication, and forwards requests to the backend. Responses are post-processed to reduce token waste.
4
For large APIs, 3 meta-tools replace the full catalog — cutting context window usage by ~98%. The LLM orchestrates calls via a secure Boa sandbox.
Not a gateway Built for AI agents, not just HTTP traffic.API gateways route HTTP requests. MCP Bridge does something fundamentally different — it translates APIs into semantically rich tool definitions LLMs can reason about, select correctly, and call efficiently.
It handles what gateways were never designed for: tool curation, response post-processing to reduce token waste, context window management, and AI-specific observability across latency, throughput, token usage, and error rates.
REST · GraphQL · SOAP · gRPC
Latency · tokens · errors · O-Tel
Semantic search + pgvector
MCP Bridge
Annotations + schemas
MCP Bridge
Post-processing pipeline
MCP Bridge
REST · GraphQL · SOAP · gRPC
MCP Bridge
Latency · tokens · errors · O-Tel
MCP Bridge
Semantic search + pgvector
API Gateway
Static catalog
Code Mode~98% lessContext window usage
Three meta-tools replace hundreds of individual tool definitions. The LLM discovers tools on demand and orchestrates calls via JavaScript in a secure Boa sandbox with 30-second timeout — same capabilities, a fraction of the token cost.
Capabilities Enterprise-ready, on day one.Enable, rename, edit descriptions, customize parameter mappings, and configure per-tool response processing.
Per-tool declarative rules — unwrap, select, exclude, limit, sort, flatten, aggregate — or custom JavaScript in a sandbox.
Bearer, Basic, API Key, OAuth2, AWS Cognito SRP. OIDC for the web UI with Entra ID, Keycloak, Auth0, Okta.
Latency, throughput, per-tool and per-API metrics, token usage breakdowns, error rates. O-Tel in Enterprise.
Read-only, destructive, idempotent, and open-world hints auto-inferred from API semantics. Editable per tool.
Hybrid search with full-text, trigram fuzzy matching, and optional vector similarity via pgvector and HNSW.
Docker container on AWS ECS, Azure Container Apps, or any orchestrator. Zero external SaaS dependencies.
Per-API token bucket rate limiting, exponential backoff with jitter, configurable retry policies, health checks.
Who it's for Built for the teams making AI work in production. Expose internal APIs to AI agentsWithout writing or maintaining MCP adapters for each service. Import schemas, configure auth, and expose governed tools through a single control plane.
AI EngineersBuild agents that call enterprise APIs with authentication, rate limiting, response post-processing, and observability built in — not bolted on.
Enterprise Organizations Bridge your API portfolio to MCPAdopt MCP as a standard. Connect your existing API landscape to LLM clients quickly and securely, without refactoring services.
Give your AI agents the data access they need.Available on AWS and Azure Marketplace. Tiers from evaluation to enterprise-wide deployment.
Self-hosted · Free trial · No credit card required
document.querySelectorAll('.code-tab').forEach(tab => {
tab.addEventListener('click', () => {
const surface = tab.closest('.code-surface');
surface.querySelectorAll('.code-tab').forEach(t => t.classList.toggle('active', t === tab));
surface.querySelectorAll('.code-pane').forEach(p => p.classList.toggle('active', p.id === tab.dataset.pane));
});
});
document.querySelectorAll('[data-copy]').forEach(btn => {
btn.addEventListener('click', () => {
const surface = btn.closest('.code-surface');
const active = surface.querySelector('.code-pane.active');
if (!active) return;
navigator.clipboard?.writeText(active.innerText.trim());
const orig = btn.textContent;
btn.textContent = 'Copied';
setTimeout(() => btn.textContent = orig, 1600);
});
});
×
Ship an MCP serverin 2 minutes.
Self-hosted. No glue code.
Something went wrong. Please try again.
You're in.Download starting now.
Opening the download in a new tab. If it didn't open, click below.
Download MCP Bridge ↗
// --- АНИМАЦИЯ ЛИНИЙ 1 (один раз) ---
const lines1Timeline = gsap.timeline();
const line1 = prepareLine(".an-l-1");
const line2 = prepareLine(".an-l-2");
const line3 = prepareLine(".an-l-3");
const line4 = prepareLine(".an-l-4");
if (line1) {
lines1Timeline.to(
line1,
{
strokeDashoffset: 0,
duration: 1,
ease: "power3.out",
},
0
);
}
if (line2) {
lines1Timeline.to(
line2,
{
strokeDashoffset: 0,
duration: 1,
ease: "power3.out",
},
0.2
);
}
if (line3) {
lines1Timeline.to(
line3,
{
strokeDashoffset: 0,
duration: 1,
ease: "power3.out",
},
0.4
);
}
if (line4) {
lines1Timeline.to(
line4,
{
strokeDashoffset: 0,
duration: 1,
ease: "power3.out",
},
0.6
);
}
// --- АНИМАЦИЯ КРУГОВ 1 (бесконечный цикл, 2 сек каждый) ---
const circles1Timeline = gsap.timeline({
repeat: -1,
repeatDelay: 0,
paused: true,
});
// последний старт 0.6 + 2 сек движения = 2.6
const circles1Duration = 2.6;
const path1 = document.querySelector(".an-l-1");
const path2 = document.querySelector(".an-l-2");
const path3 = document.querySelector(".an-l-3");
const path4 = document.querySelector(".an-l-4");
circles1Timeline.set(
[".cir-1", ".cir-2", ".cir-3", ".cir-4"],
{ opacity: 1 },
0
);
circles1Timeline
.to(
".cir-1",
{
duration: 2,
ease: "power3.out",
motionPath: {
path: path1,
align: path1,
alignOrigin: [0.5, 0.5],
start: 0,
end: 1,
},
},
0
)
.set(".cir-1", { opacity: 0 }, 0 + 2);
circles1Timeline
.to(
".cir-2",
{
duration: 2,
ease: "power3.out",
motionPath: {
path: path2,
align: path2,
alignOrigin: [0.5, 0.5],
start: 0,
end: 1,
},
},
0.2
)
.set(".cir-2", { opacity: 0 }, 0.2 + 2);
circles1Timeline
.to(
".cir-3",
{
duration: 2,
ease: "power3.out",
motionPath: {
path: path3,
align: path3,
alignOrigin: [0.5, 0.5],
start: 0,
end: 1,
},
},
0.4
)
.set(".cir-3", { opacity: 0 }, 0.4 + 2);
circles1Timeline
.to(
".cir-4",
{
duration: 2,
ease: "power3.out",
motionPath: {
path: path4,
align: path4,
alignOrigin: [0.5, 0.5],
start: 0,
end: 1,
},
},
0.6
)
.set(".cir-4", { opacity: 0 }, 0.6 + 2);
// --- АНИМАЦИЯ ЛИНИЙ 2 (один раз, 1 c каждая) ---
const lines2Timeline = gsap.timeline({ paused: true });
const rightItems = document.querySelectorAll(".main__r-wr .main__r-ic-wr");
const addActiveClass = (index) => {
if (!rightItems[index]) return;
rightItems[index].classList.add("is-active");
};
const line5 = prepareLine(".an-l-5");
const line6 = prepareLine(".an-l-6");
const line7 = prepareLine(".an-l-7");
const line8 = prepareLine(".an-l-8");
const line9 = prepareLine(".an-l-9");
// an-l-5 + 1-й блок, t=0
if (line5) {
lines2Timeline.to(
line5,
{
strokeDashoffset: 0,
duration: 1,
ease: "power3.out",
onStart: () => addActiveClass(0),
},
0
);
} else {
lines2Timeline.add(() => addActiveClass(0), 0);
}
// an-l-6 + 2-й блок, t=0.2
if (line6) {
lines2Timeline.to(
line6,
{
strokeDashoffset: 0,
duration: 1,
ease: "power3.out",
onStart: () => addActiveClass(1),
},
0.2
);
} else {
lines2Timeline.add(() => addActiveClass(1), 0.2);
}
// an-l-7 + 3-й блок, t=0.4
if (line7) {
lines2Timeline.to(
line7,
{
strokeDashoffset: 0,
duration: 1,
ease: "power3.out",
onStart: () => addActiveClass(2),
},
0.4
);
} else {
lines2Timeline.add(() => addActiveClass(2), 0.4);
}
// an-l-8 + 4-й блок, t=0.6
if (line8) {
lines2Timeline.to(
line8,
{
strokeDashoffset: 0,
duration: 1,
ease: "power3.out",
onStart: () => addActiveClass(3),
},
0.6
);
} else {
lines2Timeline.add(() => addActiveClass(3), 0.6);
}
// an-l-9 + 5-й блок, t=0.8
if (line9) {
lines2Timeline.to(
line9,
{
strokeDashoffset: 0,
duration: 1,
ease: "power3.out",
onStart: () => addActiveClass(4),
},
0.8
);
} else {
lines2Timeline.add(() => addActiveClass(4), 0.8);
}
// --- АНИМАЦИЯ КРУГОВ 2 (цикл, 2 c каждый, 5 кругов) ---
const circles2Timeline = gsap.timeline({
repeat: -1,
repeatDelay: 0,
paused: true,
});
const path5 = document.querySelector(".an-l-5");
const path6 = document.querySelector(".an-l-6");
const path7 = document.querySelector(".an-l-7");
const path8 = document.querySelector(".an-l-8");
const path9 = document.querySelector(".an-l-9");
circles2Timeline.set(
[".cir-5", ".cir-6", ".cir-7", ".cir-8", ".cir-9"],
{ opacity: 1 },
0
);
// cir-5 по an-l-5, t=0
circles2Timeline
.to(
".cir-5",
{
duration: 2,
ease: "power3.out",
motionPath: {
path: path5,
align: path5,
alignOrigin: [0.5, 0.5],
start: 0,
end: 1,
},
},
0
)
.set(".cir-5", { opacity: 0 }, 2);
// cir-6 по an-l-6, t=0.2
circles2Timeline
.to(
".cir-6",
{
duration: 2,
ease: "power3.out",
motionPath: {
path: path6,
align: path6,
alignOrigin: [0.5, 0.5],
start: 0,
end: 1,
},
},
0.2
)
.set(".cir-6", { opacity: 0 }, 2.2);
// cir-7 по an-l-7, t=0.4
circles2Timeline
.to(
".cir-7",
{
duration: 2,
ease: "power3.out",
motionPath: {
path: path7,
align: path7,
alignOrigin: [0.5, 0.5],
start: 0,
end: 1,
},
},
0.4
)
.set(".cir-7", { opacity: 0 }, 2.4);
// cir-8 по an-l-8, t=0.6
circles2Timeline
.to(
".cir-8",
{
duration: 2,
ease: "power3.out",
motionPath: {
path: path8,
align: path8,
alignOrigin: [0.5, 0.5],
start: 0,
end: 1,
},
},
0.6
)
.set(".cir-8", { opacity: 0 }, 2.6);
// cir-9 по an-l-9, t=0.8
circles2Timeline
.to(
".cir-9",
{
duration: 2,
ease: "power3.out",
motionPath: {
path: path9,
align: path9,
alignOrigin: [0.5, 0.5],
start: 0,
end: 1,
},
},
0.8
)
.set(".cir-9", { opacity: 0 }, 2.8);
// --- ФЛОУ ---
let secondStageStarted = false;
// После окончания линий 1 запускаем круги 1
lines1Timeline.eventCallback("onComplete", () => {
circles1Timeline.restart(true);
});
// После окончания ПЕРВОГО цикла кругов 1 запускаем линии 2,
// а после завершения линий 2 — бесконечные круги 2
circles1Timeline.eventCallback("onRepeat", () => {
if (secondStageStarted) return;
secondStageStarted = true;
lines2Timeline.restart(true);
lines2Timeline.eventCallback("onComplete", () => {
circles2Timeline.restart(true);
});
});
});