svelte-split-flap
v1.0.7
Published
A Svelte component library for creating realistic split-flap displays with animations and sound effects
Maintainers
Readme
Svelte Split-Flap
A modern Svelte component library for creating realistic split-flap displays with smooth animations and sound effects. Perfect for creating retro mechanical displays with authentic flip animations.
Features
- ✅ Smooth Animations: Realistic split-flap flip effects
- ✅ Customizable Styling: Support for colors, fonts, and sizes
- ✅ Sound Effects: Realistic split-flap audio with Web Audio API
- ✅ Svelte 5 Ready: Built with modern Svelte 5 runes
- ✅ Self-contained: No external dependencies required
Installation
npm install svelte-split-flapQuick Start
Basic Usage
<script>
import { SplitFlap } from 'svelte-split-flap';
import 'svelte-split-flap/styles.css';
let currentText = 'HELLO WORLD';
</script>
<SplitFlap text={currentText} />Dynamic Text Updates
<script>
import { SplitFlap } from 'svelte-split-flap';
import 'svelte-split-flap/styles.css';
let messages = ['TOKYO SK07', 'BERLIN 12', 'ATHENS 97'];
let currentIndex = 0;
function changeText() {
currentIndex = (currentIndex + 1) % messages.length;
}
</script>
<SplitFlap text={messages[currentIndex]} size="large" fontFamily="din" />
<button onclick={changeText}>Change Text</button>Component API
SplitFlap Props
| Prop | Type | Default | Description |
| -------------- | ------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | ---------------------------------- |
| text | string | '' | Text to display |
| chars | string[] | 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 '.split('') | Available character set |
| length | number \| undefined | undefined | Fixed display length with padding |
| padChar | string | ' ' | Character used for padding |
| padMode | 'auto' \| 'start' \| 'end' | 'auto' | Padding alignment |
| timing | number | 60 | Animation timing in milliseconds |
| duration | number | 300 | Flip duration in milliseconds |
| easing | string | 'ease-in-out' | CSS easing function |
| size | number \| string | 'medium' | Size variant or custom pixel size |
| color | string | 'white' | Text color (CSS or Tailwind class) |
| fontFamily | 'din' \| 'brains' \| 'mono' \| 'ibm' \| 'roboto' \| 'mont' \| 'barlow' \| 'cabin' \| 'cabinCondensed' | 'roboto' | Font family |
| fontWeight | 'extralight' \| 'light' \| 'medium' \| 'semibold' \| 'bold' | 'bold' | Font weight |
| soundEnabled | boolean | true | Enable sound effects |
| soundUrl | string | 'default' | Custom sound file URL |
| styles | StyleOverrides | {} | Custom CSS styles for components |
Size Options
'xsmall'- 16px'small'- 24px'medium'- 48px (default)'large'- 72px'xlarge'- 96px'2xlarge'- 120px'3xlarge'- 144pxnumber- Custom pixel size (e.g.,64)
Style Overrides
The styles prop accepts an object with CSS strings for different component parts:
| Style Key | Target | Description |
| ------------ | ------------------------------- | ---------------------------------------------------------------------- |
| container | Main container div | Overall display container styles |
| digit | Individual character containers | Digit/character container styles |
| flap | Individual flap elements | Flap panel styles (background, borders, etc.) - applies to both halves |
| flapTop | Top flap half only | Styles for upper flap half only |
| flapBottom | Bottom flap half only | Styles for lower flap half only |
| text | Text content spans | Text styling within flaps |
| hinge | Hinge line between flaps | Center divider line styles |
Examples
Airport-Style Display
<SplitFlap
text="FLIGHT AB1234"
color="#FFD700"
fontFamily="din"
fontWeight="semibold"
size="large"
length={16}
padMode="end"
/>Retro Counter
<SplitFlap
text="000042"
color="green-400"
fontFamily="mono"
fontWeight="bold"
length={6}
padMode="start"
padChar="0"
/>Train Station Display
<SplitFlap
text="PLATFORM 9¾"
color="white"
fontFamily="din"
fontWeight="medium"
timing={80}
duration={250}
soundEnabled={true}
/>Sound Configuration
<!-- Default bundled sound -->
<SplitFlap text="HELLO" />
<!-- External URL - uses HTML Audio Element (CORS-friendly) -->
<SplitFlap text="HELLO" soundUrl="https://www.soundjay.com/communication/typewriter-2.wav" />
<!-- Custom local file in user's public folder -->
<SplitFlap text="HELLO" soundUrl="/my-custom-sound.mp3" />
<!-- Silent mode -->
<SplitFlap text="HELLO" soundEnabled={false} />Sound Loading Strategy:
- Default: Uses bundled split-flap audio with full features (HTML Audio Element + Web Audio API for advanced features)
- External URLs: Uses HTML Audio Element only (basic playback, no panning/advanced features due to CORS)
- Fallback: Gracefully falls back to silent mode if audio fails to load
Note: External URLs have limited audio features due to browser CORS restrictions. For full feature support, use local files or the bundled sound.
Custom Styling
Two-Tone Flaps (Different Colors for Top/Bottom)
<SplitFlap
text="DEPARTURE"
styles={{
flapTop:
'background: linear-gradient(145deg, #4f46e5, #3730a3); border-bottom: 1px solid #1e1b4b;',
flapBottom:
'background: linear-gradient(145deg, #dc2626, #991b1b); border-top: 1px solid #7f1d1d;',
text: 'color: white; font-weight: bold; text-shadow: 0 1px 2px rgba(0,0,0,0.5);',
hinge: 'background: #1f2937; height: 2px; box-shadow: 0 1px 3px rgba(0,0,0,0.8);'
}}
fontFamily="din"
size="large"
/>Classic Airport Style with Split Colors
<SplitFlap
text="FLIGHT 1234"
styles={{
container: 'background: #1a1a1a; padding: 20px; border-radius: 8px;',
flapTop:
'background: linear-gradient(145deg, #2d2d2d, #1e1e1e); border-bottom: 1px solid #000;',
flapBottom:
'background: linear-gradient(145deg, #404040, #2d2d2d); border-top: 1px solid #555;',
text: 'color: #ffd700; font-weight: bold; text-shadow: 0 0 8px rgba(255,215,0,0.5);',
hinge: 'background: linear-gradient(90deg, #666, #888, #666); height: 2px;'
}}
fontFamily="din"
fontWeight="bold"
size="large"
/>Override component styles for complete customization:
<SplitFlap
text="CUSTOM"
styles={{
container:
'background: linear-gradient(45deg, #ff6b35, #f7931e); padding: 20px; border-radius: 12px;',
digit: 'border: 2px solid #fff; border-radius: 8px; margin: 4px;',
flap: 'background: linear-gradient(145deg, #2c3e50, #34495e); border: 1px solid #3498db;',
text: 'color: #ecf0f1; text-shadow: 0 1px 2px rgba(0,0,0,0.5);',
hinge: 'background: #e74c3c; height: 3px; box-shadow: 0 0 5px rgba(0,0,0,0.3);'
}}
/>Neon/Cyberpunk Style
<SplitFlap
text="CYBER 2077"
styles={{
container: 'filter: drop-shadow(0 0 10px #00ff41);',
flap: 'background: linear-gradient(145deg, #000, #111); border: 1px solid #00ff41; box-shadow: inset 0 1px 1px rgba(0,255,65,0.1);',
text: 'color: #00ff41; text-shadow: 0 0 10px #00ff41, 0 0 20px #00ff41;',
hinge: 'background: #00ff41; height: 2px; box-shadow: 0 0 5px #00ff41;'
}}
fontFamily="mono"
size="large"
/>Vintage/Retro Style
<SplitFlap
text="DEPARTURE 15:42"
styles={{
container:
'background: #8b4513; padding: 16px; border: 4px solid #654321; border-radius: 4px;',
flap: 'background: linear-gradient(145deg, #f4a460, #daa520); border: 1px solid #8b4513; box-shadow: inset 0 1px 2px rgba(255,255,255,0.2);',
text: 'color: #2f1b14; font-weight: bold; text-shadow: 0 1px 1px rgba(255,255,255,0.3);',
hinge: 'background: #654321; height: 3px;'
}}
fontFamily="din"
size="medium"
/>Minimalist Style
<SplitFlap
text="MINIMAL"
styles={{
container: 'background: #f8f9fa; padding: 12px; border-radius: 8px;',
flap: 'background: #ffffff; border: 1px solid #e9ecef; box-shadow: 0 1px 3px rgba(0,0,0,0.1);',
text: 'color: #212529; font-weight: 500;',
hinge: 'background: #dee2e6; height: 1px;'
}}
fontFamily="ibm"
size="medium"
/>Font Configuration
Using Built-in Web Fonts (Default)
The library uses web fonts by default for maximum compatibility:
<SplitFlap text="HELLO" fontFamily="brains" />
<!-- JetBrains Mono -->
<SplitFlap text="HELLO" fontFamily="ibm" />
<!-- IBM Plex Mono -->
<SplitFlap text="HELLO" fontFamily="roboto" />
<!-- Roboto Mono -->
<SplitFlap text="HELLO" fontFamily="mont" />
<!-- Montserrat -->
<SplitFlap text="HELLO" fontFamily="barlow" />
<!-- Barlow Condensed -->
<SplitFlap text="HELLO" fontFamily="cabin" />
<!-- Cabin -->
<SplitFlap text="HELLO" fontFamily="cabinCondensed" /><!-- Cabin Condensed -->Font Family Options
| Font Family | Description | Best For |
| ---------------- | -------------------------------------------------- | ----------------------------------- |
| brains | JetBrains Mono - Clean monospace with coding focus | Technical displays, code-like text |
| ibm | IBM Plex Mono - Professional IBM typeface | Corporate, professional displays |
| roboto | Roboto Mono - Google's versatile monospace | Modern, clean displays |
| mont | Montserrat - Geometric sans-serif | Headlines, modern look |
| barlow | Barlow Condensed - Tall, condensed sans-serif | Space-efficient displays, headlines |
| cabin | Cabin - Humanist sans-serif with warmth | Friendly, approachable displays |
| cabinCondensed | Cabin Condensed - Space-saving version | Compact displays, multiple lines |
| din | DIN 1451 - German industrial standard | Authentic European transport look |
| mono | System monospace fallback | Universal compatibility |
Font Showcase Examples
Modern Corporate Style (Barlow Condensed)
<SplitFlap
text="QUARTERLY RESULTS"
fontFamily="barlow"
fontWeight="semibold"
size="large"
color="#0066cc"
styles={{
container:
'background: linear-gradient(135deg, #f8f9fa, #e9ecef); padding: 20px; border-radius: 8px;',
flap: 'background: linear-gradient(145deg, #ffffff, #f8f9fa); border: 1px solid #dee2e6;',
text: 'color: #0066cc; font-weight: 600;'
}}
/>Friendly Information Display (Cabin)
<SplitFlap
text="WELCOME GUESTS"
fontFamily="cabin"
fontWeight="medium"
size="large"
styles={{
container: 'background: #2c3e50; padding: 18px; border-radius: 12px;',
flap: 'background: linear-gradient(145deg, #ecf0f1, #bdc3c7); border: 1px solid #95a5a6;',
text: 'color: #2c3e50; font-weight: 500;'
}}
/>Compact Multi-line Display (Cabin Condensed)
<SplitFlap
text="GATE 12A BOARDING"
fontFamily="cabinCondensed"
fontWeight="bold"
size="medium"
styles={{
container: 'background: #1a1a1a; padding: 16px;',
flap: 'background: linear-gradient(145deg, #333, #222); border: 1px solid #444;',
text: 'color: #ffd700; font-weight: bold; text-shadow: 0 0 8px rgba(255,215,0,0.5);'
}}
/>Old School Style with White Text (using new fonts)
<SplitFlap
text="PLATFORM 9"
fontFamily="barlow"
fontWeight="medium"
timing={80}
duration={350}
easing="ease-in-out"
size={64}
styles={{
container:
'background: #2c1810; padding: 24px; border: 4px solid #8b4513; border-radius: 8px; box-shadow: inset 0 0 20px rgba(0,0,0,0.3), 0 8px 32px rgba(0,0,0,0.4);',
flap: 'background: linear-gradient(145deg, #f5f5dc, #e6e6fa); border: 2px solid #8b7355; box-shadow: inset 0 2px 4px rgba(0,0,0,0.1), 0 2px 6px rgba(0,0,0,0.2); border-radius: 2px;',
text: 'color: #2f2f2f; font-weight: 600; text-shadow: 0 1px 2px rgba(255,255,255,0.8);',
hinge: 'background: linear-gradient(90deg, #654321, #8b4513, #654321); height: 3px; box-shadow: 0 2px 4px rgba(0,0,0,0.5);'
}}
/>Development
Prerequisites
- Node.js 20+
- npm or pnpm
Setup
# Clone the repository
git clone https://github.com/socketopp/svelte-split-flap.git
cd svelte-split-flap
# Install dependencies
npm install
# Start development server
npm run devBuilding the Library
# Build CSS and package the library
npm run build
# This runs:
# 1. npm run build:css - Generates Tailwind CSS from components
# 2. npm run prepack - Runs svelte-package and publintTesting Changes
The project includes a test environment to verify library functionality:
Method 1: Automated Testing (Recommended)
# Build library, pack it, and install in test project
npm run test-local
# This will:
# 1. Build the library (CSS + packaging)
# 2. Create svelte-split-flap-1.0.5.tgz
# 3. Install it in test-library/
# 4. Update dependencies
# Run the test project
cd test-library
npm run devMethod 2: Manual Testing
# Build and pack the library
npm run build
npm pack
# Navigate to test project
cd test-library
# Remove old version and install new tarball
npm uninstall svelte-split-flap
npm install ../svelte-split-flap-[X.Y.Z].tgz
# Start test server
npm run devTest Project Structure
The test-library/ folder contains a minimal Svelte 5 application for testing:
test-library/
├── package.json # Svelte 5 + Vite setup
├── vite.config.js # Vite configuration
├── index.html # Entry HTML
└── src/
├── main.js # Svelte 5 mount syntax
└── App.svelte # Test component usageTesting Different Scenarios
Modify test-library/src/App.svelte to test various configurations:
<script>
import { SplitFlap } from 'svelte-split-flap';
import 'svelte-split-flap/styles.css';
// Test different scenarios
let scenarios = [
{ text: 'HELLO WORLD', size: 'medium' },
{ text: 'FLIGHT AB1234', size: 'large', fontFamily: 'din' },
{ text: '000042', size: 64, fontFamily: 'mono', padMode: 'start' },
{ text: 'CUSTOM SOUND', soundUrl: 'https://www.soundjay.com/misc/beep-07a.wav' }
];
let currentScenario = $state(0);
</script>
{#each scenarios as scenario, i}
<div class="mb-4">
<h3>Scenario {i + 1}</h3>
<SplitFlap {...scenario} />
</div>
{/each}Verifying the Build
After building, check that these files exist:
dist/styles.css- Generated Tailwind CSSdist/components/- Compiled Svelte componentsdist/sounds/- Audio filessvelte-split-flap-1.0.X.tgz- Packaged library
Publishing
# Ensure everything builds correctly
npm run build
# Publish to npm (requires npm login)
npm publishTroubleshooting
Common Issues
CSS not loading: Make sure to import the CSS file:
import 'svelte-split-flap/styles.css';Component not rendering: Ensure you're using Svelte 5 syntax:
import { mount } from 'svelte';
import App from './App.svelte';
mount(App, { target: document.getElementById('app') });Audio not playing: Check browser console for audio loading errors. The component will fallback gracefully if audio files are unavailable.
Build errors: Ensure Node.js 20+ and compatible npm version.
Custom sounds not working:
- External URLs: Should work with any publicly accessible audio file. The library uses HTML Audio Element which doesn't have CORS restrictions.
- Local Files: Place audio files in your
publicfolder (e.g.,/my-sound.mp3) - File Formats: Ensure the audio format is supported by browsers (MP3, WAV, OGG recommended)
- HTTPS: Some browsers require HTTPS for audio playback in production
Browser Support
- Chrome 60+
- Firefox 55+
- Safari 11+
- Edge 79+
License
MIT
Contributing
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Test using the test-library project
- Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Development Workflow
- Make changes to components in
src/lib/ - Test changes:
npm run test-local - Verify in browser at
http://localhost:5173 - Update documentation if needed
- Submit PR with clear description of changes
Credits
Credits to original creators
- akira02 - react-split-flap
- jayKayEss - react-split-flap-effect
Roadmap
- ✅ Custom styles parameter for all components
- [ ] Grid/multi-line displays
- [ ] Animation patterns
- [ ] More font options
- [ ] Custom sound effects
- [ ] Accessibility improvements
- [ ] Implement LongFlap
- [ ] Implement Emojis/Numbers
- [ ] Improve fonts, add capability for using fonts from fontsource
- [ ] Setup UI testing
