Model
- Cost/1M
- Overall
{#each categoryKeys as cat}
- {cat}
{/each}
@@ -221,7 +222,7 @@
>
- {model.cost}
@@ -234,7 +235,7 @@
{#each categoryKeys as cat}
{model.categories[cat]}%
diff --git a/src/routes/(marketing)/(components)/ai.svelte b/src/routes/(marketing)/(components)/ai.svelte
index 56b867663f0..c522d00d76c 100644
--- a/src/routes/(marketing)/(components)/ai.svelte
+++ b/src/routes/(marketing)/(components)/ai.svelte
@@ -1,6 +1,4 @@
@@ -90,133 +76,108 @@
-
-
-
-
- MCP - Connect AI agents to your Appwrite backend.
- No custom integrations required.
-
+
+
+
-
+
+
+
+
+ MCP - Connect AI agents to your Appwrite backend.
+ No custom integrations required.
+
+
+
+
-
-
-
-
- Skills - Teach AI agents your backend,
- so they always make the right call.
-
+
+
-
+
+
+
+
+ Skills - Teach AI agents your backend,
+ so they always make the right call.
+
+
+
+
-
+
-
-
-
-
- {#each tools as tool, i}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {/each}
-
-
-
-
-
-
-
+
+
{#each tools as tool, i}
-
handleMobileTap(e, i)}
- class="border-smooth relative flex h-16 w-full items-center justify-center border-r border-dashed {i ===
- 0
- ? 'border-l'
- : ''}"
- style="--primary-color:{tool.primary};--secondary-color:{tool.secondary}"
- >
+
-
-
-
- {#if activeMobileIndex === i}
-
- {/if}
-
+ class="pointer-events-none absolute inset-0 z-0 bg-gradient-to-tl from-(--primary-color)/4 to-(--secondary-color)/10 opacity-0 transition-opacity group-hover:opacity-100"
+ >
+
+
+
+
+
+
+
+
+
+
+
{/each}
-
+
diff --git a/src/routes/(marketing)/(components)/bento/(animations)/auth.svelte b/src/routes/(marketing)/(components)/bento/(animations)/auth.svelte
index 0b4beb6e60f..8ec7e04d091 100644
--- a/src/routes/(marketing)/(components)/bento/(animations)/auth.svelte
+++ b/src/routes/(marketing)/(components)/bento/(animations)/auth.svelte
@@ -98,13 +98,15 @@
Email
Create Password
Jayden
diff --git a/src/routes/(marketing)/(components)/bento/(animations)/sites.svelte b/src/routes/(marketing)/(components)/bento/(animations)/sites.svelte
index dfffb06af01..058bdd2ec68 100644
--- a/src/routes/(marketing)/(components)/bento/(animations)/sites.svelte
+++ b/src/routes/(marketing)/(components)/bento/(animations)/sites.svelte
@@ -171,7 +171,7 @@
Deployment logs
Building
diff --git a/src/routes/(marketing)/(components)/bento/bento.svelte b/src/routes/(marketing)/(components)/bento/bento.svelte
index a4c292cf6f8..08b8d9af3e8 100644
--- a/src/routes/(marketing)/(components)/bento/bento.svelte
+++ b/src/routes/(marketing)/(components)/bento/bento.svelte
@@ -52,8 +52,8 @@
-
- Build like a team of hundreds
+
+ All the services you need in one platform
diff --git a/src/routes/(marketing)/(components)/case-studies.svelte b/src/routes/(marketing)/(components)/case-studies.svelte
index eea6f70a82d..fa8d5b44e39 100644
--- a/src/routes/(marketing)/(components)/case-studies.svelte
+++ b/src/routes/(marketing)/(components)/case-studies.svelte
@@ -63,7 +63,7 @@
{#each studies as study, index}
diff --git a/src/routes/(marketing)/(components)/case-study-card.svelte b/src/routes/(marketing)/(components)/case-study-card.svelte
index 029e2ccdc2e..77549f98a2d 100644
--- a/src/routes/(marketing)/(components)/case-study-card.svelte
+++ b/src/routes/(marketing)/(components)/case-study-card.svelte
@@ -16,7 +16,8 @@
diff --git a/src/routes/(marketing)/(components)/hero.svelte b/src/routes/(marketing)/(components)/hero.svelte
index 462c7c6451b..ed8bb3c5188 100644
--- a/src/routes/(marketing)/(components)/hero.svelte
+++ b/src/routes/(marketing)/(components)/hero.svelte
@@ -125,7 +125,7 @@
/** Aside: clip mockup bleed. Stacked: avoid clipping long titles on tablet (overflow-hidden + nowrap). */
layoutAside
? 'overflow-hidden py-10 md:py-0 lg:min-h-[680px]'
- : 'overflow-hidden overflow-y-clip pt-10 pb-6 md:pt-14 md:pb-8 lg:min-h-[560px] lg:pt-16'
+ : 'overflow-hidden overflow-y-clip pt-10 pb-3 md:pt-14 md:pb-4 lg:min-h-[560px] lg:pt-16'
)}
>
-
+
shownFrameworkStrip[i] ?? null
- )
- );
-
- const hasMoreFrameworks = $derived(
- frameworkBatchStart + FRAMEWORKS_GALLERY_PAGE_SIZE < allFrameworkStrip.length
- );
- const hasFrameworkStripPagination = $derived(
- allFrameworkStrip.length > FRAMEWORKS_GALLERY_PAGE_SIZE
- );
-
- const marketingFrameworkMarquee = $derived(
- allFrameworkStrip.map((p) => ({ ...p, trackPrefix: 'technologies' as const }))
- );
-
const marketingAiStrip: StripItem[] = [
{
name: 'Claude Code',
@@ -97,10 +67,58 @@
}
];
- const marketingCombinedMarqueeMobile = $derived([
- ...marketingFrameworkMarquee,
- ...marketingAiStrip.map((p) => ({ ...p, trackPrefix: 'ai-tooling' as const }))
- ]);
+ /**
+ * First gallery page: `FRAMEWORKS_GALLERY_PAGE_SIZE` tiles = early frameworks (skipping some to
+ * make room) plus all AI marks in `marketingAiStrip` order (…Lovable, then OpenCode).
+ */
+ const DEFERRED_FIRST_PAGE_FRAMEWORKS = new Set(['Nuxt', 'Angular', 'Qwik', 'Refine', 'Solid']);
+ const FIRST_PAGE_AI_COUNT = marketingAiStrip.length;
+
+ /** Frameworks and AI tools in one list (desktop paginated strip + mobile marquee). */
+ const unifiedStrip = $derived.by(() => {
+ const firstPageFrameworkSlots = FRAMEWORKS_GALLERY_PAGE_SIZE - FIRST_PAGE_AI_COUNT;
+ const firstPageFw: MarqueeMobileEntry[] = [];
+ for (const p of allFrameworkStrip) {
+ if (DEFERRED_FIRST_PAGE_FRAMEWORKS.has(p.name)) continue;
+ firstPageFw.push({ ...p, trackPrefix: 'technologies' });
+ if (firstPageFw.length >= firstPageFrameworkSlots) break;
+ }
+ const usedNames = new Set(firstPageFw.map((e) => e.name));
+ const firstPageAi = marketingAiStrip
+ .slice(0, FIRST_PAGE_AI_COUNT)
+ .map((p) => ({ ...p, trackPrefix: 'ai-tooling' as const }));
+ for (const p of firstPageAi) usedNames.add(p.name);
+
+ const restFw: MarqueeMobileEntry[] = [];
+ for (const p of allFrameworkStrip) {
+ if (usedNames.has(p.name)) continue;
+ restFw.push({ ...p, trackPrefix: 'technologies' });
+ usedNames.add(p.name);
+ }
+ const restAi = marketingAiStrip
+ .slice(FIRST_PAGE_AI_COUNT)
+ .map((p) => ({ ...p, trackPrefix: 'ai-tooling' as const }));
+
+ return [...firstPageFw, ...firstPageAi, ...restFw, ...restAi];
+ });
+
+ /** Which page of `FRAMEWORKS_GALLERY_PAGE_SIZE` icons is shown. */
+ let stripBatchIndex = $state(0);
+
+ const stripBatchStart = $derived(stripBatchIndex * FRAMEWORKS_GALLERY_PAGE_SIZE);
+
+ /** Always `FRAMEWORKS_GALLERY_PAGE_SIZE` slots so row width stays even when the last page has fewer icons. */
+ const unifiedStripSlots = $derived(
+ Array.from(
+ { length: FRAMEWORKS_GALLERY_PAGE_SIZE },
+ (_, i) => unifiedStrip[stripBatchStart + i] ?? null
+ )
+ );
+
+ const hasMoreStrip = $derived(
+ stripBatchStart + FRAMEWORKS_GALLERY_PAGE_SIZE < unifiedStrip.length
+ );
+ const hasStripPagination = $derived(unifiedStrip.length > FRAMEWORKS_GALLERY_PAGE_SIZE);
const aiDocLinks = [
{ label: 'MCP servers', href: '/docs/tooling/ai/mcp-servers' },
@@ -128,16 +146,16 @@
trackEvent(`platforms-ai-doc-${label.toLowerCase().replace(/\s+/g, '-')}-click`);
}
- function stepFrameworkStripBack() {
- if (frameworkBatchIndex > 0) {
- frameworkBatchIndex -= 1;
+ function stepStripBack() {
+ if (stripBatchIndex > 0) {
+ stripBatchIndex -= 1;
trackEvent('technologies-framework-strip-back-click');
}
}
- function stepFrameworkStripForward() {
- if (hasMoreFrameworks) {
- frameworkBatchIndex += 1;
+ function stepStripForward() {
+ if (hasMoreStrip) {
+ stripBatchIndex += 1;
trackEvent('technologies-framework-strip-advance-click');
}
}
@@ -155,9 +173,9 @@
'dark:disabled:hover:text-greyscale-300'
)}
aria-controls="platforms-framework-strip-icons"
- aria-label="Show previous quick-start frameworks"
- disabled={frameworkBatchIndex === 0}
- onclick={stepFrameworkStripBack}
+ aria-label="Show previous frameworks and AI tools"
+ disabled={stripBatchIndex === 0}
+ onclick={stepStripBack}
>
{/snippet}
-{#snippet aiToolingStripCells()}
-
- {#each marketingAiStrip as platform, platformIndex (platform.name)}
-
-
-
- {/each}
-
-{/snippet}
-
{#snippet marqueeMobileRow(items: MarqueeMobileEntry[])}
-
-
-
+
+
+
{platformsHeading}
-
- {@render marqueeMobileRow(marketingCombinedMarqueeMobile)}
-
-
+
+
+
+ {@render marqueeMobileRow(unifiedStrip)}
+
+
diff --git a/src/routes/(marketing)/(components)/quick-start-strip-items.ts b/src/routes/(marketing)/(components)/quick-start-strip-items.ts
index 916d8b0330d..a37f4dfc093 100644
--- a/src/routes/(marketing)/(components)/quick-start-strip-items.ts
+++ b/src/routes/(marketing)/(components)/quick-start-strip-items.ts
@@ -28,10 +28,10 @@ export type QuickStartStripItem = {
light: string;
};
-/** Icons per page on the homepage strip and headline strip (paginated on large viewports). */
-export const FRAMEWORKS_GALLERY_PAGE_SIZE = 10;
+/** Icons per page on the homepage paginated strip (large viewports; full-width row). */
+export const FRAMEWORKS_GALLERY_PAGE_SIZE = 14;
-/** First screen of homepage strip; order matches the start of `allFrameworkStrip` (length matches page size). */
+/** Priority order for the start of `allFrameworkStrip` (homepage / docs ordering). */
export const MARKETING_HOME_FIRST_NAMES = [
'React',
'Next.js',
diff --git a/src/routes/(marketing)/+page.svelte b/src/routes/(marketing)/+page.svelte
index b40c063098e..67ad3180a97 100644
--- a/src/routes/(marketing)/+page.svelte
+++ b/src/routes/(marketing)/+page.svelte
@@ -32,7 +32,7 @@
Just like a Swiss Army Knife you can choose and use the
tools that you need with Appwrite.
Just like a Swiss Army Knife you can choose and use the
tools that you need with Appwrite.
-
{button.label}
+
{button.label}
{button.description}
diff --git a/src/routes/startups/case-studies-light.svelte b/src/routes/startups/case-studies-light.svelte
index 2704663cd92..14c429fda94 100644
--- a/src/routes/startups/case-studies-light.svelte
+++ b/src/routes/startups/case-studies-light.svelte
@@ -51,7 +51,7 @@
{#each studies as study, index}
diff --git a/static/images/blog/customer-story-storealert/cover-menu.webp b/static/images/blog/customer-story-storealert/cover-menu.webp
new file mode 100644
index 00000000000..37eae18d4de
Binary files /dev/null and b/static/images/blog/customer-story-storealert/cover-menu.webp differ
diff --git a/static/images/blog/customer-story-storealert/cover.png b/static/images/blog/customer-story-storealert/cover.png
index ac21d2c857d..78b6f593993 100644
Binary files a/static/images/blog/customer-story-storealert/cover.png and b/static/images/blog/customer-story-storealert/cover.png differ
diff --git a/static/images/testimonials/phil-avatar.webp b/static/images/testimonials/phil-avatar.webp
new file mode 100644
index 00000000000..c0a42ebebae
Binary files /dev/null and b/static/images/testimonials/phil-avatar.webp differ