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.
- ✅ 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
npm install svelte-split-flap
<script>
import { SplitFlap } from 'svelte-split-flap';
import 'svelte-split-flap/styles.css';
let currentText = 'HELLO WORLD';
</script>
<SplitFlap text={currentText} />
<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>
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' |
'din' |
Font family |
fontWeight |
'extralight' | 'light' | 'medium' | 'semibold' | 'bold' |
'medium' |
Font weight |
soundEnabled |
boolean |
true |
Enable sound effects |
soundUrl |
string |
'default' |
Custom sound file URL |
styles |
StyleOverrides |
{} |
Custom CSS styles for components |
'xsmall'
- 16px'small'
- 24px'medium'
- 48px (default)'large'
- 72px'xlarge'
- 96px'2xlarge'
- 120px'3xlarge'
- 144pxnumber
- Custom pixel size (e.g.,64
)
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.) |
text |
Text content spans | Text styling within flaps |
hinge |
Hinge line between flaps | Center divider line styles |
<SplitFlap
text="FLIGHT AB1234"
color="#FFD700"
fontFamily="din"
fontWeight="semibold"
size="large"
length={16}
padMode="end"
/>
<SplitFlap
text="000042"
color="green-400"
fontFamily="mono"
fontWeight="bold"
length={6}
padMode="start"
padChar="0"
/>
<SplitFlap
text="PLATFORM 9¾"
color="white"
fontFamily="din"
fontWeight="medium"
timing={80}
duration={250}
soundEnabled={true}
/>
<!-- 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.
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);'
}}
/>
<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"
/>
<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"
/>
<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"
/>
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 | 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 |
<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;'
}}
/>
<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;'
}}
/>
<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);'
}}
/>
<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);'
}}
/>
- Node.js 20+
- npm or pnpm
# 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 dev
# 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 publint
The project includes a test environment to verify library functionality:
# 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 dev
# 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 dev
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 usage
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}
After building, check that these files exist:
dist/styles.css
- Generated Tailwind CSSdist/components/
- Compiled Svelte componentsdist/sounds/
- Audio filessvelte-split-flap-1.0.5.tgz
- Packaged library
# Ensure everything builds correctly
npm run build
# Publish to npm (requires npm login)
npm publish
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
public
folder (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
- Chrome 60+
- Firefox 55+
- Safari 11+
- Edge 79+
MIT
- 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
- 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 to original creators
- akira02 - react-split-flap
- jayKayEss - react-split-flap-effect
- ✅ 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