# Technical Documentation: plasmicapp/plasmic

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/plasmicapp/plasmic)

### Overview (README.md)

<p align="center">
  <a href="https://www.plasmic.app">
    <img alt="Plasmic" role="img" src="https://static1.plasmic.app/brand/2023/logo-cropped.png" width="120">
  </a>
</p>
<h1 align="center">
  Plasmic
</h1>
<h3 align="center">
  The open-source visual builder for your codebase.
</h3>
<p align="center">
  Build beautiful apps and websites incredibly fast.
</p>
<p align="center">
  Drag and drop your own components, integrate with your codebase.
</p>
<p align="center">
  Break through the low-code ceiling.
</p>

<p>&nbsp;</p>

<p align="center">
  <a href="https://www.plasmic.app">
    <img src="https://user-images.githubusercontent.com/7129/146098801-0691ff13-e302-40fb-827e-90488a7a28b4.gif"/>
  </a>
</p>

<p align="center">
  <a href="https://docs.plasmic.app/learn/quickstart">
    <img src="https://user-images.githubusercontent.com/7129/139351025-8acd6f6d-8e32-4486-982e-a6f26a53d865.png"/>
  </a>
</p>

<p align="center">
  <a href="https://github.com/plasmicapp/plasmic"><img alt="License" src="https://img.shields.io/github/license/plasmicapp/plasmic" /></a>
  <a href="https://www.npmjs.com/package/@plasmicapp/loader-react"><img alt="Types" src="https://img.shields.io/npm/types/@plasmicapp/loader-react" /></a>
  <a href="https://github.com/prettier/prettier"><img alt="code style: prettier" src="https://img.shields.io/badge/code_style-prettier-ff69b4.svg" /></a>
  <a href="https://github.com/plasmicapp/plasmic/pulls"><img alt="PRs Welcome" src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" /></a>
</p>

## Quick links

- [Website](https://www.plasmic.app/)
- [Documentation][docs]
- [Quickstart][quickstart]
- [Plasmic Forum][forum]
- [Slack Community][slack]

[docs]: https://www.plasmic.app/learn/
[quickstart]: https://www.plasmic.app/learn/quickstart/
[forum]: https://forum.plasmic.app/
[slack]: https://www.plasmic.app/slack

## See Plasmic in action

- Vercel marketing page: https://youtu.be/itvbmgLZvcM (live app: https://vercel-workflow.vercel.app)

- Apple.com: https://apple.plasmic.run

- Shopify headless storefront: https://commerce.plasmic.run

- Twitter clone: https://youtu.be/rpdjrFuVMog (live app: https://twitter.plasmic.run)

- Service desk app: https://youtu.be/rYqSpUEJSTw (live app: https://tickets.plasmic.run)

- Interview with Lee Robinson, Plasmic as a visual CMS: https://www.youtube.com/watch?v=pcVzNR6FBAQ

## What is Plasmic?

Plasmic is a visual builder for the web.

It enables rapidly designing and building applications and websites--code optional.

Main use cases:

- Content management: let marketing drag/drop your React components to build landing pages in your Next.js website, with design guardrails

- Applications: let developers and technical users quickly build internal tools, client portals, and business software

- Website builder and design tool that doesn’t limit you to some built-in ecommerce platform, CMS, or hosting

Plasmic is powerful, with a deep feature set that scales to complex projects.
And with codebase integration, it removes the ceiling typically associated with low-code tools.

## What makes Plasmic special?

Plasmic combines some seemingly disparate genres:

- Webflow, Wordpress and other site builders
- Retool and other tool builders
- Glide and no-code app builders
- Contentful and other CMSes

Today these are different tools to specialize in, but the line between, say, a website and an application is blurry (consider an ecommerce storefront with user logins). With the right foundations, we think these can be unified—Plasmic’s UI can adapt to different levels of control for different personas/tasks.

But more importantly, unlike existing tools, Plasmic integrates with codebases. This is critical to making low-code scale past the complexity ceiling that all such tools (including Plasmic) have. You can drag and drop existing complex React components, and you can visually create new UIs/components within traditionally-coded applications, seamlessly weaving code and no-code.

Some feature highlights:

- **Full design freedom** and speedy modern design tool UX.
- **Integrate with codebases** to drag/drop existing React components, publish screens into existing applications, and extend/customize Plasmic Studio.
- Create **rich stateful interactions and behavior**.
- Connect with **arbitrary data source and backend integrations**.
- **Powerful abstractions** like components, variants, slots, composable state management, and more that promote composition and let you build and maintain at scale.
- **Customizable headless design system components** powered by [react-aria](https://react-spectrum.adobe.com/react-aria/).
- **Content creator mode**: give specific collaborators a more simplified editing experience with design guardrails.
- **Open integrations**: choose your own CMS, ecommerce platform, hosting provider, and more.
- Deep collaboration with multiplayer, branching, cross-project imports, and multi-workspace organizations.
- **Import designs from Figma**, translating its proprietary vector document format into DOM/CSS.
- **Page performance and high-quality codegen**. Supports static site generation, automatic image optimization, layout shift reduction, and more.
- **Deploy/host/export anywhere**, including Vercel, Netlify, or any hosting provider.
- **End-user auth and permissions**, including RBAC and user-scoped permissions.
- **Open-source platform** that you can always fork and control.

Learn more on [our website][website] and [our docs][docs]. Or check out [comparisons of Plasmic vs other tools][comparisons].

[website]: https://www.plasmic.app
[comparisons]: https://docs.plasmic.app/learn/comparisons/

## How do I integrate Plasmic as a CMS?

This is one popular use case of Plasmic.

**Step 1.** Install Plasmic into your codebase (exact package [depends on your framework][quickstart]).

```
npm install @plasmicapp/loader-nextjs
```

**Step 2 (optional).** Make components from your app or design system available for drag-and-drop in the visual editor:

```tsx
// Take any component from your app or design system...
export default function HeroSection({ children }) {
  return <div className="hero-section">{children}</div>;
}

// ...and make it available for drag-and-drop, along with any props you want to
// expose.
PLASMIC.registerComponent(HeroSection, {
  props: {
    children: "slot",
  },
});
```

**Step 3.** Add placeholders that render pages/components made in the visual editor anywhere in your app:

```tsx
// pages/index.tsx

import {
  PlasmicComponent,
  PlasmicRootProvider,
} from "@plasmicapp/loader-nextjs";
import { PLASMIC } from "../plasmic-init";

// Here we fetch dynamically on the client, but you can also fetch and render
// components server-side in SSG/SSR frameworks, such as via getStaticProps
// in Next.js.
export default function IndexPage() {
  return (
    <PlasmicRootProvider plasmic={PLASMIC}>
      <PlasmicComponent component="Summer22LandingPage" />
    </PlasmicRootProvider>
  );
}
```

**Step 4.** Non-developers (or developers!) can now create new pages, sections, or components that ship directly into the app/website.

**Step 5.** When you hit Publish, changes get picked up via webhooks that trigger rebuilds,
or more specific mechanisms such as incremental static revalidation or dynamic fetching from the Plasmic CDN.

## Who uses Plasmic?

Plasmic is used by companies ranging from Fortune 500s to boutique brands to solo makers.
It's used for websites ranging from headless commerce storefronts to marketing websites to logged-in app content.

Check out the [Case Studies and Community Showcase][customers].

[customers]: https://www.plasmic.app/casestudies

<p align="center">
  <a href="https://www.plasmic.app/casestudies">
    <img alt="Customer logos" width="1106"  src="https://github.com/plasmicapp/plasmic/assets/7129/2c682d45-6b72-4571-895a-e48b0c588647">
  </a>
</p>

<p align="center">
  <a href="https://www.plasmic.app/casestudies">
    <img alt="Showcase" src="https://user-images.githubusercontent.com/7129/139349675-a807ad9d-aaaf-411b-ab4b-8247a09be676.png">
  </a>
</p>

## How does Plasmic work?

### How codebase integration works

Note: you do not need to integrate Plasmic with a codebase.
This is core to using Plasmic as a CMS, but you can build complete apps and websites without this, entirely within Plasmic.

Read [the full technical overview](https://docs.plasmic.app/learn/technical-overview/).

### Bring your own React components

You can register your own arbitrary custom React components for use as building blocks within Plasmic Studio.
[Learn more about code components](https://docs.plasmic.app/learn/code-components/).

### Codegen

Besides the Headless API, you can also [generate React code](https://docs.plasmic.app/learn/codegen-guide) into your codebase.
This is a powerful way to use Plasmic as a UI builder for creating rich interactive web applications—one example of this is Plasmic Studio itself.
See the [application development tutorials](https://docs.plasmic.app/learn/minitwitter-tutorial) to learn more.

## Note on versioning

One common issue we see is mismatched or duplicate versions of packages.

`@plasmicapp` packages can depend on each other.
Each package always has an _exact_ version of its @plasmicapp dependencies.
This is because we want to ensure that all packages are always in sync, and that we don't end up with a mismatched set of packages.

Packages like `@plasmicapp/host` must also be deduped, since functionality such as `registerComponent` make use of globals and side effects, so with multiple versions you could end up using the wrong "instance" of this package.
Additionally, types can be tightly coupled across multiple packages.

Unfortunately, npm and yarn make it easy for you to end up with mismatched versions and duplicate versions of packages.
Use the `npm list` command to ensure that you have unique deduped versions of packages.
Furthermore, issues can be "sticky," since npm/yarn are stateful.
At times, you may need to rely on `npm dedupe`, or removing and reinstalling Plasmic packages (including `@plasmicpkgs` packages), resetting package-lock.json/yarn.lock, in order to unwedge npm/yarn.

`@plasmicpkgs` (the built-in code component packages) have `@plasmicapp` packages as peer dependencies,
and these specify ranges rather than exact versions--this is to offer some flexibility for developers to use the core package versions they need, while still using `@plasmicpkgs`.

Note: exact versioning does not imply that every package increments versions for every release.
Packages are only incremented if they or their dependencies have changed.
Incrementing versions is done automatically when our deployment scripts run `lerna version patch --exact...`,
which detects whether a package has changed since its last git-tagged release.
Internal `dependencies` and `devDependencies` are declared as `workspace:*`, which `pnpm publish` replaces with the exact version at pack time.

## Contributing 🚀

Please see [CONTRIBUTING.md](CONTRIBUTING.md).

## Get help and join our community

Our [docs][docs] and our community [forum] and [Slack] with 3000+ members are the best places to get help with Plasmic.

For support from the Plasmic team, please use the forum.
The forum is also easily searchable for all previously asked questions and discussions.

Both the docs and forum are indexed by search engines!
Search both by including “plasmic” in your query.

## License

All content outside of `platform/` is licensed under the MIT license--see LICENSE.md.

`platform/` is licensed under the AGPL--see LICENSE.platform.md.

## Contributors ❤️

Thanks to all the people who make Plasmic!

<a href="https://github.com/plasmicapp/plasmic/graphs/contributors">
  <img src="https://contrib.rocks/image?repo=plasmicapp/plasmic" />
</a>

---

### Contributing Platform 00 Getting Started (`docs/contributing/platform/00-getting-started.md`)

# Developing Plasmic Studio: getting started

## Database setup

Plasmic uses PostgreSQL (v15) as a database. We highly recommend setting postgres through docker (see `docker-compose.yml` for details). If you follow the Docker setup guide -- database will be created for you automatically.
If you prefer the manual application set up just run `docker-compose up -d --no-deps plasmic-db` in your terminal to build and launch the postgresql instance.

## OS-specific instructions

### Mac OS X

This section applies only if you install postgres manually, not through docker.

Update the version numbers for Postgresql in the following depending on what's latest!

```
{ sed 's/#.*//' | while read line; do sudo port install -b $line; done ; } << "EOF"
curl-ca-bundle
postgresql15
postgresql15-server
hadolint # for Dockerfile checking
EOF

# Follow the instructions printed during the postgresql-server installation:
sudo port select postgresql postgresql15
sudo mkdir -p /opt/local/var/db/postgresql15/defaultdb
sudo chown postgres:postgres /opt/local/var/db/postgresql15/defaultdb
sudo su postgres -c 'cd /opt/local/var/db/postgresql15 && /opt/local/lib/postgresql15/bin/initdb -D /opt/local/var/db/postgresql15/defaultdb
sudo port load postgresql15-server
```

(Your life will be much easier if you use macports. Don't use brew for installing PG.)

In order for `sudo -u postgres psql` to work without error messages, you should `chmod 755 ~`.

### Ubuntu 18.04+

- Install OS packages:

  ```
  apt update
  apt install build-essential python3 python3-pip virtualenvwrapper postgresql postgresql-contrib wget screen
  ```

- You may also need to increase your max watched file limit (see [issue](https://github.com/facebook/create-react-app/issues/2549)):
  ```
  echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
  ```

## asdf

`asdf` (https://asdf-vm.com/) manages multiple versions of runtimes/tools that we use, such as `node` and `python`.
This can be useful if you need to work in multiple environments on the same machine.

Versions are kept in version control in `.tool-versions` and `.envrc`.

1. Install `asdf`: https://asdf-vm.com/guide/getting-started.html
1. Install plugins:
   ```
   asdf plugin add nodejs
   asdf plugin add python
   asdf plugin add direnv
   ```
1. Run `asdf install` from the root directory (and any dir with `.tool-versions`).
1. In the root directory, run: `direnv allow`.
1. Check that the installed tools work and have the correct version.
   ```bash
   node --version
   python --version
   ```

Notes:

- You want asdf for python instead of using your Mac's system python because
  - in the latest MacOS 12.6 (which suddenly switches to python 3.9) building binary packages within certain environments like the pre-commit pyenv is broken, unless maybe you install Xcode.
  - we have more consistent control across platforms of which python we are relying on, which can have subtle effects on the chances of success of npm gyp builds. Plus, no more sudden switching python 3.8 to 3.9 (for ex) just because you updated MacOS!
- You want asdf-direnv so that:
  - you get local virtualenv's managed by direnv (what's called "layouts" in direnv) - these local envs are not handled by asdf.
  - things like `node --various-node-flags $(which pnpm)` work as expected (used in various scripts).
  - plus the general benefits of avoiding shims.

## Docker setup

By default, the source code is mounted as a shared volume with the host. The node modules are mounted separately, each having their own volume, in order to cache dependency installation and make sure we don't pollute the shared volume with the built artifacts.

This setup is quite heavy on CPU/RAM consumption, make sure you have **at least** 8GB of RAM available for the application container.

Launching the app through docker takes just a single command from the root of the repository:

```
docker-compose up -d
```

It will automatically spin up database, seed it, perform all the migrations, build all the source code needed for the studio to operate properly, and launch the server.

## Manual setup (suggested)

Before proceeding, make sure you have configured your [database](#database-setup) and [git hooks](#configuring-git-and-git-hooks).

### 1. Environment variables

Make sure the root of your project and `./platform/wab` folder contain the following `.env` files:

```
DATABASE_URI=postgres://wab:SEKRET@localhost:5432/wab
WAB_DBNAME=plasmic-db
WAB_DBPASSWORD=SEKRET
NODE_ENV=development
```

### 2. Installing dependencies

Run `pnpm install` in the root folder, then `pnpm install` in `./platform` (one pnpm workspace covering wab, canvas-packages, loader-bundle-env and loader-html-hydrate)

#### Configuring Git and Git hooks

The root `pnpm install` also sets up the repository's Git hooks through Husky. In a fresh Git worktree, run it at the worktree root before your first commit. The generated, gitignored `.husky/_` directory is absent until the install runs, so Git silently skips the hooks.

### 3. Seeding the database

In the `./platform/wab` run:

```
pnpm seed
```

### 4. Application setup

In the project root directory, run:

```
pnpm setup-all && pnpm bootstrap
```

### 5. Starting dev servers

Run all servers (frontend, backend, and watchers):

```
pnpm dev
```

## Using the app

The app runs on http://localhost:3003/.

If you have freshly reset the DB, the following users will be created for you
(see [seed script](/platform/wab/src/wab/server/db/DbInit.ts) for details):

- admin@admin.example.com
- user@example.com
- user2@example.com

The password for these accounts is `!53kr3tz!`.

WARNING: Avoid testing with the admin@admin.example.com user.
By default, the admin.example.com domain is considered an admin and has
elevated privileges (e.g. access to all teams, workspaces, projects, etc).
For most development purposes, use a normal user such as user@example.com.

## Troubleshooting

### Executable `hadolint` not found

Install [hadolint](https://github.com/hadolint/hadolint) if you do any changes to the docker configs

### tools/dev.bash: line 3: concurrently: command not found

If your `/platform/wab/tools/dev.bash` throws an error about `concurrently` not being a function, re-write it as `npx concurrently`

## Next steps

Dive deeper into the tooling and configuration in [01-config-tooling.md](./01-config-tooling.md).

---

### Contributing Corporate Cla (`docs/contributing/corporate-cla.md`)

In order to clarify the intellectual property license granted with Contributions from any person or entity, Plasmic Inc ("Plasmic") must have a Contributor License Agreement (CLA) on file that has been signed by each Contributor, indicating agreement to the license terms below. This license is for your protection as a Contributor as well as the protection of Plasmic and its users; it does not change your rights to use your own Contributions for any other purpose.

This version of the Agreement allows an entity (the "Corporation") to submit Contributions to Plasmic, to authorize Contributions submitted by its designated employees to Plasmic, and to grant copyright and patent licenses thereto.

You accept and agree to the following terms and conditions for Your present and future Contributions submitted to Plasmic. Except for the license granted herein to Plasmic and recipients of software distributed by Plasmic, You reserve all right, title, and interest in and to Your Contributions.

1.  Definitions.

    "You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with Plasmic. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.

    "Contribution" shall mean the code, documentation or any original work of authorship, including any modifications or additions to an existing work, that is intentionally submitted by You to Plasmic for inclusion in, or documentation of, any of the products owned or managed by Plasmic (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to Plasmic or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, Plasmic for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution."

2.  Grant of Copyright License. Subject to the terms and conditions of this Agreement, You hereby grant to Plasmic and to recipients of software distributed by Plasmic a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works.

3.  Grant of Patent License. Subject to the terms and conditions of this Agreement, You hereby grant to Plasmic and to recipients of software distributed by Plasmic a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.

4.  You represent that You are legally entitled to grant the above license. You represent further that each employee of the Corporation designated by You is authorized to submit Contributions on behalf of the Corporation.

5.  You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of others).

6.  You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.

7.  Should You wish to submit work that is not Your original creation, You may submit it to Plasmic separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as "Submitted on behalf of a third-party: [named here]".

8.  It is your responsibility to notify Plasmic when any change is required to the list of designated employees authorized to submit Contributions on behalf of the Corporation, or to the Corporation's Point of Contact with Plasmic.

---

### Contributing Individual Cla (`docs/contributing/individual-cla.md`)

In order to clarify the intellectual property license granted with Contributions from any person or entity, Plasmic Inc ("Plasmic") must have a Contributor License Agreement ("CLA") on file that has been signed by each Contributor, indicating agreement to the license terms below. This license is for your protection as a Contributor as well as the protection of Plasmic; it does not change your rights to use your own Contributions for any other purpose.

You accept and agree to the following terms and conditions for Your present and future Contributions submitted to Plasmic. Except for the license granted herein to Plasmic and recipients of software distributed by Plasmic, You reserve all right, title, and interest in and to Your Contributions.

1.  Definitions.

    "You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with Plasmic. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.

    "Contribution" shall mean any original work of authorship, including any modifications or additions to an existing work, that is intentionally submitted by You to Plasmic for inclusion in, or documentation of, any of the products owned or managed by Plasmic (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to Plasmic or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, Plasmic for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution."

2.  Grant of Copyright License. Subject to the terms and conditions of this Agreement, You hereby grant to Plasmic and to recipients of software distributed by Plasmic a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works.

3.  Grant of Patent License. Subject to the terms and conditions of this Agreement, You hereby grant to Plasmic and to recipients of software distributed by Plasmic a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.

4.  You represent that you are legally entitled to grant the above license. If your employer(s) has rights to intellectual property that you create that includes your Contributions, you represent that you have received permission to make Contributions on behalf of that employer, that your employer has waived such rights for your Contributions to Plasmic, or that your employer has executed a separate Corporate CLA with Plasmic.

5.  You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of others). You represent that Your Contribution submissions include complete details of any third-party license or other restriction (including, but not limited to, related patents and trademarks) of which you are personally aware and which are associated with any part of Your Contributions.

6.  You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON- INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.

7.  Should You wish to submit work that is not Your original creation, You may submit it to Plasmic separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as "Submitted on behalf of a third-party: [named here]".

8.  You agree to notify Plasmic of any facts or circumstances of which you become aware that would make these representations inaccurate in any respect.

---

### Contributing Platform 01 Config Tooling (`docs/contributing/platform/01-config-tooling.md`)

# Developing Plasmic Studio: config and tooling guide

## Config (optional)

Write something like this in `~/.plasmic/secrets.json`:

```
{
  "encryptionKey": "dummykey",
  "google": {
    "clientId": "SEE_GOOGLE_INSTRUCTIONS_BELOW",
    "clientSecret": "SEE_GOOGLE_INSTRUCTIONS_BELOW"
  },
  "resendApiKey": "SET_THIS_TO_RESEND_API_KEY",
  "smtpAuth": {
    "user": "SET_THIS_TO_SMTP_USER",
    "pass": "SET_THIS_TO_SMTP_KEY"
  },
  "segmentWriteKey": "ignorethis"
}
```

You'll also need `~/.aws/credentials`, since various parts such as codegen/publish and Figma import use S3.

## Database

### Setup DB

On project root directory, make sure the Postgresql server is running, and run:

```
pnpm db:setup
pnpm db:reset # specify no_sudo=1 if `sudo -u postgres psql` doesn't work
```

### Reset DB State

If you ever want to, you can reset the DB state by running (on project root):

```
pnpm db:reset # specify no_sudo=1 if `sudo -u postgres psql` doesn't work
```

> Important: remember clearing your browser cookies and restart any running servers.

## Running Servers

### Running Servers using screen

From `platform/wab`, run all servers in screens:

```
bash tools/start.bash
```

If you'd like to disable type-checking for faster incremental dev-server builds,
use:

```
NO_TYPECHECK=1 bash tools/start.bash
```

After start.bash, you'll automatically get three panes viewing various terminals, each one running some subset of procseses.

### (Experimental) Running on different ports

If you'd like to run on an alternate backend (app server) port:

```
BACKEND_PORT=3007 bash tools/start.bash
```

If you'd like to run on an alternate frontend (webpack dev server) port:

```
PORT=3006 bash tools/start.bash
```

If you'd like to run on an alternate database name:

```
WAB_DBNAME=altwab bash tools/start.bash
```

### (Incomplete) Running Servers manually

(This just documents running things in wab, but you must also run things outside of wab.)

In `wab` folder

Run backend

```
pnpm backend
```

Run frontend client dev server

```
pnpm start
```

Run host client, just a proxy on port 3005 to the frontend

```
pnpm host-server
```

### Running Servers using pm2

You can also use pm2 to manage all the server processes in dev environment.
First, initialize the shell as:

```
workon wab
. ~/.node/*/bin/activate
```

Install pm2 globally so you can use pm2 rather than "pnpm pm2"

```
npm install pm2
```

To start all processes, just

```
cd wab
pm2 start pm2-dev.config.js
```

To stop all processes,

```
pm2 stop all
```

To delete all processes,

```
pm2 delete all
```

To inspect logs,

```
pm2 logs
```

Refer to https://pm2.keymetrics.io/docs/usage/quick-start/ for more usage information.

## When pulling codebase

Whenever you fetch the latest changes, most of the time, you just need to run:

```
pnpm install
make
# restart node server
# restart webpack, once in a blue moon
```

But if something is still going wrong, try:

```
pnpm setup
# restart node server
# restart webpack, once in a blue moon
```

If the above doesn't fix the issue, try again but running `pnpm setup-all` instead.

## SVG Icons

For the in-flux SVG icons, install the icon fonts from https://github.com/keremciu/font-bundles

## Plume special package

To make sure your local database contains the latest version of the Plume
package so that you can create components from Plume templates, run:

```
pnpm plume:dev update
```

If you don't do so, studio may show a NotFoundError when you open any new
project.

## Testing

Run unit tests with:

```
bash tools/test.bash
```

## Migrating DB/model bundle schema

To migrate bundles, create a new file in the `bundle-migrations` following the same format as existing files. Small example:

```
// wab/src/wab/server/bundle-migrations/XX-my-migration.ts

import { UnsafeBundle } from "../../shared/bundles";

export function migrate(bundle: UnsafeBundle) {
    for (const [k, v] of Object.entries(bundle.map)) {
        if (v.__type === "Rule") {
            v.values = v.values;
        }
    }
}
```

And that is!

If you want to revert, simply remove the file and then restart the app server. WARNING: this will occur in data loss. If you can create a new migration instead, do so!

In reality, you only have to worry about adding files and reverting files. Our deployment scripts will take care of the rest. Here's a brief explanation on how to do the changes in your local environment:

- Migrating: add a new migration and restart the server.
- Reverting: remove the migration and restart the server.

## Migrating dev/test bundles

We have some local JSON bundles for development/test purposes, which you also need to migrate.

To migrate these, run:

```bash
pnpm migrate-dev-bundles
```

This runs any necessary migrations according to the version stamp.

Then make sure you run the tests and update the snapshots.

NOTE: This will first do a `git checkout` on the file, resetting to a fresh checkout state! This lets you repeatedly test and run your migration script on the file.

## Debugging Studio

Because Studio runs in a cross-origin iframe, debugging becomes a bit trickier.

In particular, the React Devtools Chrome extension will not work. However, you can run the standalone React Devtools Electron package.

Install and run `react-devtools`:

```bash
    npm install react-devtools
    react-devtools
```

Alternatively you can run it with npx:

```bash
npx react-devtools
```

And now when you open up Studio with the devflag `?enableReactDevTools=true` and it should auto-connect.
It should work for both dev server and prod.

## Debugging Node Server

You can use IntelliJ/Webstorm.

Or use `node --inspect` to debug your node app using Chrome DevTools - just open about:inspect in Chrome as per
<https://medium.com/@paul_irish/debugging-node-js-nightlies-with-chrome-devtools-7c4a1b95ae27>.

## Ant

We're opting to import all Ant styles wholesale and override their globals
in antd-overrides.less. This allows for live theming (no dev server restarts
necessary).

## Maintaining dependencies

Check what dependencies are not used (or missing):

```
pnpm knip:deps
```

Check what needs to be updated:

```
pnpm outdated
```

Update the dependencies:

```
pnpm up --latest
```

This will upgrade everything. You can also try selectively upgrading individual
packages, but things get complicated with upgrading dependencies that are
also indirect dependencies of other dependencies.

## Alternate configs

When pointing to a different DB, you currently have to make sure you locally
edit ormconfig.json (used by typeorm CLI) and set the WAB_DBNAME env var.

## Audit licenses of dependencies

For node dependencies, do this from each project directory:

    npx license-checker --csv --out license-checker.csv

For Python dependencies, do this from each project directory:

    pip-licenses --from=mixed -f csv > pip-licenses.csv

## Production Build

Run `pnpm build` to build client app for production. This takes a long time (>5m).

You can test out your built artifact with:

```
  npm install local-web-server
  cd build/
  ws --spa index.html --rewrite '/api/(.*) -> http://localhost:3004/api/$1'
```

Then open http://localhost:8000.

---

### Contributing Platform 02 Integrations (`docs/contributing/platform/02-integrations.md`)

# Developing Plasmic Studio: third-party system integrations

## Figma import

See [Figma plugin setup](03-figma.md).

## Plasmic hosting on Vercel

To locally access a Plasmic-hosted project, run the hosting application from
`platform/hosting`:

```bash
cd platform/hosting
pnpm dev
```

To run it against a local Studio project, temporarily hardcode the local project's
`projectId`, `token`, and `wantToShowBadge` in
`platform/hosting/pages/_sites/[site]/[[...catchall]].tsx`. Then set the API host:

```bash
cd platform/hosting
NEXT_PUBLIC_PLASMIC_HOST=http://localhost:3003 pnpm dev
```

You can access a published project at `http://localhost:3000/_sites/yourdomain.plasmic.run`,
which is equivalent to `yourdomain.plasmic.run`.

## Setting up Google SSO

For now, users who use SSO must have an email domain that matches an org's domain.

Each developer who works on Plasmic and wants to try out SSO will need to set up
a project on Google Developers Console.

- Go to [Google Developers Console](https://console.developers.google.com/)
- On the upper-left corner, you can see the Project you are using (next to three black hexagons).
  Click it, and in the dialog box, click "New Project" on the upper-right.
- Name your project something like "Plasmic Yang Dev"
- Click on the Credentials tab on the left sidebar.
- First click on the "OAuth consent screen". Fill in the required fields, and for scopes,
  make sure "email", "profile", "openid" are included (should be by default).
- Next, click on the "Credentials tab"
  - Select "Create credentials", and choose "OAuth Client ID".
  - Application type: "Web application"
  - Name: <whatever you want>
  - Authorized Javascript origins: [http://localhost:3003]
  - Authorized redirect URIs: [http://localhost:3003/api/v1/oauth2/google/callback]
- Save the client ID and secret in your `~/.plasmic/secrets.json`. It should look like:
  ```json
  {
    "encryptionKey": "this is a secret DB encryption key",
    "google": {
      "clientId": "YOUR CLIENT ID",
      "clientSecret": "YOUR CLIENT SECRET"
    }
  }
  ```

## Setting up GitHub App

- Sign in to GitHub with your personal account and go to
  [GitHub Developer Settings](https://github.com/settings/apps).
- Create a new GitHub App with the following information:
  - Homepage URL: http://localhost:3003
  - Callback URL: http://localhost:3003/github/callback
  - Uncheck "Expire user authorization tokens"
  - Check "Request user authorization (OAuth) during installation"
  - Deactivate webhook
  - Repository permissions:
    - Actions: Read & write
    - Administration: Read & write
    - Contents: Read & write
    - Pages: Read & write
    - Pull requests: Read & write
    - Workflows: Read & write
- Click on "Edit" in the app you created and generate/store a client secret
  and a private key.
- Fill the following fields in your ~/.plasmic/secrets.json:

  ```json
  {
    "github": {
      "appId": "<APP_ID>",
      "privateKey": "-----BEGIN RSA PRIVATE KEY-----\n<YOUR_KEY>...",
      "oauth": {
        "clientId": "<CLIENT_ID>",
        "clientSecret": "<CLIENT_SECRET>"
      }
    }
  }
  ```

  **Note that the private key must have its line breaks replaced by "\n".**

- Edit the devflags (in your local storage) changing githubClientId and
  githubAppName to your app client ID and kebab-cased name (copy it from the
  app URL), then reload studio for changes to take effect.

### Developing/debugging GitHub integration

Here are various tips and tools for localhost development.

### Set an externally facing URL

GitHub Actions needs to call your app server to perform syncs, so use a service
like localhost.run and set your `externalBaseUrl` devflag to point to your
resulting temp URL.

### Use toolchain debug flags

We internally use our own toolchain including create-plasmic-app,
@plasmicapp/cli, @plasmicapp/loader, etc. For local-only testing in a pnpm
project, use the `local-link` setup/build/teardown workflow documented in
[CONTRIBUTING.md](../../../CONTRIBUTING.md). It uses temporary `file:` overrides
without changing the package versions declared by the consuming project. You
can also use the various debug flags for those packages like
`PLASMIC_DEFAULT_HOST`.

For example, to have the CLI/PlasmicLoader point to your own localhost server:

    PLASMIC_DEFAULT_HOST=http://localhost:3003 pnpm backend

This is ignored by the app server but consumed by CLI/PlasmicLoader.

See the various READMEs on those projects for relevant debug flags.

### Publish the toolchain first

The CLI/PlasmicLoader does eventually get run on GitHub Actions runners, so the "easiest" way to test things for now is to publish first.

Potentially, you can also amend the resulting package.json (in the repo that gets pushed to GitHub) to point to some alternate package source, but I haven't done/needed this yet.

## Setting up billing (Stripe)

To test billing locally, add Stripe test secret key (https://dashboard.stripe.com/test/apikeys) to secrets.json:

```json
{
  "stripe": {
    "secretKey": "<PASTE_SECRET_KEY_HERE>"
  }
}
```

## Setting up Google Sheets

Have a GCloud account, Sheets API enabled, OAuth consent screen.

Create an OAuth client.

- Type: web application
- Redirects: http://localhost:3003/api/v1/oauth2/google-sheets/callback

Save into secrets.json:

```json
{
  "google-sheets": {
    "clientId": "<CLIENT_ID>",
    "clientSecret": "<CLIENT_SECRET>"
  }
}
```

---

### Contributing Platform 03 Figma (`docs/contributing/platform/03-figma.md`)

# Figma plugin setup

The plugin copies a `clipId` and uploads selected layers through a web bridge (`figma-plugin-web`) to `PUT /api/v1/clip/:clipId`. Studio fetches the data on paste with `GET /api/v1/clip/:clipId`.

## Use the production plugin

For internal development, use the published plugin if your Studio app server has authorized read access to production clip storage. Set `CLIP_BUCKET`, `S3_ENDPOINT`, and AWS credentials to match that storage, then restart the server. Having `~/.aws/credentials` alone does not grant access.

For separate storage, configure the bridge and exporter below.

## Configure storage

Set these on the Studio app server:

```sh
CLIP_BUCKET=your-figma-clips
# For S3-compatible storage:
# S3_ENDPOINT=https://s3.example.com
```

Use a private bucket and AWS credentials with `GetObject` and `PutObject` access. Allow multipart operations for large uploads. No public
bucket access or bucket CORS is needed. `CLIP_BUCKET` defaults to `plasmic-clips`, `S3_ENDPOINT` also affects other app server storage clients. The clip client doesn't force path-style addressing.

Clip routes don't need Studio auth or CSRF, anyone with a clip ID can retrieve it. Remember to set an expiration policy.

## Serve the web bridge

Use the repository’s Node version and each package’s pinned pnpm version.
From the repository root:

```sh
cd platform/figma-plugin-web
pnpm install --frozen-lockfile
PUBLIC_URL=/figma-plugin-app NODE_OPTIONS=--openssl-legacy-provider SKIP_PREFLIGHT_CHECK=true pnpm build
```

The flags are for Webpack 4 on Node 24 and Create React App’s ancestor dependency check. Serve `build/` at `https://studio.example.com/figma-plugin-app/`, on the same origin as the Studio API. The bridge uses relative `/api/v1/...` URLs.

## Build the exporter

In `platform/figma-plugin-plasmic-exporter`:

1. Set iframe `src` in `src/ui/components/App.tsx` to your URL, e.g. `https://studio.example.com/figma-plugin-app/`.
2. Set `networkAccess.allowedDomains` in `manifest.json` to `["https://studio.example.com"]`. For local development, use `devAllowedDomains` with HTTPS origin and port ([Figma manifest reference](https://developers.figma.com/docs/plugins/manifest/)).
3. Build:

   ```sh
   pnpm install --frozen-lockfile
   NODE_OPTIONS=--openssl-legacy-provider pnpm build
   ```

In Figma desktop, choose **Plugins → Development → Import plugin from manifest…** and select this package’s `manifest.json`. Run that plugin, select layers, click **Export selected layers to clipboard**, wait for completion, and paste into Studio. Rebuild and relaunch after source changes, and distribute `manifest.json`and `dist/` together.

## Troubleshoot

- **Export hangs:** check bridge assets, HTTPS, iframe URL, manifest allowlist, framing headers, and login redirects in Figma’s developer console.
- **Upload fails:** check the PUT response and app logs for storage permissions, routing, or request size limits.
- **Paste cannot find the clip:** verify the plugin’s destination and Studio’s bucket/endpoint match. The published plugin uses production storage.

Sources: [bridge](../../../platform/figma-plugin-web/src/index.tsx),
[clip API](../../../platform/wab/src/wab/server/routes/misc.ts),
[paste handler](../../../platform/wab/src/wab/client/figma.tsx).

---

### Contributing Platform Dev Notes (`docs/contributing/platform/dev-notes.txt`)

React Gotchas
=============

- For some reason, if a component crashes on the first render (within the
  ViewInitializer's first `setState({viewCtx})`), this causes some very
  confusing issues with attempting to reload the base-pkg and refresh the app
  again from the top.  This might manifest as an attempt to render
  foreign components and then not finding the component in
  ForeignComponents.forValComponent().  I ran into this when e.g. enabling
  CreateTab rendering earlier (renders the gallery even when no selection is
  active, but there was a silly bug in CreateItem triggering the above symptoms)

Library Gotchas
===============

- Do not import from "jquery", always use the one from deps.  They have
different plugins, but more subtlely, they have different .data() stores.

WAB Gotchas
===========

- Tpls.ancestors doesn't do any filtering, but canvasCtx().valAncestors() filters
  out the valUserRoot!  (Which is good since in both isolated component editing
  mode and normal page editing mode, they're more like sentinels.)
- Tagger will actually tag the portaled div of a React Bootstrap Modal on first
  render (as seen in componentDidMount), but not later updates that re-show the
  div (componentDidUpdate just sees null).  I'm not able to repro that initial
  tagging outside of WAB---see e.g. https://codesandbox.io/s/q8828q9p69.  So
  don't rely on that initial tagging.
- Currently, when you insert a Modal, you might have this val tree:

    ValComponent for Modal
      ValComponent for ModalBody
        ValTag for div

  which renders as these React components:

    CanvasElement
      Sub
        Modal
          ModalBody <-- Modal expects ModalBody to be its direct child
            Sup
              CanvasElement
                div

  Because of that parent-child requirement, we unfortunately can't interleave a
  CanvasElement, which would let us more easily associate the DOM node (with
  .getDOMNode() or .findDOMNode()) with that ValComponent (without overriding
  more bsRole settings---which may be a good thing to consider eventually).

---

### Platform Wab Docs ICONS (`platform/wab/docs/ICONS.md`)

# Icons

Studio icons are SVG React components generated by Plasmic, not hand-written
files. Most of them come from the `[PlasmicKit] Icons` project
(`oT38tGyqov9SPWHpf3Y2Rf`) and land in
`src/wab/client/plasmic/plasmic_kit_icons/icons/PlasmicIcon__*.tsx`. A few
older ones live under the other `src/wab/client/plasmic/plasmic_kit_*/`
directories.

## Adding a new icon

1. Check whether an existing icon works first. There are ~600 of them, so
   search `src/wab/client/plasmic/plasmic_kit_icons/icons/` before drawing
   anything new.
2. Add the SVG as an icon asset in the `[PlasmicKit] Icons` Plasmic project,
   following the conventions below.
3. Sync it into the repo:

   ```
   pnpm plasmic:sync
   ```

   This writes the generated component and registers it in `plasmic.json`.
   Commit both.

4. Give it a semantic name in `src/wab/client/icons.tsx` rather than importing
   the generated `PlasmicIcon__*` module all over the codebase.

## SVG conventions

New icons should match the existing set:

- `viewBox="0 0 24 24"` (the set is drawn at 24×24, even though it renders at
  16px by default)
- `fill="none"` on the `<svg>` element; draw with strokes, not fills
- `stroke="currentColor"` so the icon inherits text color — never hardcode a
  color
- `stroke-width="1.5"`
- `stroke-linecap="round"` and `stroke-linejoin="round"`
- Prefer a single `<path>` over many primitives
- Keep the artwork inside the 24×24 box with a consistent margin instead of
  bleeding to the edges, so icons look the same weight when placed side by side

An existing icon that follows all of the above, useful as a reference:
`src/wab/client/plasmic/plasmic_kit_icons/icons/PlasmicIcon__Braces.tsx`.

## Using an icon

Render icons through the `Icon` widget, which applies the standard sizing
(16px) and the `custom-svg-icon` class:

```tsx
import { Icon } from "@/wab/client/components/widgets/Icon";
import BracesIcon from "@/wab/client/plasmic/plasmic_kit_icons/icons/PlasmicIcon__Braces";

<Icon icon={BracesIcon} />;
```

Pass `size` to override the default, and `monochromeExempt` for the rare icon
that should keep its own colors.

---

--- METRICS ---
- Files Extracted: 9
- Estimated Token Budget: ~12548 tokens
- Canonical Reference: https://codewiki.google/github.com/plasmicapp/plasmic
