/** * openvibe-shared/glyphs.js — the OpenVibe glyphs: one registry for every icon the network draws (plan L32; the owner, * 2026-10-31: "our own custom icon system… replace Font Awesome… with our own… through openvibe.design"). * * One hand for all of them, the mark's: a 24-unit grid, 2-unit round strokes, nothing filled but a dot. The kit's icons * (kit.js) are the first of them; the drawings below fill in what the network asked Font Awesome for most, and FA * maps every Font Awesome name in use to the glyph that stands for it, so a page can drop Font Awesome as soon as its * names are covered. Brand logos (GitHub, YouTube, Discord…) are not ours to redraw and stay as they are. * * const glyphs = require('openvibe-shared/glyphs'); * glyphs.NAMES every glyph's name * glyphs.path(name) its drawing (the inside of a 24-unit SVG), or '' * glyphs.svg(name, { size, title, style }) a standalone SVG, or '' * glyphs.fromFa('fa-tower-broadcast') → 'live' the glyph for a Font Awesome name (with or without fa-), or null * glyphs.markup('live', { title, cls }) , OpenVibe's own markup (4.231.0) * glyphs.fromFaClasses('fa-solid fa-eye me-2') { icon: 'eye', cls: ['ovg-fill', 'me-2'], … } (scripts/fa-to-ov.js) * glyphs.FA { 'tower-broadcast': 'live', … } * glyphs.META[name] { by, tags } who drew it and what it is for (openvibe.design/icons) * * In a page, ov-glyphs.js (built from this file by scripts/build-glyphs.js) swaps for the glyph, * in place, and leaves a name it does not know to Font Awesome. */ (function (root, factory) { const api = factory(typeof module === 'object' && module.exports ? require('./kit') : root.OpenVibeKit); if (typeof module === 'object' && module.exports) { module.exports = api; return; } root.OpenVibeGlyphs = api; })(typeof globalThis !== 'undefined' ? globalThis : this, function (kit) { 'use strict'; // ── The drawings that join the kit's: 24-unit grid, strokes only (round caps and joins), a dot is a 0.01 line ── const DRAWN = { // 4.238.0 (the owner, 11-13: "regenerate the bell icon like that's ringing"): the bell with its two waves. 'bell-ring': '', scissors: '', tree: '', pin: '', volume: '', mute: '', tent: '', food: '', train: '', water: '', dish: '', history: '', film: '', circle: '', sliders: '', leaf: '', clipboard: '', gauge: '', save: '', plug: '', // 4.101.0: a jigsaw piece (a browser extension, an add-on, a plug-in), knobs out on top and right, notches in. puzzle: '', compress: '', expand: '', care: '', city: '', wrench: '', music: '', 'eye-off': '', plane: '', fire: '', nodes: '', // Two towers, the cable between them and the deck (2026-11-11 review: the old one read as a bank). bridge: '', 'check-circle': '', 'x-circle': '', 'alert-circle': '', news: '', camera: '', crown: '', wallet: '', chip: '', id: '', brain: '', snow: '', mountain: '', 'mic-off': '', database: '', layers: '', hash: '', text: '', enter: '', language: '', idea: '', dollar: '', target: '', 'arrow-right': '', 'arrow-left': '', 'arrow-up': '', 'arrow-down': '', shirt: '', route: '', reply: '', smile: '', archive: '', 'user-check': '', ticket: '', tack: '', store: '', keyboard: '', gavel: '', drop: '', wifi: '', branch: '', // 2026-11-12: the tools, machines and creative shapes the icon audit found missing (plan L32 I1/I2). binoculars: '', telescope: '', microscope: '', gpu: '', cpu: '', memory: '', joystick: '', wand: '', 'layers-plus': '', // 4.63.0: the Font Awesome names the network still used most (openvibe.design/icons' "Still Font Awesome", 10-31). restroom: '', shelter: '', 'hot-tub': '', umbrella: '', parking: '', skull: '', group: '', medical: '', shapes: '', headphones: '', drive: '', 'check-double': '', tv: '', toolbox: '', table: '', scale: '', road: '', money: '', 'heart-pulse': '', heading: '', fist: '', 'fast-forward': '', rewind: '', 'file-code': '', dice: '', contrast: '', briefcase: '', timeline: '', seedling: '', rocket: '', 'list-ordered': '', lifebuoy: '', infinity: '', inbox: '', door: '', card: '', storm: '', // 4.68.0 (plan L49): the rest of the names Live still asked Font Awesome for (the owner, 2026-11-01: "why Font // Awesome? … OpenVibe Design's icon system for all our icons"). 'trend-up': '', 'trend-down': '', 'chevrons-left': '', 'chevrons-right': '', sort: '', 'sort-asc': '', share: '', 'arrows-h': '', move: '', // A viewfinder with its centre (2026-11-11 review: four tiny arrows crowded at 16 px). focus: '', at: '', box: '', bug: '', megaphone: '', burst: '', 'camera-flip': '', 'camera-off': '', car: '', child: '', donate: '', record: '', 'plus-circle': '', 'minus-circle': '', clapper: '', 'clipboard-check': '', cc: '', 'cloud-off': '', commit: '', 'chat-off': '', compass: '', cookie: '', couch: '', cubes: '', ear: '', eraser: '', laugh: '', fish: '', finish: '', flask: '', 'folder-tree': '', skip: '', gem: '', ghost: '', grip: '', hammer: '', handshake: '', wizard: '', 'heart-broken': '', hourglass: '', lungs: '', 'link-off': '', mask: '', mug: '', paw: '', walk: '', 'phone-off': '', piggy: '', airplane: '', print: '', quote: '', radio: '', ranking: '', recycle: '', rss: '', scroll: '', signature: '', square: '', sword: '', columns: '', 'thumbs-up': '', undo: '', 'user-circle': '', 'user-lock': '', 'user-minus': '', 'user-pen': '', 'user-tag': '', 'user-off': '', weight: '', wind: '', window: '', 'window-restore': '', 'align-left': '', slash: '', // 4.69.0: an open book for fa-book-open (the closed one read as an empty square at 14 px). 'book-open': '', // A spinner is never drawn as one (the owner, 2026-10-31: nothing spins): three dots that take turns (ov-glyphs.js). busy: '', }; // ── Small sizes (4.69.0, plan L49; the owner, 2026-11-01: "really tiny icons… a solid colour rather than the border // lines… so all our icons look nice across sizes"). A solid drawing for the glyphs most often shown small: filled // shapes, holes cut with fill-rule evenodd, a line that must stay a line as class "ln". ov-glyphs.js draws both and // shows the solid one when the icon is 18 px or smaller (pure CSS, see scripts/build-glyphs.js); a glyph without // one draws its lines heavier there instead. const SOLID = Object.freeze({ handshake: '', focus: '', // 4.182.0, the last five shapes: a car, a door, a podium, a rocket and a camera that flips. After these, every // glyph without a solid drawing is one made of lines, which thickens when small instead. car: '', door: '', ranking: '', rocket: '', 'camera-flip': '', // 4.182.0, sixth batch: things with one outline (an aeroplane, a burst, a fish, a shoe, a sword, a mask, a // piggy bank), a couch, a coin over a box, two folders on a tree, a chequered flag, and two people. airplane: '', burst: '', fish: '', shoe: '', sword: '', donate: '', mask: '', couch: '', child: '', walk: '', finish: '', piggy: '', 'folder-tree': '', // 4.182.0, fifth batch: a laughing face, a cookie, a radio, a toolbox, a task, two windows, captions, an // eraser, a seedling and a hammer. laugh: '', cookie: '', radio: '', toolbox: '', task: '', 'window-restore': '', cc: '', eraser: '', seedling: '', hammer: '', // 4.182.0, the "-off" family: the shape is cut along the slash (a band a little wider than the line), so the // slash stays a line across it, as eye-off and mic-off already do. 'chat-off': '', 'user-off': '', 'camera-off': '', 'cloud-off': '', // 4.182.0, third batch: a die, a lifebuoy, cubes, a paw, a weight, and a person with a pen or a tag. dice: '', lifebuoy: '', cubes: '', paw: '', weight: '', 'user-pen': '', 'user-tag': '', // 4.182.0, second batch: marks in a disc, the media keys, and a few things (flame, mug, clapper, a person with // a badge). A mark inside a filled shape is cut out of it; a thin part that must stay a line is class "ln". 'plus-circle': '', 'minus-circle': '', contrast: '', rewind: '', 'fast-forward': '', skip: '', flame: '', 'heart-broken': '', clapper: '', mug: '', 'user-minus': '', 'user-lock': '', 'clipboard-check': '', 'file-code': '', // 4.182.0: thirteen more shapes that are shown small (frames, cards and the person in a circle). A frame's // inner line becomes a gap between two filled panels, so the shape still reads at 14 px. grid: '', square: '', more: '', record: '', window: '', sidebar: '', columns: '', table: '', card: '', briefcase: '', inbox: '', 'user-circle': '', compass: '', print: '', // 4.73.0: the most-used shapes on the sites (Live's sweep, 2026-11-01) get their solid drawing too. copy: '', scissors: '', volume: '', mute: '', robot: '', film: '', clipboard: '', computer: '', sliders: '', pencil: '', save: '', plug: '', puzzle: '', chart: '', gear: '', search: '', game: '', idea: '', wrench: '', target: '', nodes: '', 'book-open': '', book: '', fire: '', info: '', 'alert-circle': '', alert: '', heart: '', star: '', bell: '', user: '', members: '', chat: '', eye: '', clock: '', pin: '', home: '', camera: '', video: '', mic: '', lock: '', shield: '', crown: '', trophy: '', tag: '', zap: '', play: '', pause: '', spark: '', flag: '', folder: '', file: '', image: '', cloud: '', moon: '', drop: '', 'check-circle': '', 'x-circle': '', smile: '', calendar: '', 'thumbs-up': '', megaphone: '', gem: '', ghost: '', trash: '', coin: '', live: '', gift: '', music: '', // 4.80.0: the next most-used shapes (Shared's usage sweep, 2026-11-01), drawn the same way; an "off" glyph // keeps its slash as a line, with the shape cut back from it. globe: '', circle: '', plane: '', mail: '', 'eye-off': '', key: '', gauge: '', server: '', 'user-check': '', 'mic-off': '', palette: '', dish: '', layers: '', phone: '', money: '', care: '', news: '', hand: '', tack: '', help: '', invite: '', ticket: '', cart: '', box: '', store: '', map: '', sun: '', leaf: '', headphones: '', tv: '', bug: '', terminal: '', database: '', // 4.98.0: the most-used places and things without one (Design's usage count, 2026-11-02): tree, tent, train, // mountain, city, id, wallet, chip, restroom, brain. tree: '', tent: '', train: '', mountain: '', city: '', id: '', wallet: '', chip: '', restroom: '', brain: '', // 4.103.0: the next eight by use (Design's usage count, 2026-11-02): retry, water, food, history, compress, // bridge, text and steps. Arrows keep their arcs as lines with filled heads; a list keeps its rows as lines. retry: '', water: '', food: '', history: '', compress: '', bridge: '', text: '', steps: '', // 4.104.0: the next eight by use with a shape to fill (Design's usage count): download, upload, expand, shirt, // shapes, shelter, archive and keyboard. An arrow is filled whole; its tray stays a line. download: '', upload: '', expand: '', shirt: '', shapes: '', shelter: '', archive: '', keyboard: '', umbrella: '', parking: '', medical: '', drive: '', skull: '', 'hot-tub': '', group: '', gavel: '', binoculars: '', telescope: '', microscope: '', gpu: '', cpu: '', memory: '', joystick: '', wand: '', 'layers-plus': '', }); const BY = { kit: 'the OpenVibe Kit', opus: 'drawn by Opus for the glyph set (2026-10-31)' }; const ALL = { ...(kit && kit.PATHS ? kit.PATHS : {}), ...DRAWN }; const NAMES = Object.freeze(Object.keys(ALL).sort()); // ── Font Awesome's names, as the network uses them, mapped to the glyph that stands for each ── const FA = Object.freeze({ // 4.231.0: the names sites used that drew nothing once Font Awesome's stylesheet was gone (the maps app, yt). 'arrow-rotate-left': 'undo', 'chart-pie': 'chart', 'book-skull': 'book', crosshairs: 'target', 'location-crosshairs': 'target', satellite: 'image', 'globe-americas': 'globe', 'street-view': 'walk', 'magnifying-glass-location': 'search', 'apple-whole': 'food', backpack: 'briefcase', 'shield-heart': 'shield', openstreetmap: 'map', 'wand-magic-sparkles': 'wand', 'wand-magic': 'wand', 'wand-sparkles': 'wand', sparkles: 'spark', 'star-of-life': 'spark', eye: 'eye', 'eye-slash': 'eye-off', binoculars: 'binoculars', telescope: 'telescope', microscope: 'microscope', joystick: 'joystick', gpu: 'gpu', cpu: 'cpu', memory: 'memory', ram: 'memory', 'tower-broadcast': 'live', 'broadcast-tower': 'live', 'satellite-dish': 'dish', 'tower-cell': 'live', 'signal': 'wifi', wifi: 'wifi', xmark: 'close', times: 'close', 'circle-xmark': 'x-circle', 'xmark-circle': 'x-circle', video: 'video', 'video-slash': 'video', camera: 'camera', robot: 'robot', scissors: 'scissors', cut: 'scissors', copy: 'copy', paste: 'clipboard', clipboard: 'clipboard', 'clipboard-list': 'clipboard', bolt: 'zap', 'bolt-lightning': 'zap', check: 'check', 'check-circle': 'check-circle', 'circle-check': 'check-circle', comments: 'chat', comment: 'chat', 'comment-dots': 'chat', message: 'chat', play: 'play', 'circle-play': 'play', pause: 'pause', stop: 'stop', tree: 'tree', spinner: 'busy', 'circle-notch': 'busy', 'map-pin': 'pin', 'location-dot': 'pin', 'location-pin': 'pin', map: 'map', route: 'route', globe: 'globe', 'earth-americas': 'globe', 'earth-europe': 'globe', language: 'language', code: 'code', terminal: 'terminal', 'code-branch': 'branch', 'code-fork': 'branch', coins: 'coin', coin: 'coin', 'hand-holding-dollar': 'coin', 'dollar-sign': 'dollar', wallet: 'wallet', clock: 'clock', 'clock-rotate-left': 'history', 'rotate-left': 'retry', rotate: 'retry', 'rotate-right': 'retry', 'arrows-rotate': 'retry', 'arrow-rotate-right': 'retry', 'shield-halved': 'shield', shield: 'shield', 'user-shield': 'shield', plus: 'plus', minus: 'minus', lock: 'lock', unlock: 'lock', key: 'key', 'arrow-right': 'arrow-right', 'arrow-left': 'arrow-left', 'arrow-up': 'arrow-up', 'arrow-down': 'arrow-down', 'chevron-right': 'chevron', 'chevron-left': 'back', 'chevron-down': 'down', 'chevron-up': 'up', 'angle-right': 'chevron', 'angle-down': 'down', star: 'star', 'volume-high': 'volume', 'volume-low': 'volume', 'volume-xmark': 'mute', 'volume-off': 'mute', 'triangle-exclamation': 'alert', 'circle-exclamation': 'alert-circle', 'circle-info': 'info', 'circle-question': 'help', question: 'help', link: 'link', image: 'image', images: 'image', 'file-image': 'image', 'photo-film': 'film', film: 'film', user: 'user', 'user-secret': 'user', 'user-astronaut': 'user', 'user-plus': 'invite', 'user-check': 'user-check', users: 'members', 'people-group': 'members', 'user-group': 'members', server: 'server', database: 'database', 'magnifying-glass': 'search', search: 'search', campground: 'tent', utensils: 'food', train: 'train', heart: 'heart', 'hand-holding-heart': 'care', water: 'water', 'person-swimming': 'water', house: 'home', 'house-chimney': 'home', download: 'download', upload: 'upload', 'cloud-arrow-up': 'upload', circle: 'circle', sliders: 'sliders', 'sliders-h': 'sliders', leaf: 'leaf', gamepad: 'game', microphone: 'mic', 'microphone-slash': 'mic-off', 'arrow-up-right-from-square': 'open', 'up-right-from-square': 'open', 'external-link': 'open', palette: 'palette', bell: 'bell', 'gauge-high': 'gauge', gauge: 'gauge', 'floppy-disk': 'save', trash: 'trash', 'trash-can': 'trash', 'chart-line': 'chart', plug: 'plug', compress: 'compress', expand: 'expand', 'up-right-and-down-left-from-center': 'expand', pen: 'pencil', 'pen-nib': 'pencil', pencil: 'pencil', 'pen-to-square': 'pencil', city: 'city', ban: 'ban', 'screwdriver-wrench': 'wrench', wrench: 'wrench', music: 'music', gear: 'gear', gears: 'gear', 'paper-plane': 'plane', fire: 'fire', 'circle-nodes': 'nodes', 'network-wired': 'nodes', 'diagram-project': 'nodes', sitemap: 'nodes', bridge: 'bridge', envelope: 'mail', sun: 'sun', moon: 'moon', 'list-check': 'steps', list: 'list', 'list-ul': 'list', bars: 'menu', display: 'computer', desktop: 'computer', laptop: 'computer', 'wave-square': 'wave', newspaper: 'news', 'file-lines': 'file', file: 'file', 'file-pdf': 'file', 'file-audio': 'file', folder: 'folder', book: 'book', 'book-open': 'book-open', crown: 'crown', microchip: 'chip', 'id-card': 'id', brain: 'brain', cloud: 'cloud', 'cloud-sun': 'cloud', 'cloud-rain': 'cloud', 'cloud-showers-heavy': 'cloud', snowflake: 'snow', mountain: 'mountain', 'mountain-sun': 'mountain', 'layer-group': 'layers', hashtag: 'hash', font: 'text', 'text-height': 'text', 'right-from-bracket': 'leave', 'right-to-bracket': 'enter', 'arrow-right-from-bracket': 'leave', 'arrow-right-to-bracket': 'enter', gift: 'gift', lightbulb: 'idea', 'cart-shopping': 'cart', cart: 'cart', bullseye: 'target', trophy: 'trophy', tag: 'tag', tags: 'tag', shirt: 'shirt', reply: 'reply', 'face-smile': 'smile', 'box-archive': 'archive', ticket: 'ticket', thumbtack: 'tack', store: 'store', keyboard: 'keyboard', gavel: 'gavel', droplet: 'drop', 'calendar-check': 'calendar', 'cloud-arrow-down': 'download', 'magnifying-glass-chart': 'chart', 'magnifying-glass-dollar': 'search', 'plug-circle-plus': 'plug', 'power-off': 'stop', receipt: 'ticket', 'shoe-prints': 'walk', broadcast: 'live', clip: 'scissors', flag: 'flag', calendar: 'calendar', 'calendar-days': 'calendar', phone: 'phone', 'mobile-screen': 'phone', 'hand': 'hand', 'hand-pointer': 'hand', grid: 'grid', 'table-cells': 'grid', 'chart-simple': 'chart', 'chart-bar': 'chart', 'filter': 'filter', 'ellipsis': 'more', 'ellipsis-vertical': 'more', 'share-nodes': 'nodes', // 4.63.0 restroom: 'restroom', 'person-shelter': 'shelter', 'hot-tub-person': 'hot-tub', 'hot-tub': 'hot-tub', umbrella: 'umbrella', 'umbrella-beach': 'umbrella', 'square-parking': 'parking', parking: 'parking', 'skull-crossbones': 'skull', skull: 'skull', 'object-group': 'group', 'kit-medical': 'medical', 'briefcase-medical': 'medical', 'suitcase-medical': 'medical', 'info-circle': 'info', icons: 'shapes', shapes: 'shapes', headphones: 'headphones', 'headphones-simple': 'headphones', headset: 'headphones', 'hard-drive': 'drive', hdd: 'drive', 'check-double': 'check-double', tv: 'tv', television: 'tv', toolbox: 'toolbox', table: 'table', 'table-list': 'table', 'scale-balanced': 'scale', 'balance-scale': 'scale', road: 'road', 'people-arrows': 'members', 'money-bill': 'money', 'money-bill-1': 'money', 'money-bill-wave': 'money', 'money-bill-transfer': 'money', 'money-check': 'money', 'heart-pulse': 'heart-pulse', heartbeat: 'heart-pulse', heading: 'heading', 'hand-fist': 'fist', 'fist-raised': 'fist', forward: 'fast-forward', 'forward-fast': 'fast-forward', backward: 'rewind', 'backward-fast': 'rewind', 'file-code': 'file-code', dice: 'dice', 'dice-five': 'dice', 'dice-six': 'dice', 'circle-half-stroke': 'contrast', adjust: 'contrast', briefcase: 'briefcase', suitcase: 'briefcase', timeline: 'timeline', seedling: 'seedling', rocket: 'rocket', 'right-left': 'swap', 'arrow-right-arrow-left': 'swap', 'exchange-alt': 'swap', 'person-hiking': 'mountain', hiking: 'mountain', 'microphone-lines': 'mic', 'list-ol': 'list-ordered', 'life-ring': 'lifebuoy', infinity: 'infinity', inbox: 'inbox', 'folder-open': 'folder', 'faucet-drip': 'drop', faucet: 'drop', 'face-grin-stars': 'smile', 'door-open': 'door', 'door-closed': 'door', 'credit-card': 'card', 'cloud-bolt': 'storm', // 4.68.0 'arrow-trend-up': 'trend-up', 'arrow-trend-down': 'trend-down', 'angles-left': 'chevrons-left', 'angles-right': 'chevrons-right', 'arrow-down-wide-short': 'sort', 'arrow-down-short-wide': 'sort-asc', 'arrow-up-from-bracket': 'share', 'arrows-left-right': 'arrows-h', 'left-right': 'arrows-h', 'arrows-up-down-left-right': 'move', 'arrows-to-dot': 'focus', at: 'at', 'box-open': 'box', box: 'box', bug: 'bug', bullhorn: 'megaphone', burst: 'burst', 'camera-rotate': 'camera-flip', 'camera-slash': 'camera-off', car: 'car', child: 'child', 'circle-dollar-to-slot': 'donate', 'circle-dot': 'record', 'circle-plus': 'plus-circle', 'plus-circle': 'plus-circle', 'circle-minus': 'minus-circle', 'minus-circle': 'minus-circle', clapperboard: 'clapper', 'clipboard-check': 'clipboard-check', 'closed-captioning': 'cc', 'cloud-slash': 'cloud-off', 'code-commit': 'commit', 'comment-slash': 'chat-off', compass: 'compass', 'cookie-bite': 'cookie', cookie: 'cookie', couch: 'couch', cubes: 'cubes', cube: 'box', 'ear-listen': 'ear', eraser: 'eraser', 'face-laugh': 'laugh', 'face-grin-squint': 'laugh', 'face-grin-squint-tears': 'laugh', 'face-grin': 'laugh', fish: 'fish', 'flag-checkered': 'finish', flask: 'flask', 'flask-vial': 'flask', 'folder-tree': 'folder-tree', 'forward-step': 'skip', 'step-forward': 'skip', gem: 'gem', ghost: 'ghost', 'grip-vertical': 'grip', grip: 'grip', hammer: 'hammer', handshake: 'handshake', 'handshake-angle': 'handshake', 'hat-wizard': 'wizard', 'heart-crack': 'heart-broken', 'hourglass-half': 'hourglass', 'hourglass-start': 'hourglass', 'hourglass-end': 'hourglass', hourglass: 'hourglass', lungs: 'lungs', 'link-slash': 'link-off', mask: 'mask', 'mug-hot': 'mug', 'mug-saucer': 'mug', paw: 'paw', 'person-walking': 'walk', 'phone-slash': 'phone-off', 'piggy-bank': 'piggy', plane: 'airplane', 'plane-departure': 'airplane', print: 'print', 'quote-left': 'quote', 'quote-right': 'quote', radio: 'radio', 'ranking-star': 'ranking', recycle: 'recycle', rss: 'rss', scroll: 'scroll', signature: 'signature', square: 'square', sword: 'sword', 'table-columns': 'columns', 'thumbs-up': 'thumbs-up', undo: 'undo', 'rotate-back': 'undo', 'user-circle': 'user-circle', 'circle-user': 'user-circle', 'user-lock': 'user-lock', 'user-minus': 'user-minus', 'user-pen': 'user-pen', 'user-edit': 'user-pen', 'user-tag': 'user-tag', 'user-slash': 'user-off', 'weight-hanging': 'weight', wind: 'wind', 'window-maximize': 'window', 'window-restore': 'window-restore', 'align-left': 'align-left', slash: 'slash', 'address-card': 'id', 'basket-shopping': 'cart', 'cart-plus': 'cart', 'calendar-day': 'calendar', 'chart-area': 'chart', 'chart-column': 'chart', 'camera-retro': 'camera', 'camera-cctv': 'camera', 'caret-down': 'down', clone: 'copy', 'cloud-moon': 'cloud', smog: 'cloud', 'file-pen': 'pencil', 'gauge-simple-high': 'gauge', 'gauge-simple-low': 'gauge', 'gauge-simple': 'gauge', 'hand-point-right': 'hand', 'house-signal': 'home', icicles: 'snow', 'map-location-dot': 'map', 'map-marker-alt': 'pin', 'mobile-screen-button': 'phone', 'plug-circle-bolt': 'plug', 'plug-circle-check': 'plug', 'puzzle-piece': 'puzzle', puzzle: 'puzzle', 'puzzle-piece-simple': 'puzzle', 'plug-circle-xmark': 'plug', save: 'save', th: 'grid', 'down-left-and-up-right-to-center': 'compress', paintbrush: 'palette', 'paint-brush': 'palette', }); // Each glyph's words, for openvibe.design/icons and the suggest API: the Font Awesome names it stands for, plus // the synonyms a person would type for it. Every glyph has some (a name with no alias still gets its own). const KEYWORDS = { binoculars: 'look see view search find observe spy distance bird', telescope: 'look far stars space astronomy observe lens', microscope: 'science lab biology research tiny zoom', gpu: 'graphics card render video hardware compute gaming', cpu: 'processor chip computer hardware core', memory: 'ram stick computer hardware storage', joystick: 'game controller gamepad play arcade', wand: 'magic sparkle spell create wizard', 'layers-plus': 'add stack new level create', broadcast: 'live stream radio signal', clip: 'cut attach scissors', }; const META = Object.freeze(Object.fromEntries(NAMES.map((n) => { const aliases = Object.entries(FA).filter(([, g]) => g === n).map(([fa]) => fa.replace(/-/g, ' ')); const words = [n.replace(/-/g, ' '), ...(KEYWORDS[n] || '').split(' ').filter(Boolean)]; return [n, { by: DRAWN[n] ? BY.opus : BY.kit, tags: [...new Set([...words, ...aliases])].slice(0, 24) }]; }))); const path = (name) => (Object.prototype.hasOwnProperty.call(ALL, name) ? ALL[name] : ''); const esc = (s) => String(s).replace(/[&<>"]/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"' }[c])); function svg(name, { size = 24, title = '', style = 'regular' } = {}) { const d = path(name); if (!d) return ''; const weights = { thin: 1, light: 1.5, regular: 2, bold: 2.5, duotone: 2 }; if (!['thin', 'light', 'regular', 'bold', 'solid', 'duotone'].includes(style)) throw new TypeError('glyphs.svg: unsupported style'); // A part of a solid drawing that must stay a line (class "ln") carries its own stroke here: this svg stands // alone, with no stylesheet to give it one (ov-glyphs.js does it in CSS, the sprite inline, the same way). // Without it the line was filled as a shape, or not drawn at all. const solidPath = solid(name).replace(/class="ln"/g, 'class="ln" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"'); const drawing = style === 'solid' && solidPath ? solidPath : d; const extra = style === 'solid' && solidPath ? ' stroke="none"' : ` stroke-width="${weights[style]}"`; const layered = style === 'duotone' && solidPath ? `${solidPath}${d}` : drawing; const label = title ? ` role="img" aria-label="${esc(title)}">${esc(title)}` : ' aria-hidden="true">'; return ``; } const fromFa = (fa) => { const n = String(fa || '').replace(/^fa-/, ''); return Object.prototype.hasOwnProperty.call(FA, n) && path(FA[n]) ? FA[n] : null; }; const solid = (name) => (Object.prototype.hasOwnProperty.call(SOLID, name) ? SOLID[name] : ''); /** The inside of the ov-glyphs.js draws for a glyph: the line drawing, and its solid one when it has one. */ const inner = (name) => { const d = path(name); const so = solid(name); return d ? d + (so ? `${so}` : '') : ''; }; // ── OpenVibe's own markup (4.231.0): , drawn in the page by ov-glyphs.js ── function markup(name, { title = '', cls = '' } = {}) { if (name !== 'busy' && !path(name)) return ''; return ``; } // Font Awesome's classes that say how, in OpenVibe's: '' drops one (the glyphs' default does it), null means a person // has to decide (an animation, a stack, a list: scripts/fa-to-ov.js reports it and leaves the element alone). const FA_HOW = Object.freeze({ 'fa-solid': 'ovg-fill', fas: 'ovg-fill', 'fa-regular': '', far: '', 'fa-classic': '', 'fa-thin': 'ovg-thin', 'fa-light': 'ovg-light', 'fa-fw': 'ovg-fw', 'fa-2xs': 'ovg-xs', 'fa-xs': 'ovg-xs', 'fa-sm': 'ovg-sm', 'fa-1x': '', 'fa-lg': 'ovg-lg', 'fa-xl': 'ovg-xl', 'fa-2xl': 'ovg-2x', 'fa-2x': 'ovg-2x', 'fa-3x': 'ovg-3x', 'fa-rotate-90': 'ovg-rotate-90', 'fa-rotate-180': 'ovg-rotate-180', 'fa-rotate-270': 'ovg-rotate-270', 'fa-flip-horizontal': 'ovg-flip-h', 'fa-flip-vertical': 'ovg-flip-v', fa: '', }); const SPINNERS = new Set(['spinner', 'circle-notch', 'rotate', 'arrows-rotate', 'sync', 'sync-alt', 'rotate-right', 'arrow-rotate-right', 'gear', 'cog', 'circle-dot']); /** * A class list in OpenVibe's terms: { icon, brand, cls, manual, unknown }. ICON is the glyph its Font Awesome name * maps to (a spinning spinner is busy), BRAND a logo's Font Awesome name (the caller maps it with brands.fromFa), * CLS the classes to keep (the page's own, and ovg-* for Font Awesome's sizes, widths and turns), MANUAL the * classes a person has to decide, UNKNOWN a name the glyphs do not have. Classes without fa- give icon null. */ function fromFaClasses(list) { const out = { icon: null, brand: null, cls: [], manual: [], unknown: null }; const words = String(list || '').split(/\s+/).filter(Boolean); const brand = words.includes('fa-brands') || words.includes('fab'); const spin = words.some((w) => /^fa-(spin|spin-pulse|pulse)$/.test(w)); for (const w of words) { if (w === 'fa-brands' || w === 'fab') continue; if (Object.prototype.hasOwnProperty.call(FA_HOW, w)) { if (FA_HOW[w]) out.cls.push(FA_HOW[w]); continue; } if (/^fa-(spin|spin-pulse|pulse)$/.test(w)) continue; if (/^fa-(beat|beat-fade|bounce|fade|flip|shake|stack|stack-1x|stack-2x|layers|layers-text|layers-counter|ul|li|border|pull-left|pull-right|inverse|rotate-by|flip-both|sharp|duotone|sharp-duotone|[4-9]x|10x|swap-opacity|width-auto)$/.test(w)) { out.manual.push(w); continue; } if (/^fa-[a-z0-9-]+$/.test(w)) { const n = w.slice(3); if (brand) { out.brand = out.brand || n; continue; } if (spin && SPINNERS.has(n)) { out.icon = 'busy'; continue; } const g = fromFa(n); if (g && !out.icon) out.icon = g; else if (!g) out.unknown = out.unknown || w; continue; } out.cls.push(w); } if (spin && out.icon && out.icon !== 'busy') out.manual.push('fa-spin'); out.cls = [...new Set(out.cls)]; return out; } return { NAMES, META, FA, SOLID, DRAWN: Object.freeze(Object.keys(DRAWN)), path, solid, inner, svg, fromFa, markup, fromFaClasses, FA_HOW }; });