From 057c52cdd2c74d5c2268a802f1707863fd7ab210 Mon Sep 17 00:00:00 2001
From: Devin
Date: Thu, 6 Aug 2026 01:07:19 +0000
Subject: [PATCH 1/6] Make Swift and Rust clickable in the landing page SDK
animation
---
fern/assets/styles.css | 65 ++++++++++++++++++++++++++++
fern/products/home/pages/welcome.mdx | 12 +++++
fern/rive-animation.js | 22 ++++++----
3 files changed, 90 insertions(+), 9 deletions(-)
diff --git a/fern/assets/styles.css b/fern/assets/styles.css
index 7f7c9bbbc4..3d96ac7eb3 100644
--- a/fern/assets/styles.css
+++ b/fern/assets/styles.css
@@ -1084,6 +1084,71 @@ h1, h2, h3 {
display: inline-block;
}
+/* Live Swift and Rust tabs layered over the SDK animation.
+ Positions and sizes are percentages of the 369x93 Rive artboard, so they track the canvas as it scales. */
+.sdk-rive .rive-container {
+ container-type: inline-size;
+}
+
+.rive-tab-overlay {
+ position: absolute;
+ inset: 0;
+ z-index: 2;
+ pointer-events: none;
+}
+
+.rive-tab {
+ position: absolute;
+ top: 34.34%;
+ height: 28.6%;
+ width: 10.46%;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 1.92cqw;
+ text-decoration: none;
+ background-color: #fcfcfd;
+ pointer-events: auto;
+}
+
+.dark .rive-tab {
+ background-color: #111113;
+}
+
+.rive-tab-swift {
+ left: 76.53%;
+}
+
+.rive-tab-rust {
+ left: 86.99%;
+}
+
+.rive-tab-icon {
+ width: 2.88cqw;
+ height: 2.88cqw;
+ margin: 0;
+ object-fit: contain;
+}
+
+.rive-tab-label {
+ font-family: "JetBrains Mono", ui-monospace, monospace;
+ font-size: 1.73cqw;
+ line-height: 1;
+ color: #4a4a4a;
+}
+
+.dark .rive-tab-label {
+ color: #a9a9a9;
+}
+
+.rive-tab:hover .rive-tab-label {
+ color: #21201c;
+}
+
+.dark .rive-tab:hover .rive-tab-label {
+ color: #fcfcfd;
+}
+
/*** END -- LANDING PAGE STYLING ***/
/* HACK: add a slash to markdown snippet documentation (otherwise it gets parsed by CLI) */
diff --git a/fern/products/home/pages/welcome.mdx b/fern/products/home/pages/welcome.mdx
index 0de8f47702..fa43f2e59f 100644
--- a/fern/products/home/pages/welcome.mdx
+++ b/fern/products/home/pages/welcome.mdx
@@ -45,6 +45,18 @@ layout: custom
+ {/* The Rive file renders Swift and Rust as inert grey artwork, so they are covered with live tabs */}
+
diff --git a/fern/rive-animation.js b/fern/rive-animation.js
index 24b8489c21..900c115058 100644
--- a/fern/rive-animation.js
+++ b/fern/rive-animation.js
@@ -45,15 +45,18 @@
try {
// Set container aspect ratio while respecting existing layout
- const currentWidth = riveContainer.offsetWidth || riveContainer.clientWidth;
- if (currentWidth > 0) {
- // Use existing width, set height based on aspect ratio
- riveContainer.style.height = (currentWidth / aspectRatio) + 'px';
- } else {
- // Fallback: use CSS aspect-ratio if container has no initial width
- riveContainer.style.aspectRatio = aspectRatio.toString();
- riveContainer.style.width = '100%';
- }
+ const syncContainerHeight = () => {
+ const currentWidth = riveContainer.offsetWidth || riveContainer.clientWidth;
+ if (currentWidth > 0) {
+ // Use existing width, set height based on aspect ratio
+ riveContainer.style.height = (currentWidth / aspectRatio) + 'px';
+ } else {
+ // Fallback: use CSS aspect-ratio if container has no initial width
+ riveContainer.style.aspectRatio = aspectRatio.toString();
+ riveContainer.style.width = '100%';
+ }
+ };
+ syncContainerHeight();
// Let Rive handle canvas sizing internally - much simpler!
const r = new rive.Rive({
@@ -107,6 +110,7 @@
// Simple resize handling (following Rive best practices)
const windowResizeHandler = () => {
+ syncContainerHeight();
// Let Rive handle the canvas sizing internally
if (r && r.resizeDrawingSurfaceToCanvas) {
r.resizeDrawingSurfaceToCanvas();
From 1656d59750a26d85e7117fbfdbca3328abf395b6 Mon Sep 17 00:00:00 2001
From: "jon.syla"
Date: Fri, 7 Aug 2026 13:57:58 +0000
Subject: [PATCH 2/6] Rebuild the landing page SDK card in HTML/CSS with Swift
and Rust as real tabs
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
---
fern/assets/styles.css | 243 ++++++++++++++++++++-------
fern/products/home/pages/welcome.mdx | 87 ++++++++--
fern/rive-animation.js | 43 +----
3 files changed, 264 insertions(+), 109 deletions(-)
diff --git a/fern/assets/styles.css b/fern/assets/styles.css
index 3d96ac7eb3..90f5e82908 100644
--- a/fern/assets/styles.css
+++ b/fern/assets/styles.css
@@ -1016,23 +1016,6 @@ h1, h2, h3 {
-.sdk-rive {
- aspect-ratio: 369/93;
- width: 100%;
- display: block;
- overflow: visible; /* Changed from hidden - was clipping interactive areas */
- transform: translateY(0px);
- transition: transform 250ms ease-out !important;
- will-change: transform;
- /* Ensure click events can reach the canvas */
- pointer-events: auto;
- min-height: 104px;
-}
-
-.sdk-rive:hover {
- transform: translateY(-3px) !important;
-}
-
.docs-rive {
min-height: 213px;
}
@@ -1042,10 +1025,6 @@ h1, h2, h3 {
}
@media (max-width: 640px) {
- .sdk-rive {
- min-height: inherit;
- }
-
.docs-rive {
min-height: inherit;
}
@@ -1084,69 +1063,215 @@ h1, h2, h3 {
display: inline-block;
}
-/* Live Swift and Rust tabs layered over the SDK animation.
- Positions and sizes are percentages of the 369x93 Rive artboard, so they track the canvas as it scales. */
-.sdk-rive .rive-container {
+/* SDK language tabs.
+ Sizes and positions are expressed in --u, one unit of the 369x93 grid the card is laid out on,
+ so everything scales with the card width. */
+.sdk-card {
+ --u: 0.271003cqw; /* 100cqw / 369 */
+ --tab-pitch: 39.03;
+ --tab-first: 9.8;
+ --tab-index: 0;
+ --underline-width: calc(37.1 * var(--u));
+ --sdk-card-bg: #fcfcfd;
+ --sdk-card-subdued-bg: #f5f5f6;
+ --sdk-card-border: #e0e1e6;
+ --sdk-card-skeleton: #cacaca;
+ --sdk-card-text: #191919;
+ --sdk-card-subdued-text: #5a5a5b;
+ --sdk-card-copy: #b3b3b4;
+ --sdk-card-active: #008700;
container-type: inline-size;
+ box-sizing: border-box;
+ aspect-ratio: 369/93;
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ border-radius: 4px;
+ /* Drawn inside the box so the 369x93 grid is not shrunk by the border */
+ box-shadow: inset 0 0 0 1px var(--sdk-card-border);
+ background-color: var(--sdk-card-bg);
+ transition: transform 250ms ease-out;
+}
+
+.dark .sdk-card {
+ --sdk-card-bg: #111113;
+ --sdk-card-subdued-bg: #1b1b1d;
+ --sdk-card-border: #303136;
+ --sdk-card-skeleton: #47484f;
+ --sdk-card-text: #e7e7e7;
+ --sdk-card-subdued-text: #a3a4a8;
+ --sdk-card-copy: #2d2e33;
+ --sdk-card-active: #9cdd8d;
+}
+
+.sdk-card:hover {
+ transform: translateY(-3px);
}
-.rive-tab-overlay {
+.sdk-card * {
+ box-sizing: border-box;
+}
+
+/* Visually hidden, but still focusable and operable with the arrow keys */
+.sdk-card-radio {
position: absolute;
- inset: 0;
- z-index: 2;
+ width: 1px;
+ height: 1px;
+ opacity: 0;
pointer-events: none;
}
-.rive-tab {
- position: absolute;
- top: 34.34%;
- height: 28.6%;
- width: 10.46%;
- display: flex;
- flex-direction: column;
- align-items: center;
- gap: 1.92cqw;
- text-decoration: none;
- background-color: #fcfcfd;
- pointer-events: auto;
+.sdk-card-header {
+ flex: none;
+ height: calc(19.25 * var(--u));
+ padding: calc(8.6 * var(--u)) 0 0 calc(6.15 * var(--u));
+ border-bottom: 1px solid var(--sdk-card-border);
+}
+
+.sdk-card-skeleton {
+ display: block;
+ width: calc(51.6 * var(--u));
+ height: calc(2 * var(--u));
+ border-radius: 999px;
+ background-color: var(--sdk-card-skeleton);
}
-.dark .rive-tab {
- background-color: #111113;
+.sdk-card-tabs {
+ position: relative;
+ flex: 1;
+ display: flex;
+ padding: 0 calc(7.9 * var(--u)) 0 calc(var(--tab-first) * var(--u));
+ border-bottom: 1px solid var(--sdk-card-border);
}
-.rive-tab-swift {
- left: 76.53%;
+.sdk-card-tab {
+ flex: 1;
+ display: grid;
+ grid-template-rows: calc(13.7 * var(--u)) auto;
+ justify-items: center;
+ align-items: center;
+ gap: calc(0.5 * var(--u));
+ padding-top: calc(10.9 * var(--u));
+ margin: 0;
+ cursor: pointer;
+ transform-origin: 50% 60%;
+ transition: transform 150ms ease-out;
}
-.rive-tab-rust {
- left: 86.99%;
+.sdk-card-tab:hover {
+ transform: scale(1.048);
}
-.rive-tab-icon {
- width: 2.88cqw;
- height: 2.88cqw;
+.sdk-card-tab-icon {
+ width: var(--icon-size);
+ height: var(--icon-size);
margin: 0;
object-fit: contain;
}
-.rive-tab-label {
- font-family: "JetBrains Mono", ui-monospace, monospace;
- font-size: 1.73cqw;
- line-height: 1;
- color: #4a4a4a;
+.sdk-card-tab-typescript { --icon-size: calc(10.63 * var(--u)); }
+.sdk-card-tab-python { --icon-size: calc(13.62 * var(--u)); }
+.sdk-card-tab-go { --icon-size: calc(13.06 * var(--u)); }
+.sdk-card-tab-java { --icon-size: calc(13.66 * var(--u)); }
+.sdk-card-tab-dotnet { --icon-size: calc(13.27 * var(--u)); }
+.sdk-card-tab-php { --icon-size: calc(13.68 * var(--u)); }
+.sdk-card-tab-ruby { --icon-size: calc(10.57 * var(--u)); }
+.sdk-card-tab-swift { --icon-size: calc(10.07 * var(--u)); }
+.sdk-card-tab-rust { --icon-size: calc(10.02 * var(--u)); }
+
+.sdk-card-tab-label {
+ font-family: var(--font-code);
+ font-size: calc(6.16 * var(--u));
+ line-height: calc(7.3 * var(--u));
+ color: var(--sdk-card-text);
+ white-space: nowrap;
}
-.dark .rive-tab-label {
- color: #a9a9a9;
+.sdk-card-underline {
+ position: absolute;
+ bottom: -1px; /* sits on the separator, like the animation did */
+ left: calc((var(--tab-first) + (var(--tab-index) + 0.5) * var(--tab-pitch)) * var(--u) - var(--underline-width) / 2);
+ width: var(--underline-width);
+ height: calc(0.9 * var(--u));
+ background-color: var(--sdk-card-active);
+ transition: left 150ms ease-out, width 150ms ease-out;
}
-.rive-tab:hover .rive-tab-label {
- color: #21201c;
+#sdk-card-python:checked ~ .sdk-card-tabs { --tab-index: 1; --underline-width: calc(22.4 * var(--u)); }
+#sdk-card-go:checked ~ .sdk-card-tabs { --tab-index: 2; --underline-width: calc(19 * var(--u)); }
+#sdk-card-java:checked ~ .sdk-card-tabs { --tab-index: 3; --underline-width: calc(19 * var(--u)); }
+#sdk-card-dotnet:checked ~ .sdk-card-tabs { --tab-index: 4; --underline-width: calc(18.7 * var(--u)); }
+#sdk-card-php:checked ~ .sdk-card-tabs { --tab-index: 5; --underline-width: calc(18.5 * var(--u)); }
+#sdk-card-ruby:checked ~ .sdk-card-tabs { --tab-index: 6; --underline-width: calc(19.9 * var(--u)); }
+#sdk-card-swift:checked ~ .sdk-card-tabs { --tab-index: 7; --underline-width: calc(18.6 * var(--u)); }
+#sdk-card-rust:checked ~ .sdk-card-tabs { --tab-index: 8; --underline-width: calc(19 * var(--u)); }
+
+#sdk-card-typescript:focus-visible ~ .sdk-card-tabs .sdk-card-tab-typescript,
+#sdk-card-python:focus-visible ~ .sdk-card-tabs .sdk-card-tab-python,
+#sdk-card-go:focus-visible ~ .sdk-card-tabs .sdk-card-tab-go,
+#sdk-card-java:focus-visible ~ .sdk-card-tabs .sdk-card-tab-java,
+#sdk-card-dotnet:focus-visible ~ .sdk-card-tabs .sdk-card-tab-dotnet,
+#sdk-card-php:focus-visible ~ .sdk-card-tabs .sdk-card-tab-php,
+#sdk-card-ruby:focus-visible ~ .sdk-card-tabs .sdk-card-tab-ruby,
+#sdk-card-swift:focus-visible ~ .sdk-card-tabs .sdk-card-tab-swift,
+#sdk-card-rust:focus-visible ~ .sdk-card-tabs .sdk-card-tab-rust {
+ outline: 2px solid var(--sdk-card-active);
+ outline-offset: calc(-1 * var(--u));
+ border-radius: 2px;
}
-.dark .rive-tab:hover .rive-tab-label {
- color: #fcfcfd;
+.sdk-card-command {
+ flex: none;
+ height: calc(30.5 * var(--u));
+ display: flex;
+ align-items: center;
+ gap: calc(4 * var(--u));
+ padding: 0 calc(8.12 * var(--u)) 0 calc(7 * var(--u));
+ background-color: var(--sdk-card-subdued-bg);
+}
+
+.sdk-card-command-text {
+ flex: 1;
+ display: none;
+ overflow: hidden;
+ padding: 0;
+ border: none;
+ border-radius: 0;
+ box-shadow: none;
+ background: none;
+ font-family: var(--font-code);
+ font-size: calc(6.97 * var(--u));
+ line-height: 1.2;
+ white-space: nowrap;
+ color: var(--sdk-card-subdued-text);
+}
+
+#sdk-card-typescript:checked ~ .sdk-card-command .sdk-card-command-typescript,
+#sdk-card-python:checked ~ .sdk-card-command .sdk-card-command-python,
+#sdk-card-go:checked ~ .sdk-card-command .sdk-card-command-go,
+#sdk-card-java:checked ~ .sdk-card-command .sdk-card-command-java,
+#sdk-card-dotnet:checked ~ .sdk-card-command .sdk-card-command-dotnet,
+#sdk-card-php:checked ~ .sdk-card-command .sdk-card-command-php,
+#sdk-card-ruby:checked ~ .sdk-card-command .sdk-card-command-ruby,
+#sdk-card-swift:checked ~ .sdk-card-command .sdk-card-command-swift,
+#sdk-card-rust:checked ~ .sdk-card-command .sdk-card-command-rust {
+ display: block;
+}
+
+.sdk-card-copy {
+ flex: none;
+ width: calc(6.88 * var(--u));
+ height: calc(8 * var(--u));
+ color: var(--sdk-card-copy);
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .sdk-card,
+ .sdk-card-tab,
+ .sdk-card-underline {
+ transition: none;
+ }
}
/*** END -- LANDING PAGE STYLING ***/
diff --git a/fern/products/home/pages/welcome.mdx b/fern/products/home/pages/welcome.mdx
index fa43f2e59f..b7cb464871 100644
--- a/fern/products/home/pages/welcome.mdx
+++ b/fern/products/home/pages/welcome.mdx
@@ -41,22 +41,77 @@ layout: custom
- {/* Rive Animation */}
-
-
-
- {/* The Rive file renders Swift and Rust as inert grey artwork, so they are covered with live tabs */}
-
+ {/* SDK language tabs */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
npm install your-company
+
pip install your-company
+
go get github.com/your-company/go-sdk
+
{'compile "com.your-company:java-sdk:1.0.0"'}
+
dotnet add package YourCompany.Net --version 1.0.0
+
composer require your-company/your-company-php
+
gem install your_company
+
{'.package(url: "https://github.com/your-company/swift-sdk")'}
+
cargo add your-company
+
diff --git a/fern/rive-animation.js b/fern/rive-animation.js
index 900c115058..960766ed98 100644
--- a/fern/rive-animation.js
+++ b/fern/rive-animation.js
@@ -45,18 +45,15 @@
try {
// Set container aspect ratio while respecting existing layout
- const syncContainerHeight = () => {
- const currentWidth = riveContainer.offsetWidth || riveContainer.clientWidth;
- if (currentWidth > 0) {
- // Use existing width, set height based on aspect ratio
- riveContainer.style.height = (currentWidth / aspectRatio) + 'px';
- } else {
- // Fallback: use CSS aspect-ratio if container has no initial width
- riveContainer.style.aspectRatio = aspectRatio.toString();
- riveContainer.style.width = '100%';
- }
- };
- syncContainerHeight();
+ const currentWidth = riveContainer.offsetWidth || riveContainer.clientWidth;
+ if (currentWidth > 0) {
+ // Use existing width, set height based on aspect ratio
+ riveContainer.style.height = (currentWidth / aspectRatio) + 'px';
+ } else {
+ // Fallback: use CSS aspect-ratio if container has no initial width
+ riveContainer.style.aspectRatio = aspectRatio.toString();
+ riveContainer.style.width = '100%';
+ }
// Let Rive handle canvas sizing internally - much simpler!
const r = new rive.Rive({
@@ -110,7 +107,6 @@
// Simple resize handling (following Rive best practices)
const windowResizeHandler = () => {
- syncContainerHeight();
// Let Rive handle the canvas sizing internally
if (r && r.resizeDrawingSurfaceToCanvas) {
r.resizeDrawingSurfaceToCanvas();
@@ -240,27 +236,6 @@
return;
}
- // SDK Animation with native Rive interactions
- createRiveAnimation({
- canvasSelector: '#sdk-rive-canvas',
- riveUrl: 'https://cdn.prod.website-files.com/67880ff570cdb1a85eee946f/68802bc752aef23fab76e6fc_12235f640f9ad3339b42e8d026c6345a_sdk-rive.riv',
- aspectRatio: 369/93,
- stateMachine: "State Machine 1",
- fallbackImages: [
- {
- src: './images/sdks-preview-light.svg',
- className: 'sdks-preview-img dark:hidden',
- alt: 'SDK Generation Preview'
- },
- {
- src: './images/sdks-preview-dark.svg',
- className: 'sdks-preview-img hidden dark:block',
- alt: 'SDK Generation Preview'
- }
- ]
- // No eventHandlers - this animation only uses native interactions
- });
-
// Docs Animation
createRiveAnimation({
canvasSelector: '#docs-rive-canvas',
From a7a5bc9fff817a8db86e0eacdcc837c97120d2fc Mon Sep 17 00:00:00 2001
From: "jon.syla"
Date: Fri, 7 Aug 2026 14:26:29 +0000
Subject: [PATCH 3/6] Keep the .NET install command's double hyphen literal
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
---
fern/products/home/pages/welcome.mdx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fern/products/home/pages/welcome.mdx b/fern/products/home/pages/welcome.mdx
index b7cb464871..0c7b2ec2bb 100644
--- a/fern/products/home/pages/welcome.mdx
+++ b/fern/products/home/pages/welcome.mdx
@@ -103,7 +103,7 @@ layout: custom
pip install your-company
go get github.com/your-company/go-sdk
{'compile "com.your-company:java-sdk:1.0.0"'}
- dotnet add package YourCompany.Net --version 1.0.0
+ {'dotnet add package YourCompany.Net --version 1.0.0'}
composer require your-company/your-company-php
gem install your_company
{'.package(url: "https://github.com/your-company/swift-sdk")'}
From f0de8959096bc0414fcb5b31e8e3f7e79dc87100 Mon Sep 17 00:00:00 2001
From: "jon.syla"
Date: Fri, 7 Aug 2026 14:32:02 +0000
Subject: [PATCH 4/6] Draw the SDK card outline over the command row so it
closes at the bottom
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
---
fern/assets/styles.css | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/fern/assets/styles.css b/fern/assets/styles.css
index 90f5e82908..374849ac52 100644
--- a/fern/assets/styles.css
+++ b/fern/assets/styles.css
@@ -1082,18 +1082,28 @@ h1, h2, h3 {
--sdk-card-active: #008700;
container-type: inline-size;
box-sizing: border-box;
+ position: relative;
aspect-ratio: 369/93;
width: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
border-radius: 4px;
- /* Drawn inside the box so the 369x93 grid is not shrunk by the border */
- box-shadow: inset 0 0 0 1px var(--sdk-card-border);
background-color: var(--sdk-card-bg);
transition: transform 250ms ease-out;
}
+/* Drawn over the rows rather than as a border on the card, so the 369x93 grid keeps its
+ full size and the opaque command row cannot paint over the bottom of the outline. */
+.sdk-card::after {
+ content: "";
+ position: absolute;
+ inset: 0;
+ border: 1px solid var(--sdk-card-border);
+ border-radius: 4px;
+ pointer-events: none;
+}
+
.dark .sdk-card {
--sdk-card-bg: #111113;
--sdk-card-subdued-bg: #1b1b1d;
From 4ce834136292412a75d0a2e159f9dd03b7d12950 Mon Sep 17 00:00:00 2001
From: "jon.syla"
Date: Sun, 9 Aug 2026 07:18:00 +0000
Subject: [PATCH 5/6] Draw the SDK card in on load, matching the Rive intro
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
---
fern/assets/styles.css | 63 +++++++++++++++++++++++++++-
fern/products/home/pages/welcome.mdx | 22 ++++++----
2 files changed, 75 insertions(+), 10 deletions(-)
diff --git a/fern/assets/styles.css b/fern/assets/styles.css
index 374849ac52..b1704b7a7a 100644
--- a/fern/assets/styles.css
+++ b/fern/assets/styles.css
@@ -1241,8 +1241,30 @@ h1, h2, h3 {
background-color: var(--sdk-card-subdued-bg);
}
+/* Wraps every command so the typing reveal runs once on load, rather than restarting each time
+ a command is shown. Shrinks to the visible command, which makes the clip-path steps below
+ land on character boundaries. */
+.sdk-card-command-typing {
+ display: block;
+ width: fit-content;
+ max-width: 100%;
+ min-width: 0;
+ overflow: hidden;
+ animation: sdk-card-type-in 400ms steps(24) 120ms backwards;
+}
+
+/* 24 steps, one per character of the Typescript command shown on load */
+@keyframes sdk-card-type-in {
+ from {
+ clip-path: inset(0 100% 0 0);
+ }
+
+ to {
+ clip-path: inset(0);
+ }
+}
+
.sdk-card-command-text {
- flex: 1;
display: none;
overflow: hidden;
padding: 0;
@@ -1271,17 +1293,56 @@ h1, h2, h3 {
.sdk-card-copy {
flex: none;
+ margin-left: auto;
width: calc(6.88 * var(--u));
height: calc(8 * var(--u));
color: var(--sdk-card-copy);
}
+/* Draws the card in on load: a curtain in the row background colours that retreats to the right,
+ revealing the outline, separators and tabs in turn. Its soft trailing edge is what makes each
+ tab fade up rather than snap in, and it starts one softness-width off the left edge so the
+ card is fully covered on the first frame. */
+.sdk-card-intro {
+ --draw-softness: 34.5%;
+ position: absolute;
+ inset: 0;
+ z-index: 2;
+ pointer-events: none;
+ background: linear-gradient(
+ to bottom,
+ var(--sdk-card-bg) calc(62.5 * var(--u)),
+ var(--sdk-card-subdued-bg) calc(62.5 * var(--u))
+ );
+ -webkit-mask-image: linear-gradient(to right, transparent, #000 var(--draw-softness));
+ mask-image: linear-gradient(to right, transparent, #000 var(--draw-softness));
+ animation: sdk-card-draw-in 700ms cubic-bezier(0.15, 0.2, 0.4, 1) forwards;
+}
+
+@keyframes sdk-card-draw-in {
+ from {
+ transform: translateX(calc(-1 * var(--draw-softness)));
+ }
+
+ to {
+ transform: translateX(100%);
+ }
+}
+
@media (prefers-reduced-motion: reduce) {
.sdk-card,
.sdk-card-tab,
.sdk-card-underline {
transition: none;
}
+
+ .sdk-card-intro {
+ display: none;
+ }
+
+ .sdk-card-command-typing {
+ animation: none;
+ }
}
/*** END -- LANDING PAGE STYLING ***/
diff --git a/fern/products/home/pages/welcome.mdx b/fern/products/home/pages/welcome.mdx
index 0c7b2ec2bb..868c6af3cc 100644
--- a/fern/products/home/pages/welcome.mdx
+++ b/fern/products/home/pages/welcome.mdx
@@ -99,20 +99,24 @@ layout: custom
-
npm install your-company
-
pip install your-company
-
go get github.com/your-company/go-sdk
-
{'compile "com.your-company:java-sdk:1.0.0"'}
-
{'dotnet add package YourCompany.Net --version 1.0.0'}
-
composer require your-company/your-company-php
-
gem install your_company
-
{'.package(url: "https://github.com/your-company/swift-sdk")'}
-
cargo add your-company
+
+ npm install your-company
+ pip install your-company
+ go get github.com/your-company/go-sdk
+ {'compile "com.your-company:java-sdk:1.0.0"'}
+ {'dotnet add package YourCompany.Net --version 1.0.0'}
+ composer require your-company/your-company-php
+ gem install your_company
+ {'.package(url: "https://github.com/your-company/swift-sdk")'}
+ cargo add your-company
+
+
+
{/* Language Icons */}
From 067b8f1295086c94118c41362d2c1564e5d7a24b Mon Sep 17 00:00:00 2001
From: "jon.syla"
Date: Sun, 9 Aug 2026 15:05:08 +0000
Subject: [PATCH 6/6] Start the SDK card draw-in fully covering the card
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
---
fern/assets/styles.css | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/fern/assets/styles.css b/fern/assets/styles.css
index b1704b7a7a..0795184d60 100644
--- a/fern/assets/styles.css
+++ b/fern/assets/styles.css
@@ -1304,9 +1304,12 @@ h1, h2, h3 {
tab fade up rather than snap in, and it starts one softness-width off the left edge so the
card is fully covered on the first frame. */
.sdk-card-intro {
- --draw-softness: 34.5%;
+ --draw-softness: calc(127 * var(--u));
position: absolute;
- inset: 0;
+ top: 0;
+ bottom: 0;
+ left: calc(-1 * var(--draw-softness));
+ width: calc(369 * var(--u) + var(--draw-softness));
z-index: 2;
pointer-events: none;
background: linear-gradient(
@@ -1321,7 +1324,7 @@ h1, h2, h3 {
@keyframes sdk-card-draw-in {
from {
- transform: translateX(calc(-1 * var(--draw-softness)));
+ transform: translateX(0);
}
to {