🎨 An interactive emoji-based sticker canvas.
- React
- React Router DOM
- Vite
- Tailwind
- Framer Motion
- Supabase
- OpenMoji - Emoji/sticker assets
- Phosphor Icons - Icon set
- Radix UI - Custom select component
- React-Share - Social media sharing
- HTML-to-Image - Canvas export functionality
- Focus Lock - Lock focus to modals
- Choose from 4,000+ illustrations across 10 unique themes
- Add, remove, and freely arrange stickers on the canvas
- Customize background colors and patterns
- Animate stickers with floating, rotating, and scaling effects (however, for performance reasons, animations are disabled if there are more than 40 stickers in the canvas)
- Save your creations to browser storage for future editing (and a shareable link for collaborative edits)
- Download your canvas as a high-quality PNG image
- Share your creations directly to social media with a unique link (e.g. https://moji.aniqa.dev/95a22e4c-9006-480c-bb15-7443b0d1a508)
- Fully responsive design that works seamlessly across devices
- PWA support
- Dynamic designer credits that automatically update based on stickers in use
- Accessibility features including keyboard controls and ARIA labels for screen reader compatibility
- Utilizes custom hooks to aid in state management across the application (
useAnimation
,useKey
,useLocalStorage
,useMetadata
,useModal
) - Implements reusable components (modals, buttons, sliders, notification and info button)
- Leverages React Router DOM to handle custom canvas URLs for sharing
- Manages complex user interactions through event handling and state tracking
- Conditional rendering of certain toolbar options (e.g. animations are disabled after 40 stickers are added or download button is disabled until stickers are added to the canvas)
- Utilizes
useEffect
to fetch metadata (which is handled within the customuseMetadata
hook) - Integrates with Supabase for cloud storage and retrieval of canvas data
- Provides additional accessibility access for users using keyboard to navigate
- Uses Framer Motion for dragging and animations
- PWA functionality with service worker configured to cache all (4000+) stickers, allowing for offline usage
- Uses light prop drilling to pass data between different components
- Uses Context API for global state management between two contexts:
CanvasContext
: manages core canvas-related functionalitiesUIContext
: handles UI-related components (modals and notifications)
-
App.jsx
: Main app logic- dynamically loads canvas data from database if canvasId is present, otherwise, localStorage and fallback values are used
- handles user interactions
- handle state management
- displays relevant toast notifications
- integrates components based on the states and user interactions
-
AppRouter.jsx
: Defines default route and dynamic canvas routes (based on canvasId param) -
/assets
- SVG files, specifically for the heading and custom Radix UI select components
-
/components
heading/
: Logo, hint text, and tooltip componentsmodals/
: Share modal for social media sharing and info modal for application details & creditsreusable/
: Common UI components (modal, toolbar buttons, info button, range slider, and toast notification)toolbar/
: Canvas control components including:- Action buttons
- Animation controls
- Background customization
- Size controls
- Sticker management
- Theme selector
sticker/
: Handles sticker components; manages positions, animations, and metadatacanvas/
: Manages background color, dot color, and provides reference for dragging mechanism provided by Framer Motion
-
/utils
download.js
: PNG export functionality using html-to-imagestickers.js
: Utilities for sticker management, including random sticker generation and random position/size helper functionscanvas.js
: Manages canvas interactions based on sticker mode (add/remove) and updates relevant states
-
/hooks
useAnimation.js
: Bundles all animation/transformation-related state variables and setter functions, in addition to helper functions (such as, resetting animation states)useLocalStorage.js
: Handles saving and retrieving items from localStorageuseMetadata.js
: Performs the initial fetch for the JSON file that contains the stickers metadatauseKey.js
: Handles keypress events to trigger specific actions (e.g. add or remove stickers based on sticker mode, close modal with escape button, reset canvas with backspace)
-
/contexts
CanvasContext
UIContext
-
/data
supabase.js
: Provides functions for fetching, updating and saving canvas content/metadata to the database
Built with Vite. Available scripts include:
npm start
: Start development servernpm run build
: Create production buildnpm run preview
: Preview production buildnpm run lint
: Run ESLintnpm run format
: Format code with Prettiernpm run serve:mobile
: Preview development server on mobile