Agent Skills › github/replica › features-variants

features-variants

GitHub

指导开发者使用内置功能/变体系统进行原型设计,支持多UI方案切换、A/B测试及并行展示。禁止自建切换逻辑,强制通过配置和Hook实现设计替代方案的快速迭代与对比。

starters/coreai/.agents/skills/features-variants/SKILL.md github/replica

Trigger Scenarios

尝试不同布局或设计方案 创建选项B或版本2 并排比较多个设计 添加A/B测试或设计替代方案 探索功能的替代版本

Install

npx skills add github/replica --skill features-variants -g -y
More Options

Non-standard path

npx skills add https://github.com/github/replica/tree/main/starters/coreai/.agents/skills/features-variants -g -y

Use without installing

npx skills use github/replica@features-variants

指定 Agent (Claude Code)

npx skills add github/replica --skill features-variants -a claude-code -g -y

安装 repo 全部 skill

npx skills add github/replica --all -g -y

预览 repo 内 skill

npx skills add github/replica --list

SKILL.md

Frontmatter
{
    "name": "features-variants",
    "description": "Definitive guide to the app-local prototype feature\/variant system: configuration, `useFeature()`, URL params, and anti-patterns. USE WHEN: editing `app\/features.json`, using `useFeature()` in routes, creating design alternatives, A\/B comparisons, layout options, alternate versions, or switching between design proposals. Trigger keywords: feature, variant, version, option, alternate, prototype, design option, A\/B, comparison, switch between, try a different, another way, layout option, explore, side by side."
}

Feature & Variant System Instructions

Paths below are relative to this app's directory.

What Is the Feature System?

CoreAI Sandbox has a built-in feature/variant system for tracking prototyped features and presenting multiple UI alternatives on the same page. It uses a neutral floating selector with small, elevated tab links and a brand-colored Prototype InteractionTag menu trigger to distinguish itself from the designs being prototyped.

A feature represents a prototyped change from main. A feature may:

  • Have variants — multiple design alternatives that can be switched between (e.g., different layouts)
  • Be variant-less — a single prototyped change with no alternatives (just a link to the location of the change)

Multiple features can be active simultaneously on the same page, each with their own independent variant selection.

You MUST use this system whenever a user asks to:

  • Try a different layout, design, or approach for a page or section
  • Create an "option B" or "version 2" of something
  • Compare two or more designs side by side
  • Add an A/B test or design alternative
  • Explore an alternate version of a feature

Do NOT build a custom toggle, tab switcher, or parallel component tree. The feature system already handles all of this.

For a guided walk-through tailored to designer-style requests, invoke the new-variant skill.


How It Works (Summary)

  1. Features are defined in app/features.json. Each feature may have variant options. The registry is currently empty; add definitions to its top-level features array.
  2. Active variants are encoded in the URL as repeated ?variant=feature-id--variant-id params — every combination is a shareable deep link.
  3. When a user navigates to a page with applicable features, the system automatically populates selections from valid URL values, then remembered client-navigation selections, then the first configured variant.
  4. A draggable floating switcher strip appears bottom-center by default showing each feature's variants as small, elevated router-backed tab links, when applicable variants exist and Show feature selector is enabled in the Prototype menu.
  5. Route components use the useFeature(featureId) hook to conditionally render based on the active variant.
  6. Multiple features can be active on the same page simultaneously with independent variant selections.

Architecture — Key Files

File Purpose
app/features.json App configuration: all features, routes, and variant labels
app/features/featureConfig.ts Feature schema, configuration validation, and route/URL helpers
app/features/FeatureContext.ts Feature context and public context types
app/features/FeatureProvider.tsx URL state, route matching, defaults, and floating selector composition
app/features/FeatureContext.ts (useFeature) Public hook for reading the active variant
app/features/FeatureFloatingUI.tsx Floating variant selector
app/features/FeatureMenu.tsx Prototype feature menu used by the app shell

URL Structure

Variants are encoded as repeated variant query params:

# Single feature with one variant active
?variant=agent-playground-layout--accordion

# Two features active simultaneously
?variant=agent-playground-layout--accordion&variant=code-tab--visible

# Variant-less features have no variant query param (they apply only on matching routes)

Each variant param is a feature-id--variant-id pair using kebab-case string identifiers.


Step-by-Step: Adding a New Variant to an Existing Feature

If a feature already exists in app/features.json and has variants, add a new variant:

1. Update app/features.json

Add a new entry to the variants array of the existing feature:

{
  "id": "your-new-variant",
  "label": "Your New Design Name"
}

Variant id values are kebab-case strings. Choose a descriptive, URL-friendly name.

2. Update the Route Component

In the route component that uses this feature, add a conditional branch for the new variant:

import { useFeature } from '~/features/FeatureContext';

function MyPage() {
  const variant = useFeature('agent-playground-layout');

  if (variant === 'accordion') return <AccordionLayout />;
  if (variant === 'your-new-variant') return <YourNewDesign />; // ← new
  return <DefaultLayout />; // first variant or null
}

That's it. The floating UI automatically shows the new tab link when the selector is visible on an applicable route.


Step-by-Step: Creating a New Feature

Feature WITH Variants

When the feature explores multiple design alternatives:

1. Add the feature to app/features.json

Add this object to the registry's top-level features array:

{
  "id": "agent-playground-layout",
  "label": "Agent Playground Layout",
  "notes": "What design question this feature explores.",
  "defaultRoute": "/build/agents/:agent/playground",
  "defaultParams": { "agent": "agent-001" },
  "routes": ["/build/agents/:agent/playground"],
  "variants": [
    { "id": "side-panel", "label": "Side Panel (Current)" },
    { "id": "accordion", "label": "Accordion Layout" }
  ]
}

2. Add useFeature() to the Route Component

import { useFeature } from '~/features/FeatureContext';

function MyPage() {
  const variant = useFeature('agent-playground-layout');

  if (variant === 'accordion') return <AccordionLayout />;
  return <DefaultLayout />; // 'side-panel' or null
}

Feature WITHOUT Variants

When the feature is a single prototyped change with no alternatives:

1. Add the feature to app/features.json

Add this object to the registry's top-level features array:

{
  "id": "dark-mode-revamp",
  "label": "Dark Mode Revamp",
  "notes": "Updated dark mode colors across settings page.",
  "defaultRoute": "/settings/appearance",
  "routes": ["/settings/appearance"]
}

No variants array needed. The feature appears in the Prototype InteractionTag menu as a navigation link. No useFeature() call is needed in the route component.


Field reference:

Field Required Description
id Yes Kebab-case string identifier (used in URL params)
label Yes Human-readable name shown in the floating UI
notes Yes Design context — what question does this feature explore?
defaultRoute Yes The primary route to navigate to from the Prototype menu; must be in routes
defaultParams No Fallback values for :param segments (e.g., { "agent": "agent-001" }); required when defaultRoute has required parameters
routes Yes Route patterns this feature applies to. Supports :param wildcards
variants No Array of { id: string, label: string }. Omit for variant-less features

Route pattern matching: A pattern like /build/agents/:agent/playground matches any URL of that shape. The :param segments are wildcards matched segment-by-segment.


useFeature() Return Values

const result = useFeature('feature-id');
// Returns:
//   string  — active variant id (e.g., 'accordion') if feature has variants
//   true    — if feature is variant-less and applies to current route
//   null    — if feature doesn't apply to current route

Multi-Feature Pages

A single page can have multiple features active simultaneously. Each component on the page calls useFeature() with its own feature ID independently.

const layout = useFeature('agent-playground-layout');
const codeTab = useFeature('code-tab-visibility');

// Both return their own variant independently
// URL: ?variant=agent-playground-layout--accordion&variant=code-tab-visibility--visible

The floating strip shows variant tab links for all applicable features with variants, separated by dividers.


Variant Scope — What Can Change?

A variant can change anything within its route component:

  • Full page replacement: Return entirely different component trees per variant
  • Section swap: Replace just one panel, card, or section
  • Prop changes: Same component with different props
  • Style changes: Different CSS classes per variant
  • Data presentation: Same data shown in different formats
  • Conditional features: Show/hide features like buttons, tabs, or panels

Example — Small Change (text variant)

const variant = useFeature('hero-text');
return (
  <Text preset="heading2" foreground={1}>
    {variant === 'version-b'
      ? 'Start Building with AI'
      : variant === 'version-c'
        ? 'Your AI Development Platform'
        : 'Welcome to CoreAI Sandbox'}
  </Text>
);

Example — Full Layout Swap

const variant = useFeature('playground-layout');
if (variant === 'accordion') return <AccordionLayout />;
if (variant === 'dialog') return <DialogLayout />;
return <SidePanelLayout />;

Variant-Exclusive Routes

Some variants introduce routes that only exist for that variant (e.g., a "Code" tab route that only exists when go-to-code--tab is active). If a user lands on a variant-exclusive route with the wrong variant selected, the route component should redirect:

const variant = useFeature('go-to-code');

// This route only exists for the "tab" variant — redirect otherwise
if (variant !== 'tab') return <Navigate to="../playground" replace />;

Keep this guard in the route component itself, colocated with the route that knows it's conditional. Do not add redirect logic to FeatureProvider.tsx.


Anti-Patterns — Do NOT Do These

❌ Don't ✅ Do Instead
Build a custom toggle/switch for design alternatives Use useFeature() + app/features.json
Store variant state in localStorage or React state URL query params (?variant=...) handle everything
Create separate routes for each design alternative One route, conditional rendering via useFeature()
Import feature implementation internals from app/features/featureConfig.ts or app/features/FeatureProvider.tsx in app components Use useFeature() from ~/features/FeatureContext
Hard-code variant IDs as numbers Feature and variant IDs are kebab-case strings
Add a new variant switching UI element into the product design The floating tab-link UI is the switcher — it's meta-UI
Modify app-local feature-system internals for an app feature Only modify app/features.json and the consuming component

Troubleshooting

Floating strip doesn't appear on my page:

  • Check that the route pattern in app/features.json matches your page's URL exactly (segment-by-segment)
  • :param segments match any value, but the number of segments must match
  • Ensure the applicable feature has variants and Show feature selector is enabled in the Prototype menu
  • Check browser console for errors

useFeature() returns null:

  • Verify you're passing the feature ID (string), not the variant ID
  • Verify the feature's routes array includes a pattern matching the current page

Variant tab links show but clicking doesn't change anything:

  • Ensure your component reads useFeature() and conditionally renders based on it
  • Make sure you're checking the correct variant IDs (kebab-case strings)

URL params get cleared when navigating:

  • This is expected for off-route variant params: they are removed. When returning during client navigation, valid URL selections take priority, then remembered selections, then the first configured variant. A reload uses the URL or the first variant, not remembered client-navigation state. Unrelated query params are preserved.

Version History

  • f19c050 Current 2026-11-07 08:48

Same Skill Collection

.github/extensions/replica-prototype/skills/replica-pick-and-polish/SKILL.md
.github/extensions/replica-prototype/skills/replica-publish-prototype/SKILL.md
.github/extensions/replica-prototype/skills/review-hub-feedback/SKILL.md
.github/skills/code-review/SKILL.md
.github/skills/write-tests/SKILL.md
starters/coreai/.agents/skills/coreai-ds-fluentui-react/SKILL.md
starters/coreai/.agents/skills/css-styling/SKILL.md
starters/coreai/.agents/skills/icons/SKILL.md
starters/coreai/.agents/skills/interpreting-html/SKILL.md
starters/coreai/.agents/skills/lint/SKILL.md
starters/coreai/.agents/skills/new-variant/SKILL.md
starters/coreai/.agents/skills/react-components/SKILL.md
starters/coreai/.agents/skills/routing/SKILL.md
starters/coreai/.agents/skills/start-app/SKILL.md
starters/coreai/.agents/skills/state-management/SKILL.md
starters/shared/.agents/context-templates/SKILL.md
starters/shared/.agents/skills/accessibility-audit/SKILL.md
starters/shared/.agents/skills/add-seed-data/SKILL.md
starters/shared/.agents/skills/agent-browser/SKILL.md
starters/shared/.agents/skills/browser-canvas-validation/SKILL.md
starters/shared/.agents/skills/component-design-system-review/SKILL.md
starters/shared/.agents/skills/create-prototype/SKILL.md
starters/shared/.agents/skills/developer-handoff/SKILL.md
starters/shared/.agents/skills/prepare-feedback-proposals/SKILL.md
starters/shared/.agents/skills/product-design/SKILL.md
starters/shared/.agents/skills/prototype-controls/SKILL.md
starters/shared/.agents/skills/responsive-audit/SKILL.md
starters/shared/.agents/skills/review-hub-feedback/SKILL.md
starters/shared/.agents/skills/setup-skills/SKILL.md
starters/shared/.agents/skills/visual-design-review/SKILL.md

Metadata

Files
0
Version
f19c050
Hash
7a82939b
Indexed
2026-11-07 08:48

trang chủ - Wiki
Copyright © 2011-2026 iteam. Current version is 2.156.0. UTC+08:00, 2026-11-07 09:47
浙ICP备14020137号-1