PurgeTSS is a toolkit for building mobile apps with the Titanium framework. It provides utility classes, icon font support, an Animation module, a grid system, and the shades command for generating custom colors.
- 23,300+ utility classes for styling Titanium views
- Parses XML files to generate a clean
app.tsswith only the classes your project uses - Customizable defaults via
config.cjs, with JIT classes for arbitrary values - Icon font support: Font Awesome, Material Icons, Material Symbols, Framework7-Icons
build-fontscommand generatesfonts.tsswith class definitions and fontFamily selectorsshadescommand generates color shades from any hex color- Animation module for 2D matrix animations on views or arrays of views
- Grid system for aligning and distributing elements within views
Install with purgetss module (or purgetss m). This places purgetss.ui.js in your project's lib folder.
<Animation id="myAnimation" module="purgetss.ui" class="opacity-0 duration-300 ease-in" />You can use any position, size, color, opacity, or transformation class from utilities.tss.
| Method | Description |
|---|---|
play(views, cb) / toggle(views, cb) |
Animate views from current state to the animation state. Toggles open/close on each call. |
open(views, cb) |
Explicitly run the open state animation. |
close(views, cb) |
Explicitly run the close state animation. |
apply(views, cb) |
Apply properties instantly without animation. |
draggable(views) |
Make a view or array of views draggable inside their parent. |
undraggable(views) |
Remove draggable behavior and clean up all listeners. |
detectCollisions(views, dragCB, dropCB) |
Enable collision detection on draggable views with hover and drop callbacks. |
swap(view1, view2) |
Animate two views exchanging positions. Auto-normalizes position from margins/right/center via view.rect. Inherits duration, delay, curve; fallback: 200ms. |
sequence(views, cb) |
Animate views one after another. Callback fires after the last view. |
shake(view, intensity) |
Bidirectional shake animation for error feedback. Inherits duration, delay; fallback: 400ms. Default intensity: 10px. |
pulse(view, count) |
Scale-up-and-back pulse animation. Scale from Animation object (default 1.2x). Count: number of pulses (default 1). |
snapTo(view, targets) |
Snap a view to the nearest target by center distance. Auto-normalizes target position. Inherits duration, delay, curve; fallback: 200ms. |
reorder(views, newOrder) |
Animate views to new positions based on index mapping. Auto-normalizes positions. Inherits duration, delay, curve; fallback: 200ms. |
transition(views, layouts) |
Multi-view layout transitions using Matrix2D.translate().rotate().scale(). Layout properties: translation, rotate, scale, zIndex. Compatible with TiDesigner presets. Views without a layout entry fade out; returning views fade in. |
All callbacks (play, open, close, apply) receive an enriched event object:
{
type: String, // event type ('complete' or 'applied')
bubbles: Boolean,
cancelBubble: Boolean,
action: String, // 'play' or 'apply'
state: String, // 'open' or 'close'
id: String, // Animation object ID
targetId: String, // ID of the animated view
index: Number, // position in array (0-based)
total: Number, // total views in array
getTarget: Function // returns the animated view object
}When animating an array of views, the callback is called once per view with the corresponding index and total values.
$.myAnimation.play([$.card1, $.card2, $.card3], (e) => {
console.log(`Animated ${e.index + 1} of ${e.total}`) // "Animated 1 of 3", etc.
if (e.index === e.total - 1) {
console.log('All done!')
}
})Use open, close, and complete modifiers inside animationProperties to define different states:
<Animation id="fadeToggle" module="purgetss.ui" class="duration-300"
animationProperties="{
open: { opacity: 1 },
close: { opacity: 0 }
}"
/>$.myAnimation.draggable($.myView)
// or with constraints:
$.myAnimation.draggable([$.card1, $.card2])Use bounds to restrict movement, and drag/drop modifiers for drag-state animations. Use vertical-constraint or horizontal-constraint classes to limit the drag axis.
After calling draggable(), you can enable collision detection to know when a dragged view overlaps another:
$.myAnimation.draggable(views)
$.myAnimation.detectCollisions(views, onHover, onDrop)dragCB(source, target) is called during drag:
targetis the view under the drag center, ornullwhen leaving all targets- Use this to show visual feedback (highlights, borders, scaling)
dropCB(source, target) is called on drop:
targetis the view where the source was released- If no target is found, the source automatically snaps back to its original position with a 200ms animation
Animate two views exchanging positions:
$.myAnimation.swap(view1, view2)- Inherits
duration,delay, andcurvefrom the Animation object's classes - Falls back to 200ms duration, 0ms delay, and ease-in-out curve if not set
- Handles iOS transform reset automatically
- Temporarily raises z-index so views animate above siblings
- Updates internal
_originLeft/_originTopfor subsequent drag operations
Animate views one after another (unlike play(array) which runs them in parallel):
$.fadeIn.sequence([$.title, $.subtitle, $.button], () => {
console.log('All views animated')
})- Each view fully completes before the next starts
- Callback fires once after the last view
- Respects
open/closestate (set once for the entire sequence)
Quick horizontal shake for error feedback, using native autoreverse + repeat for smooth performance:
$.myAnimation.shake($.loginButton) // default intensity: 10px
$.myAnimation.shake($.input, 6) // subtle: 6px
$.myAnimation.shake($.errorLabel, 20) // strong: 20pxAfter dragging, snap a view to the closest target by center-to-center distance:
const matched = $.myAnimation.snapTo(draggedView, slotViews)
if (matched) {
console.log('Snapped to:', matched.id)
}Animate an array of views to new positions based on index mapping:
// Reverse order: view[0] goes to position of view[2], view[2] to position of view[0]
$.myAnimation.reorder(cardViews, [2, 1, 0])- All views animate simultaneously
- Captures positions before animating to avoid conflicts
Remove draggable behavior and clean up all event listeners:
$.myAnimation.undraggable(cardViews)The swap, reorder, snapTo, and shake methods inherit animation properties from the <Animation> object's classes. This means you can configure behavior declaratively in XML:
<Animation id="myAnim" module="purgetss.ui" class="curve-animation-ease-out delay-100 duration-150" />| Property | play/toggle/open/close/sequence |
swap/reorder/snapTo |
shake |
|---|---|---|---|
duration |
✅ | ✅ | ✅ (÷6) |
delay |
✅ | ✅ | ✅ |
curve |
✅ | ✅ | fixed EASE_IN_OUT |
autoreverse |
✅ | — | fixed true |
repeat |
✅ | — | fixed 3 |
Fallback defaults when not set: swap/reorder/snapTo → 200ms; shake → 400ms. All animation timing is controlled declaratively via the <Animation> object's classes.
- Removes touch and orientation listeners
- Removes views from collision detection registry
- Cleans up internal tracking properties
| Class pattern | Description |
|---|---|
duration-{n} |
Animation duration in ms |
delay-{n} |
Delay before animation starts |
rotate-{n} |
2D rotation in degrees |
scale-{n} |
Scale factor |
repeat-{n} |
Number of repeats |
ease-in, ease-out, ease-linear, ease-in-out |
Timing curve |
zoom-in-{n}, zoom-out-{n} |
Zoom animations |
drag-apply, drag-animate |
Drag interaction style |
vertical-constraint, horizontal-constraint |
Constrain drag axis |
| Function | Description |
|---|---|
deviceInfo() |
Logs detailed platform and display information to the console. Works in both Alloy and Classic projects. |
saveComponent({ source, directory }) |
Saves a view snapshot as PNG to the photo gallery. |
See the full documentation at purgetss.com/docs/animation-module/introduction.
Switch between Light, Dark, and System modes with automatic persistence:
const { Appearance } = require('purgetss.ui')
// Call once at app startup (e.g., in index.js before opening the first window)
Appearance.init()| Method | Description |
|---|---|
init() |
Restore the saved mode from Ti.App.Properties |
get() |
Returns the current mode string |
set(mode) |
Apply and persist a mode: 'system', 'light', or 'dark' |
toggle() |
Switch between 'light' and 'dark' |
Use it from any controller to respond to user actions:
const { Appearance } = require('purgetss.ui')
function selectDark() { Appearance.set('dark') }
function selectLight() { Appearance.set('light') }
function selectSystem() { Appearance.set('system') }Requires semantic.colors.json in app/assets/ for views to respond to mode changes. See the Titanium docs on semantic colors for the file format.
PurgeTSS generates font-sans, font-serif, and font-mono classes automatically with platform-appropriate values:
| Class | iOS | Android |
|---|---|---|
font-sans |
Helvetica Neue |
sans-serif |
font-serif |
Georgia |
serif |
font-mono |
monospace |
monospace |
Override or add families in config.cjs:
// theme.extend.fontFamily → adds to defaults
extend: {
fontFamily: {
display: 'AlfaSlabOne-Regular',
body: 'BarlowSemiCondensed-Regular'
}
}
// theme.fontFamily → replaces defaults entirely
theme: {
fontFamily: {
sans: 'System',
mono: 'Courier',
display: 'AlfaSlabOne-Regular'
}
}PurgeTSS sets defaults for three components out of the box:
| Component | Default |
|---|---|
Window |
backgroundColor: '#FFFFFF' |
View |
width: Ti.UI.SIZE, height: Ti.UI.SIZE |
ImageView |
hires: true (iOS only) |
Override or extend them in config.cjs with theme.extend:
module.exports = {
theme: {
extend: {
Window: {
apply: 'exit-on-close-false bg-surface'
}
}
}
}If an applied class sets a property that already exists in the defaults (e.g., bg-surface vs backgroundColor: '#FFFFFF'), the applied value wins. Array-type properties like extendEdges and orientationModes use bracket notation ([ ]) in the generated output.
Both are equivalent:
// Shorthand
Window: { apply: 'exit-on-close-false' }
// Explicit
Window: { default: { apply: 'exit-on-close-false' } }Use the explicit form when you need platform-specific variants:
Button: {
default: { apply: 'text-xl' },
ios: { apply: 'font-bold' },
android: { apply: 'text-2xl font-semibold', color: 'red' }
}Visit the official documentation site at purgetss.com to learn more.
- Titanium SDK (Compatible with all versions; 13.1.1.GA recommended for full property support)
- Alloy Framework (for most commands)
- Node.js 20+ (required for the CLI tool)
- Installation
- Commands
- Customization
- The UI Module
- Recommendations
- Grid System