Changelog

v1.0.0

We're excited to announce the release of @shadcn/designer v1.0.0 (stable). If you do not have a license, you can get one here.

v1.0.0

Here's a list of the new features and improvements:

  • mode - new mode prop to the <Designer /> component to switch between different layer modes. See the docs for more information.
  • onMount - We've added a new onMount prop to the <Designer /> component to run a callback when the designer is mounted. Useful for doing additional setup when the designer is ready.
  • defaultLayers - the layers prop has been renamed to defaultLayers for uncontrolled components.
  • layers and onLayersChange - We've added new props for controlled <Designer /> components.
  • We've also introduced a layer signature optimization to reduce the number of re-renders.
  • We've improved layer snapping to be more accurate.

See the roadmap for what's coming next.

Thank you to all the early adopters who have been using the designer and providing feedback: Mikkel, Sebastian, Piotr, Santosh, Jenny, Alex, Maria, David K., David E., and Sarah.

v0.4.0

We've released a new version of @shadcn/designer with several improvements to the image browser, a new image cropper and layer locking.

Image Browser

Image Browser

The new ActionImage now has support for plugins. You can build your own image plugin and use it in the image browser.

<ActionImage
  plugins={[
    {
      id: "cropper",
      label: "Crop",
      description:
        "Move and scale the image to crop it. The white frame represents the layer.",
      component: <ActionImageCropper />,
    },
    {
      id: "browser",
      label: "Browse",
      description:
        "Search and select an image to set as the image for the selected layer.",
      component: (
        <ActionImageBrowser
          apiUrl="/api/images"
        />
      ),
    },
  ]}
/>

See the Image Browser guide to learn how to build your own image browser plugin.

Image Cropper

We've added a new ActionImageCropper component for image cropping.

Image Cropper

The ActionImageCropper can be used on its own or as a plugin for the ActionImage component.

Locked Layers

We've also added a new locked property to layers. This allows you to lock a layer in place.

You can use the layersAction("LOCK_UNLOCK_LAYER", [layer.id]) action to lock and unlock layers.

import { useLayersAction } from "@shadcn/designer"
 
export function LockLayerButton({ layer }: { layer: DesignerLayer }) {
  const layersAction = useLayersAction()
 
  return (
   <Button onClick={() => layersAction("LOCK_UNLOCK_LAYER", [layer.id])}>
      {layer.isLocked ? <IconLock /> : <IconLockOpen />}
      <span className="sr-only">Toggle lock</span>
    </Button> 
  )
}
 

v0.3.0

We've released a new version of @shadcn/designer with several improvements to the core functionality and user experience.

History API

We've implemented a new History API that allows you to undo and redo changes in your designs. The API is available through three new hooks:

// Get access to the history state
const history = useHistory()
 
// Undo the last change
const undo = useUndo()
 
// Redo the last undone change
const redo = useRedo()

Improvements

We've made several improvements to the canvas interaction:

  • Added support for wheel and pinch zoom gestures
  • Fixed adaptive zoom behavior for better viewport handling
  • Resolved keyboard shortcut issues related to zoom controls
  • Fixed layer update flickering issues for smoother rendering

What's Next?

We are building more examples and documentation to help you, including image generation with AI. Stay tuned!

v0.2.0

We just tagged a new release of @shadcn/designer. This release brings a lot of new features and improvements.

Font Picker

We've added a Google Font picker to the designer.

The picker is decoupled from the designer so that you're free to implement your own picker or use the one we provide.

Font Picker

Image Browser

We've also added an image browser using the Unsplash API. Use this as a reference to build your own image picker.

Image Browser

Snapping

We've added snapping to the canvas. This means that layers will snap to the nearest grid point when you move them. This makes it easier to align layers to the canvas. We've also added distance guidelines for horizontal and vertical snapping.

Snapping

Template Updates

  • We've updated the template to use the new font picker and image browser.
  • We added examples for fetching fonts and images from the Unsplash API.
  • The template now ships with a Playground to test image layers. This is the same playground that you see in the demo.
  • We also added an Inspector to test the static frame rendering. This is useful for turning posts into images.

That's it for now. Grab the latest template to see the new features. See the Roadmap for what's coming next.

v0.1.0

We are excited to bring you this update as we are getting close to General Availability (GA).

This update brings a lot of changes to the core system. We've added a new set of hooks and components to make it easier to extend and build custom designers.

There are still a few things we're wrapping up, but we're excited to finally show you a demo of what we've been working on.

Designer Demo

First, let's take a look at a demo of what we've been working on. Click on Launch Demo in the header to create your own personalized playground to test the editor.

Use this playground to test the editor features, layers, controls and actions.

API

We've also built a demo to show how you can turn any design into an API. Using the API turns your designs into templates that can be used to generate designs for different contexts by passing in different layer values.

Try the API

Export to Image

When you're done customizing your layer values, click the Download button to download the design as an image.

Export to Image

This can be used to generate images for social media, banners, etc and serve them on demand over a CDN.

Performance Improvements

We've made a lot of performance improvements.

We reworked the internal system to have better rendering performance. Updates are granular and only trigger when necessary. We also fixed an issue with dropped frames.

Layer Types

You can now define your own layer types and override the default ones. A layer type can bring in its own keybindings, default values and render method.

<Designer layerTypes={[
  {
    type: "custom",
    name: "Custom",
    icon: IconCustom,
    defaultValues: {
      // ...
    },
    keybinding: {
      // ...
    },
    render: (layer) => (
      // ...
    ),
  }
]} />

Hooks

Every state and action are now available as hooks. We provide all the necessary hooks to read and update the state of the designer.

// Get the layers.
const layers = useLayers()
 
// Set the zoom level
const designerAction = useDesignerAction()
designerAction("ZOOM_IN")
 
// Get the selected layers
const selectedLayers = useSelectedLayers()
 
// Change the name of a layers
const setLayersProperty = useSetLayersProperty()
setLayersProperty([ID_OF_LAYERS], "name", "New Name")

See the reference for more information on available hooks.

Frame Size

We've made the frame size customizable. You can now pass a frameSize prop to the <Designer /> component to set the size of the frame. Useful for building social media images, banners, etc of different sizes.

<Designer frameSize={{ width: 1024, height: 1024 }} />

To programmatically change the frame size, you can use the setFrameSize hook.

const setFrameSize = useSetFrameSize()
setFrameSize({ width: 1024, height: 1920 })

Keyboard Shortcuts

We've added a new keybindings prop to the <Designer /> component to handle keyboard shortcuts. You can pass a keybindings object to the component to provide your own keybindings or override the default ones.

<Designer keybindings={{
  DUPLICATE_LAYER: {
    key: "meta+d",
    label: "Ctrl D",
    labelMac: "⌘ D",
    description: "Duplicate selected layers",
    group: "Layer",
  },
}} />

See the reference for more information on available keybindings.

Debug Mode

We've also added a new debug prop to the <Designer /> component to enable debug mode during development.