Семантическая кластеризация {D.corpus.length.toLocaleString('ru-RU')} стартапов даёт {D.TREND_CLUSTERS.length} активных направлений. Размер точки = объём кластера, цвет = направление импульса, положение по горизонтали = темп прироста к прошлой неделе.
{/* Scatter */}
{/* legend */}
горизонталь: импульсвертикаль: объём
наведите на точку или кликните для перехода к кластеру
);
}
function Legend({ dot, label }) {
return (
{label}
);
}
function TrendCard({ trend, onClick, expanded, flash, onOpen }) {
const tintHue =
trend.momentum === 'rising' ? 'emerald' :
trend.momentum === 'cooling' ? 'rose' : 'info';
// figure out italic accent in title (if title contains 'AI')
const renderTitle = (title) => {
if (/AI/.test(title)) {
const parts = title.split(/(AI)/);
return parts.map((p, i) => p === 'AI'
? AI
: {p});
}
return title;
};
return (
{renderTitle(trend.title)}
{trend.count}стартапов
{trend.recommendation || 'Сила сигнала растёт. Следующий шаг: прототип на 3 пользовательских сценариях.'}
{expanded && (
горизонт активности (30 дней)
)}
);
}
// Recommendations come from data — but if not, fall back
TrendsSection.recommendations = {
rising: 'Сила сигнала растёт. Следующий шаг: прототип на трёх пользовательских сценариях.',
steady: 'Сигнал устойчивый. Готовы к найму первого специалиста и пилоту с одним клиентом.',
cooling: 'Снижение интереса. Рекомендуем пересобрать гипотезу или приостановить направление.',
};
window.TrendsSection = TrendsSection;