Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/apursley2012/sys-core/llms.txt

Use this file to discover all available pages before exploring further.

SignalBars renders a compact five-bar signal-strength indicator styled in mint-comms green — the visual shorthand throughout sys-core for “how strong is this signal?”. Bars scale in height from left to right (20 % to 100 % of the component’s 16 px height), and active bars animate with a slow pulsing opacity loop using Framer Motion. Inactive bars are rendered at 20 % opacity as a faint background scale. The component is used wherever the site needs to communicate relative strength, confidence, or prominence — on article cards (via a signalStrength field) and alongside skill entries as a quick visual complement to the FrequencyGauge arcs.

Visual Role

Signal bars translate abstract numeric values into an immediately recognisable visual metaphor: mobile signal strength. In the context of a spacecraft comms interface, signal strength is a natural proxy for skill fluency or article significance. An article with a signalStrength of 5 is a flagship transmission; a skill at level 90+ maps to 5 bars; a beginner skill at level 30 might show only 2 bars. The mint-comms green (rgba(110, 231, 183, ...)) is shared with the RadarSweep component, reinforcing a visual grouping of “comms and scanning” instrumentation. Active bars have a subtle box-shadow glow (shadow-[0_0_5px_rgba(110,231,183,0.5)]) and animate with a staggered pulse — each bar has a delay of bar index × 0.2 s, creating a ripple effect across the five bars.

Usage

Pass a strength value from 1 to 5. Values outside this range will still render (bars with index ≤ strength are active), but 1–5 is the intended scale.
import SignalBars from "../../components/cosmic/SignalBars.js";

// 4-bar strength (e.g. for an article or skill card)
export default function ArticleCard({ article }) {
  return (
    <div className="flex items-center justify-between">
      <span className="text-off-white font-mono text-sm">{article.title}</span>
      <SignalBars strength={article.signalStrength} />
    </div>
  );
}
// Alongside a skill name in a list
import SignalBars from "../../components/cosmic/SignalBars.js";

function skillLevelToBars(level) {
  // Map 0–100 skill level to 1–5 bars
  return Math.max(1, Math.ceil(level / 20));
}

export default function SkillRow({ skill }) {
  return (
    <div className="flex items-center gap-3">
      <span className="text-off-white font-mono text-sm flex-1">{skill.name}</span>
      <SignalBars strength={skillLevelToBars(skill.level)} />
    </div>
  );
}
// With a custom className for spacing or alignment
import SignalBars from "../../components/cosmic/SignalBars.js";

export default function CompactIndicator() {
  return (
    <SignalBars strength={3} className="ml-auto" />
  );
}

Props

strength
number
required
A number from 1 to 5 representing the number of active (lit) bars. Bars with index ≤ strength render in full mint-comms green with a glow and pulse animation. Bars with index > strength render at mint-comms/20 (20 % opacity) as inactive scale marks.
className
string
default:"\"\""
Additional Tailwind classes appended to the outer flex container. Use for margin, alignment, or positioning adjustments. The container is flex items-end gap-1 h-4 — classes added here extend rather than replace that base.

Mapping Skill Levels to Bars

SignalBars uses a 1–5 scale, while skill entries in data/skills.js use a 0–100 level field. The standard mapping used across the Skills section is:
level rangeBars displayedInterpretation
1 – 201Beginner
21 – 402Developing
41 – 603Competent
61 – 804Proficient
81 – 1005Expert
// Utility function for converting skill level to bar count
function skillLevelToBars(level) {
  return Math.max(1, Math.ceil(level / 20));
}
With this mapping, the current skills data resolves as:
SkillLevelBars
React / Next.js955
TypeScript905
Tailwind CSS855
Framer Motion804
Node.js855
PostgreSQL804
Redis754
GraphQL704
Git / CI/CD905
Docker754
AWS / Vercel804
Jest / Vitest855
UI/UX Design855
Tech Writing905
Mentorship804
Agile/Scrum855

Implementation Notes

Bar geometry

Each of the five bars is a Framer Motion <motion.div> with:
  • Width: w-1.5 (6 px) with rounded-t-sm top corners.
  • Height: inline style={{ height: \$%` }}` — bar 1 is 20 % tall, bar 5 is 100 % tall.
  • Colour: active bars use bg-mint-comms shadow-[0_0_5px_rgba(110,231,183,0.5)]; inactive bars use bg-mint-comms/20.
The outer container is flex items-end gap-1 h-4, so all bars share the same bottom baseline and shorter bars appear to grow upward from it.

Framer Motion pulse animation

Active bars animate with:
animate: { opacity: [0.7, 1, 0.7] }
transition: { duration: 2, repeat: Infinity, delay: barIndex * 0.2, ease: "easeInOut" }
The staggered delay creates a left-to-right ripple across the active bars. Inactive bars have an empty animate={{}} object, so they render statically without any Framer Motion overhead.
SignalBars depends on Framer Motion via the ../../assets/proxy.js import alias in the built dist. Ensure Framer Motion is available in the project environment before using this component outside the standard Vite build.
Use SignalBars consistently at the same size across the site — its h-4 (16 px) container height is chosen to align with one-line monospace text at text-sm. Avoid overriding the height via className, as this will break the bar-height percentage calculations.

Build docs developers (and LLMs) love