sexy-af
v0.1.1
Published
A realistic makeup drawing toolkit with kajal, contour, lipstick, balm, highlighter, and mascara for React and the web.
Maintainers
Readme
sexy-af
A little makeup, a blank canvas. A drawing toolkit with six photographic cosmetic tools, fixed product shades, distinct finishes, and an eraser.
Early preview, v0.1.1. A self-contained React component and vanilla JavaScript studio. The package includes its styles and product artwork.
Personal, noncommercial use only. Commercial use and modified versions require separate written permission. Normal integration using the documented API and routine build steps is allowed for personal, noncommercial projects. See LICENSE for the full proprietary terms.
Run the playground
npm install
npm run devOpen http://localhost:4317. The main demo saves its drawing in your browser. React integration demo: http://localhost:4317/react-demo.html.
Install
To draw over other websites, use the local browser extension. The npm package below embeds a studio in your own app.
npm install sexy-afFor React, install React 18 or 19 in your application. Vanilla users import sexy-af/vanilla and do not need React.
To test a local build before publishing:
npm pack --pack-destination artifacts
npm install /absolute/path/to/sexy-af-0.1.1.tgzReact
'use client';
import { Makeup } from 'sexy-af';
export default function Playground() {
return <Makeup initialTool="lipstick" />;
}React 18 and 19 are supported by the peer range. Styles are bundled and isolated in a Shadow DOM, with no global CSS or font requests. No stylesheet import is needed. React is an optional peer dependency so vanilla consumers do not have to install it. The component mounts only in the browser and cleans up on unmount, including React Strict Mode.
import { useRef } from 'react';
import { Makeup, type MakeupHandle } from 'sexy-af';
function Editor() {
const makeup = useRef<MakeupHandle>(null);
return <>
<button onClick={() => makeup.current?.undo()}>Undo</button>
<Makeup ref={makeup} storageKey="my-makeup-draft"
onChange={strokes => console.log(strokes)} />
</>;
}Plain JavaScript
import { createMakeupStudio } from 'sexy-af/vanilla';
const studio = createMakeupStudio(document.querySelector('#studio'), {
initialTool: 'mascara',
});
// Later, when removing the component:
studio.destroy();Options and API
| Option | Default | Purpose |
| --- | --- | --- |
| initialTool | kajal | kajal, contour, lipstick, balm, highlighter, mascara, or sponge (eraser) |
| initialStrokes | [] | Restore a drawing; takes priority over a saved draft |
| initialBackground | #ffffff | Initial canvas color |
| storageKey | omitted | Opt in to browser draft storage; use distinct keys for separate studios |
| showBranding | false | Use the spacious standalone layout (legacy option name) |
| onChange | omitted | Receives a detached stroke snapshot after changes and initialization |
| className, style | omitted | React host element styling |
Initial options are read when the component mounts. Use a new React key to reset them. onChange can update without remounting. For an embedded studio, set --makeup-canvas-height on the host to control the drawing area height.
Both the React ref and vanilla instance expose getStrokes(), setStrokes(strokes), selectTool(id), undo(), redo(), clear(), and toPng(): Promise<Blob | null>. The vanilla instance additionally exposes destroy(). setStrokes() validates and clones input, normalizes color/size/opacity to the fixed product presets, and resets undo history. PNG export includes the selected paper color and erasure at 1440 pixels wide, with height matching the current canvas aspect ratio. Drawing coordinates use the same board dimensions. Resizing preserves proportions and anchors existing strokes to the top left; reducing canvas height can crop lower marks until it is expanded again.
Interaction
- Mouse, touch, and pen drawing; pen pressure affects kajal and mascara pigment coverage.
- Six photographic cosmetic tools with fixed shades, tip sizes, and coverage. Layer strokes to build color.
- Kajal sparkle, creamy contour, rosewood lipstick sheen, cool-mauve glossy balm, dewy highlighter, and separated mascara bristles.
- Undo, redo, reversible clear, partial erasing, and programmatic PNG export with
toPng(). 1–6select products,Eselects the eraser, Cmd/Ctrl+Z undo, Shift+Cmd/Ctrl+Z redo. Shortcuts apply while focus is inside the studio.- Optional local draft persistence, responsive layout, reduced-motion support, labeled controls, and keyboard focus states. Freehand drawing itself requires a pointer.
Build and verify
npm run check
npm run build
npm test
npm run typecheck
npm pack --pack-destination artifactsThe tarball contains ESM, CommonJS, and TypeScript definitions. The development playground, tests, and React demo bundle are excluded. The vanilla entry has no runtime dependencies.
Toolbar interaction was inspired by Drawesome. Product artwork was generated from official product references with matched studio lighting. Colors and material effects are visual approximations, not exact physical simulations. See ASSETS.md for sources and generation prompts.
Products
| Tool ID | Product | Shade |
| --- | --- | --- |
| kajal | Victoria Beckham Beauty Satin Kajal Liner | Night Flash |
| contour | Victoria Beckham Beauty Contour Stylus | Sandstone |
| lipstick | Hermès Silky Lipstick Shine | 48 Rose Boisé |
| balm | EADEM Le Chouchou | Fig Sauce |
| highlighter | Chanel Baume Essentiel | Dragée |
| mascara | Tom Ford Extreme Mascara | Raven |
The read-only PRODUCTS array is exported from both package entry points. Generated imagery and source links describe an independent prototype; brand affiliation is not implied.
Publishing updates
Continue editing this project and check changes in the local playground. Record the changes in CHANGELOG.md, then publish a new version:
# Small fixes: 0.1.1 → 0.1.2
npm version patch --no-git-tag-version
npm publishnpm publish runs syntax checks, the build, drawing tests, and TypeScript checks through prepack. The public package contains only the built library, declarations, and documentation. The playground and research files are excluded.
Use npm version minor --no-git-tag-version for a new feature release. Published versions cannot be overwritten; consumers choose when to upgrade:
npm install sexy-af@latestPublishing is a deliberate release step; editing the local project does not automatically change installed copies.
