diff --git a/nuxt/components/AiCapabilityDiagram.vue b/nuxt/components/AiCapabilityDiagram.vue new file mode 100644 index 0000000000..cc19b0464d --- /dev/null +++ b/nuxt/components/AiCapabilityDiagram.vue @@ -0,0 +1,214 @@ + + + diff --git a/nuxt/components/content/FfCommand.vue b/nuxt/components/content/FfCommand.vue new file mode 100644 index 0000000000..8c5b5a5241 --- /dev/null +++ b/nuxt/components/content/FfCommand.vue @@ -0,0 +1,77 @@ + + + diff --git a/nuxt/nuxt.config.ts b/nuxt/nuxt.config.ts index 76ef3c2709..7dadf6157f 100644 --- a/nuxt/nuxt.config.ts +++ b/nuxt/nuxt.config.ts @@ -366,6 +366,10 @@ export default defineNuxtConfig({ '/integrations', '/pricing', '/product', + // /ai is only linked from 11ty-generated HTML (nav, homepage), which the + // Nuxt prerender crawler never parses, so it has to be listed explicitly + // or the route is missing from nuxt/dist and every link to it breaks. + '/ai', ...collectProductRoutes(join(__dirname, 'content/products')), // Without this, @nuxtjs/sitemap only bakes /sitemap.xml statically when // isNuxtGenerate() is true, which checks for nitro.static/preset "static" - diff --git a/nuxt/pages/ai/index.vue b/nuxt/pages/ai/index.vue new file mode 100644 index 0000000000..abcbddd699 --- /dev/null +++ b/nuxt/pages/ai/index.vue @@ -0,0 +1,519 @@ + + + diff --git a/nuxt/server/middleware/legacy.ts b/nuxt/server/middleware/legacy.ts index f65792a8bc..93c012368a 100644 --- a/nuxt/server/middleware/legacy.ts +++ b/nuxt/server/middleware/legacy.ts @@ -4,7 +4,7 @@ import { defineEventHandler, proxyRequest } from 'h3' // Extend this list as pages are migrated. Trailing slashes are matched automatically. // Note: /sitemap-legacy.xml is deliberately NOT listed here — it only exists in // nuxt/public/ after a production build, so in dev it must keep proxying to 11ty's _site/. -const NUXT_ROUTES = new Set(['/terms', '/privacy-policy', '/integrations', '/resources/publications', '/sitemap.xml', '/robots.txt', '/llms.txt', '/llms-full.txt', '/contact-us', '/book-demo', '/support', '/professional-services']) +const NUXT_ROUTES = new Set(['/ai', '/terms', '/privacy-policy', '/integrations', '/resources/publications', '/sitemap.xml', '/robots.txt', '/llms.txt', '/llms-full.txt', '/contact-us', '/book-demo', '/support', '/professional-services']) // Path prefixes handled by Nuxt. Used for dynamic routes like /integrations/{id}. const NUXT_ROUTE_PREFIXES = ['/integrations/', '/raw/'] @@ -14,7 +14,7 @@ const NUXT_PREFIXES = ['/handbook', '/ebooks', '/whitepaper', '/pricing', '/docs // Top-level routes still on 11ty, not yet ported to Nuxt (everything not listed above // already falls through to the 11ty proxy by default). Remove entries here as they migrate: -// / (homepage), /about, /ai, /blueprints, /careers, /community, /events, +// / (homepage), /about, /blueprints, /careers, /community, /events, // /free-consultation, /industries, /landing, /node-red, /partners, /platform, // /use-cases, /vs, /webinars diff --git a/src/ai.njk b/src/ai.njk deleted file mode 100644 index 321f9ba389..0000000000 --- a/src/ai.njk +++ /dev/null @@ -1,215 +0,0 @@ ---- -layout: page -nohero: true -imageDescription: "Plant worker interacting with an HMI" -meta: - title: "Industrial AI: FlowFuse Expert, Governed and Built-In" - description: "Industrial AI with FlowFuse: build industrial applications with FlowFuse Expert, act on live operations behind approvals, and give your company-sanctioned AI governed access. Every AI capability on one platform, with the permissions, RBAC, and audit your plants require." -hero: - title: "Industrial AI, Governed and Built-In" - description: - - "AI capability is table stakes in 2026. Governed access to your operations is the difference." - buttonText: "Request a Demo" - buttonLink: "/book-demo/" - buttonReference: "ai" - img: ./images/ai/ai-hero.png - imgAlt: "FlowFuse Expert AI icon with connecting lines flowing out" -capabilityIntro: - title: "Every way AI shows up in your operations" - subtitle: "From accelerating how you build, to acting inside live flows, to connecting the AI your company already trusts. Each one runs on the same governed platform." -capabilityGroups: - - title: "Accelerate engineering" - eyebrow: "Build" - subtitle: "FlowFuse Expert turns intent into working industrial applications, right in the editor." - items: - - name: "AI-assisted engineering" - svgPath: "components/icons/code-bracket.svg" - status: "Available" - statusKind: "live" - description: "Generate and edit Node-RED flows, Function node JavaScript, SQL queries and dashboard UI from plain language, and ask Expert to explain any existing flow so any engineer can pick it up. It works inline in the editor your team already uses, so there is no separate tool to context-switch into. That turns unfamiliar or inherited flows into something the whole team can read and maintain." - - name: "Prompt-to-app" - svgPath: "components/icons/sparkles.svg" - status: "Available" - statusKind: "live" - description: "Describe the application you need and FlowFuse Expert agentically builds the starting flows and logic directly in your workspace. You begin from a working draft instead of a blank canvas, then refine it like any other flow. Everything it creates stays inside the platform, so the same permissions and review apply from the first node." - - name: "Build your own AI agents" - svgPath: "components/icons/squares-plus.svg" - status: "Available" - statusKind: "live" - description: "Start from an agent blueprint, like the LLM chat agent or RAG chat agent, to stand up a task-specific AI agent grounded in your own data, tools and context. It gives you a proven structure to adapt rather than wiring an agent up from scratch. With MCP servers you can give the agent access to anything, including your RAG applications. Because it runs on the platform, the agent operates within the access you grant it." - - name: "Built-in product expert" - svgPath: "components/icons/book-open.svg" - status: "Available" - statusKind: "live" - description: "A chat assistant with answers grounded in FlowFuse and Node-RED documentation, so guidance comes from the product, not stale wikis. Ask how a node works or how to approach a build and get an answer without leaving your workspace. It shortens the path from question to working flow for new and experienced users alike." - - title: "Operate with AI, safely" - eyebrow: "Operate" - subtitle: "AI that acts inside your flows and answers questions about live operations, always behind your controls." - items: - - name: "Governed autonomous operations" - svgPath: "components/icons/bolt.svg" - status: "Available" - statusKind: "live" - description: "Platform Automations let AI act on live systems, with every write behind an approval card, session-scoped and fully audited. A person approves, edits or rejects each proposed change before it reaches a machine. Nothing runs outside the permissions and RBAC that already govern your teams." - - name: "Ask your plant anything" - svgPath: "components/icons/chat-bubble-left-right.svg" - status: "Available" - statusKind: "live" - description: "In Insights mode, ask questions in natural language and get answers grounded in live machine state, alarms and logs. Operators and engineers can check what is happening on the floor without building a report or querying a database by hand. Table and MQTT-broker reading are coming soon." - - name: "Automated visual inspection" - svgPath: "components/icons/camera.svg" - status: "Available" - statusKind: "live" - description: "Run ONNX vision models inside flows next to the machine, with camera ingest over RTSP, for inference that works offline and keeps data on your network. Detection results flow into the same logic as any other signal, so you can trigger alerts or actions from what the model sees. Running at the edge means no round trip to the cloud and no image data leaving the plant." - - name: "Use any model within flows" - svgPath: "components/icons/cog-6-tooth.svg" - status: "Available" - statusKind: "live" - description: "Certified LLM nodes bring OpenAI, Anthropic, Gemini or local models via Ollama into any flow with your own keys. Choose the provider that fits each task, or keep everything on local models when data cannot leave your network. Because you supply the keys, model access and spend stay under your control." - - title: "Connect and govern your AI" - eyebrow: "Connect" - subtitle: "Give the AI your company already trusts a governed door into operations, on a boundary you control." - items: - - name: "Connect your company's AI" - svgPath: "components/icons/arrows-right-left.svg" - status: "Coming soon" - statusKind: "soon" - description: "Expose flows as MCP tools so the AI your company already sanctioned, like Claude or Copilot, can reach operational data through a permissioned boundary. The AI reaches only what you expose, on the terms you set, rather than getting direct access to plant systems. This is our most-requested capability and is in active development." - - name: "AI that uses your tools" - svgPath: "components/icons/puzzle-piece.svg" - status: "Available" - statusKind: "live" - description: "Build your own MCP servers and let Insights-mode agents call your tools and services as part of a workflow. Wrap an internal API or system as a tool once, then let agents use it wherever it fits. The agent stays inside the workflow you designed, calling only the tools you register." -governance: - title: "Governance you can prove" - subtitle: "The control plane every AI action runs through, the same one that governs your teams." - items: - - svgPath: "components/icons/check-circle.svg" - title: "Approval cards on writes" - description: "Every write action AI proposes waits for a human to approve, reject or edit." - - svgPath: "components/icons/lock-closed.svg" - title: "Per-tool permissions" - description: "Grant read, write or delete per tool and per team, so AI only reaches what you allow." - - svgPath: "components/icons/shield-check.svg" - title: "Role-based access" - description: "The same RBAC that governs your teams governs what AI can see and do." - - svgPath: "components/icons/clipboard-document-check.svg" - title: "Audit on everything" - description: "Every action AI touches is logged, so you can show exactly what happened and when." ---- - -
-
-
-
-
-
-

- {{ hero.title | safe }} -

-

The platform is the control plane. AI is the accelerator.

- {% for p in hero.description %} -

{{ p | safe }}

- {% endfor %} -
-
- - {% include "components/ai-chat-interface.njk" %} - - - {% include "components/ai-expert-modal.njk" %} -
-
-
-
-
-
- - -
-
-
-
- {% image "./images/ai/ai-ui.png", "FlowFuse Expert showing AI-generated flow suggestions", [1200] %} -
-
-
-
- -
-
-
-

{{ capabilityIntro.title | safe }}

-

{{ capabilityIntro.subtitle }}

-
- {% for group in capabilityGroups %} -
- -
-

- 0{{ loop.index }} - {{ group.eyebrow }} -

-

{{ group.title }}

-

{{ group.subtitle }}

-
- -
- {% for item in group.items %} -
-
- -
-
- {{ item.name }} - {% if item.statusKind == 'soon' %} - Coming soon - {% endif %} -
-

{{ item.description | safe }}

-
-
-
- {% endfor %} -
-
- {% endfor %} -
-
- -
-
-
-

{{ governance.title | safe }}

-

{{ governance.subtitle }}

-
-
- {% for g in governance.items %} -
-
{% include g.svgPath %}
-

{{ g.title }}

-

{{ g.description }}

-
- {% endfor %} -
-
-
- - - - -
-
-

Where AI meets your operations

-

The use cases pair with FlowFuse AI, from governed agent access to AI-assisted monitoring.

- {% set featuredUseCases = ["production-monitoring", "shop-floor-communication"] %} - {% include "components/use-case-links.njk" %} -

See all use cases

-
-
- diff --git a/src/css/style.css b/src/css/style.css index 0be94f9c0a..8bfa5679cd 100644 --- a/src/css/style.css +++ b/src/css/style.css @@ -482,6 +482,35 @@ dl.message-properties > dd { @apply border-green-500 text-green-400; } +/* Stacked variant: the address block on its own, with the copy control below it as + a full-width primary button rather than a chip inside the dark block. + + Why it exists: side by side, the inline button plus the block's own padding took + 106px of the AI page's 293px column, leaving 186px for an address that needs + 236px at 14px - so it broke across three lines. Shrinking the type was the wrong + trade for something you are about to paste. Below the block the address gets the + full column and stays on one line, and the button becomes the same object as the + CTAs in the columns beside it instead of a third kind of control. + + Defined after the base rules rather than with higher specificity, so the two + stay legible as "default" and "the variant that overrides it". */ +.ff-command--stacked { + flex-direction: column; + align-items: stretch; + gap: 0.75rem; + padding: 0; + background-color: transparent; +} +.ff-command--stacked .ff-command__text { + display: block; + width: 100%; + background-color: #0e1114; + white-space: nowrap; + overflow-x: auto; + overscroll-behavior-x: contain; + @apply rounded-lg p-4; +} + /* Event banner */ @@ -3218,24 +3247,6 @@ lite-youtube::before { height: 1.25rem; } -/* AI page ("/ai/") capabilities: sticky-header, scrolling-items layout. - The left group header pins while that group's icon-marked blocks scroll on - the right, then the next group's header takes over. These rules live in - the UNLAYERED block on purpose: the Tailwind `utilities` layer is - outranked by unlayered top-level rules, so the load-bearing sticky - positioning is placed here to avoid being silently overridden. */ -@media (min-width: 768px) { - .ff-cap-sticky { - position: -webkit-sticky; - position: sticky; - /* clear the sticky site header (roughly 75px) with breathing room */ - top: 100px; - /* take natural height inside the taller grid row so there is travel - room for the pin; without this the column stretches full height */ - align-self: start; - } -} - /* Capability marker icon: the item's own icon stands in for the old number chip, so the blocks read as a parallel list rather than an ordered sequence. Sized slot, indigo to match the brand accent, aligned to the block top. */ @@ -3248,11 +3259,157 @@ lite-youtube::before { height: 2.5rem; color: var(--color-indigo-600); } +/* "Differs by agent" clause: sits under a capability whose behaviour is not identical + on the FlowFuse Expert path and the bring-your-own-agent path. Quieter than the body + copy, and set off by a rule, so it reads as a qualification rather than a feature. */ +.ff-cap-differs { + font-size: 0.875rem; + line-height: 1.6; + color: var(--color-gray-500); + padding-left: 0.875rem; + border-left: 2px solid var(--color-indigo-200); +} + +/* Agent tab: a segmented control on the tinted rail, not a row of CTA buttons. + The brand's solid indigo marks the active one; the rest stay quiet until hovered. + Sizing and colour are utility classes on the element - only the focus ring lives + here, because the ring has to clear the pill on all four sides inside a scroller + that would otherwise clip it. */ +.ff-agent-tab:focus { + outline: none; +} +.ff-agent-tab:focus-visible { + outline: 2px solid var(--color-indigo-600); + outline-offset: 2px; +} +/* The brand marks are , so they keep their own colours; our own glyphs are + masked spans that inherit currentColor and turn white with the label. */ +.ff-agent-tab img { + flex: none; +} + +/* The three step CTAs are three different elements - CtaSignUp's UButton, an + and the copy