# The free canvas

> In Next.js App Router projects, anything you draw, drop or paste outside the breakpoints floats on the canvas. How to use it, and the page it lives in.

- Page: https://midcode.app/docs/editor/free-canvas
- From the midcode docs. Every page as Markdown: https://midcode.app/llms.txt

In a Next.js project that uses the App Router, the canvas around the breakpoints is a place to work. Anything you draw, drop or paste there floats, the way a frame does in Framer. Build a section before it goes into a page, park something you took out, or keep alternatives side by side.

What floats is real code, in one page of your project that exists only in development and that midcode never publishes.

## Where it works

In Next.js projects that use the App Router (an `app/` or `src/app/` folder). From the next release, also in Next.js projects on the Pages Router and in Vite apps written in React, Preact or Solid ([Other React projects](#other-react-projects)), and, for plain elements, in [Vue, Svelte, Astro and HTML projects](#vue-svelte-astro-and-html). In every other project the canvas outside the breakpoints is empty space: `F` inserts a frame into the selection instead, and dropping there puts the element at the end of the page. If you drag an element out of a frame anyway, midcode says "Things float on the canvas in Next.js App Router projects, for now".

## Other React projects (next release)

In the next release the free canvas works the same in two more kinds of project. Only the file that holds what floats is somewhere else:

| Project | The file | Why it's never published |
| --- | --- | --- |
| Next.js, App Router | `app/midcode-scratch/page.tsx` | It answers 404 in production |
| Next.js, Pages Router | `pages/midcode-scratch.tsx` | Its `getStaticProps` answers "not found" in production |
| Vite + React, Preact or Solid | `src/midcode-scratch.tsx` | Nothing in your app imports it, so it's never built |

In a Vite app there is no route for that file. While midcode runs your dev server, its plugin answers `/midcode-scratch` with your own `index.html`, with the app's entry replaced by one that draws that component and loads the stylesheets your entry imports. midcode leaves the file out of Publish in all three.

A Vite app needs an `index.html` at its root for this: TanStack Start, Qwik and a Laravel app with Vite don't have the free canvas.

## Vue, Svelte, Astro and HTML (next release)

Outside React, what floats is plain HTML, the same in every one of these: a file with only the canvas's `<main>` in it.

| Project | The file |
| --- | --- |
| Vite + Vue, Vite + Svelte, SvelteKit, Astro | `src/midcode-scratch.html` |
| A folder of HTML | `midcode-scratch.html`, beside your `index.html` |

It isn't a page of the site. While midcode runs the site it serves a page around that file, at `/midcode-scratch.html`, with your stylesheets: the ones your entry, `App.vue`, the root `+layout.svelte` or your Astro layouts import, or in a folder of HTML the `<head>` of your home page. midcode leaves the file out of Publish.

Because the file is HTML and not a `.vue`, `.svelte` or `.astro` file, only plain elements can float:

- A component can't: "A component can't float on the canvas in this kind of project: only plain elements do."
- An element with something computed in it can't either (`{{ title }}`, a `v-for`, an `{#if}`, a bound attribute): "This has code in it ({{ }}, a loop, a condition): only plain elements float on the canvas in this kind of project."

Everything else works as in React: draw a frame, drop something from Insert, drag an element out of a page and back in, copy with `⌥`, wrap several in a stack, move them with the arrows. Going into a `.svelte` or `.astro` page, an element whose text has a `{` or a `}` is refused, since the page would read it as code.

Nuxt and the templates a server renders (Laravel, Django, Rails, WordPress, Shopify themes) don't have the free canvas.

## Put something on the canvas

| To | Do this |
| --- | --- |
| Draw a frame | Press `F` (or the frame button in the toolbar) and drag on the canvas. A label shows the size. A click without dragging makes one of 200 × 200. `Esc` puts the tool away. |
| Take an element out of a page | Drag it out of its frame and release over the empty canvas. |
| Copy an element out of a page | The same, holding `⌥`: the element stays and a copy floats. |
| Add something new | Drag an item from the [Insert](https://midcode.app/docs/editor/insert.md) panel, or a component from Assets, and release over the empty canvas. |
| Add an image or a video | Drop files from Finder on the empty canvas, or press `⌘V` with an image on the clipboard and nothing selected. See [Text, images and video](https://midcode.app/docs/editor/text-and-media.md). |
| Paste an element | `⌘C` on any element, deselect (`Esc`), `⌘V`. The copy lands in the middle of what's in view. |

A floating element is designed at the primary breakpoint's width: its responsive classes show the values of that breakpoint.

An element with no width of its own is as wide as its content. A text or a stack that has nothing behind it is shown over your page's background color, so light text chosen for a dark page stays readable. Frames and images float as they are.

## Select and arrange

Click a floating element to select it. It works like any other selection: the right panel edits it, a double-click edits its text, and its own layers are in [Layers](https://midcode.app/docs/editor/layers.md), after the breakpoints.

| To | Do this |
| --- | --- |
| Move | Drag it. A label shows its position. |
| Move by 1 px | Arrow keys. With `⇧`, by the nudge amount set in Settings. |
| Resize | Drag any of its eight handles. `⇧` on a corner keeps the proportions. |
| Rotate | Drag just outside a corner. `⇧` turns in steps of 15°. |
| Select several | Drag a box over them on the empty canvas, or `⇧` + click each one. `⌘A` with nothing selected takes all of them. |
| Duplicate | `⌘D`, or hold `⌥` while dragging. |
| Delete | `⌫` |
| Wrap in a stack | Select several and press `⇧A`. |

Several selected elements move together, with the pointer or the arrow keys, and `⌘C`, `⌘X`, `⌘D` and `⌫` apply to all of them.

A copy never lands on top of its original. `⌘D` and `⌘V` put it to the right of what's selected, 40 px away. Copies of several keep their places among themselves.

`⇧A` on floating elements makes one floating stack in their place. It's a row if they sit side by side and a column if they sit one above the other, in that order, and the space between them becomes its gap.

### Snapping

While you move or resize a floating element, it lines up with the edges and centers of the other floating elements, with the breakpoints' frames, and with guides. It also snaps to the same distance its neighbours keep. Lines and distances show what it found.

Hold `⌘` or `⌃` to move freely. `⇧` keeps the move on one axis. Rulers and guides are covered in [Select, move and resize](https://midcode.app/docs/editor/select-move-resize.md).

## Into a page and back

Drag a floating element over a breakpoint. The blue line shows where it would land in the page, as when you [move an element](https://midcode.app/docs/editor/select-move-resize.md). Release, and it's written into the page's file, at that place, without its canvas marks. The imports it needs go with it.

Drag it over another floating element instead and it goes inside that one.

Going the other way, an element dragged out of a page is cut from its file and written into the canvas page, with its imports. Either direction is one edit: one `⌘Z` puts the element back where it was.

What can't cross is an element that depends on where it's written, like an item inside a `.map()` that reads the loop's values: "This element uses post from its file: move it in the code."

## What midcode writes

Everything that floats lives in one file: `app/midcode-scratch/page.tsx` (under `src/app/` if that's where your app is, and `.jsx` if the project has no `tsconfig.json`). midcode creates it the first time something floats:

```tsx title="app/midcode-scratch/page.tsx"
import { notFound } from 'next/navigation'

// What floats on midcode's canvas, outside the site's breakpoints. It only exists in development
// (a 404 on the live site), and midcode never publishes it.
export default function MidcodeCanvas() {
  if (process.env.NODE_ENV === 'production') notFound()
  return (
    <main data-midcode-scratch>
    </main>
  )
}
```

Each floating element is a direct child of that `<main>`, with two attributes: an id, and where it sits.

```tsx title="app/midcode-scratch/page.tsx"
import { notFound } from 'next/navigation'
import { PricingCard } from '@/components/PricingCard'

// What floats on midcode's canvas, outside the site's breakpoints. It only exists in development
// (a 404 on the live site), and midcode never publishes it.
export default function MidcodeCanvas() {
  if (process.env.NODE_ENV === 'production') notFound()
  return (
    <main data-midcode-scratch>
      <div data-midcode-item="3f9a1c2e" data-midcode-at="2960 80" className="h-[320px] w-[480px] bg-white" />
      <h2 data-midcode-item="b71d04aa" data-midcode-at="2960 480" className="text-4xl font-semibold">
        Simple pricing
      </h2>
      <div data-midcode-item="0c5e77d1" data-midcode-at="3520 80" data-midcode-wrap>
        <PricingCard plan="Studio" />
      </div>
    </main>
  )
}
```

| Attribute | What it is |
| --- | --- |
| `data-midcode-scratch` | Marks the `<main>` that holds everything floating. |
| `data-midcode-item` | The element's id on the canvas: eight characters, unique in the file. |
| `data-midcode-at` | Its position, `x y`, in canvas px. `0 0` is the top left corner of the first breakpoint's frame. The rulers show the same coordinates. |
| `data-midcode-wrap` | On the `<div>` around a component. A component might not pass unknown attributes on to its element, so the marks go on a wrapper. |

The first element above is a frame drawn with `F`: a `<div>` with its size and a white fill.

Every gesture is an edit of that file:

- Moving changes `data-midcode-at`. That's why `⌘Z` moves an element back.
- Resizing writes `w-*` and `h-*`. From the left or the top it changes the position too.
- Rotating writes a class: `rotate-[12deg]`. Back at 0°, the class is removed.
- Going into a page removes the two attributes (and the wrapper around a component) and moves the code to the page's file.

### Never published

- The page calls `notFound()` when `NODE_ENV` is `production`. On your live site, `/midcode-scratch` answers 404.
- midcode leaves it out of [Publish](https://midcode.app/docs/publish/publish.md): it's never in the list of files, and its edits aren't in the list of changes.
- It isn't in the Pages list or in the texts of [Languages](https://midcode.app/docs/data/languages.md).

> [!NOTE]
> The file is not in `.gitignore`, on purpose. Tailwind doesn't scan files that git ignores, so the classes of what floats would never be generated: a drawn frame would have no size. That means `git add -A` in a terminal does stage it. Committing it is harmless (it's a page that answers 404 in production), but if you'd rather not, leave it out of your own commits, don't ignore it.

### Editing the file by hand

You or your agent can write in it. The rules are the ones above: everything directly inside `<main data-midcode-scratch>` needs its own `data-midcode-item` and a `data-midcode-at`. When midcode reads a file that breaks them, it repairs it:

- two elements with the same id: the second gets a new one;
- an element with no marks: it gets them, where what's inside it was, or below everything else;
- marks on an element nested inside a floating one: removed.

Delete the file (or the `midcode-scratch` folder) to clear the canvas. midcode makes a new one the next time something floats.

## Limits

- In the released version, Next.js App Router only. The next release adds the Pages Router, Vite apps in React, Preact or Solid, and, for plain elements, Vue, Svelte, Astro and folders of HTML. Nuxt and server templates don't have it yet.
- A floating element shows the primary breakpoint's styles. To see something at other widths, put it in a page.
- A component floats inside a wrapper `<div>` that is as wide as its content, unless you give the wrapper a width.
- Dragging into another floating element works for one element at a time, not for several selected together.
- The canvas page is a page of your app: it renders inside your root layout, so the layout's providers, fonts and global styles apply to what floats.
