diff --git a/x-pack/index.js b/x-pack/index.js
index d5c5a5c51389d..6e7528082d888 100644
--- a/x-pack/index.js
+++ b/x-pack/index.js
@@ -38,7 +38,7 @@ import { translations } from './plugins/translations';
 import { upgradeAssistant } from './plugins/upgrade_assistant';
 import { uptime } from './plugins/uptime';
 import { ossTelemetry } from './plugins/oss_telemetry';
-import { visualizationEditor } from './plugins/visualization_editor';
+import { visualizationLens } from './plugins/visualization_lens';
 
 module.exports = function (kibana) {
   return [
@@ -76,6 +76,6 @@ module.exports = function (kibana) {
     upgradeAssistant(kibana),
     uptime(kibana),
     ossTelemetry(kibana),
-    visualizationEditor(kibana),
+    visualizationLens(kibana),
   ];
 };
diff --git a/x-pack/plugins/visualization_editor/index.ts b/x-pack/plugins/visualization_editor/index.ts
deleted file mode 100644
index 8c77fd2093e25..0000000000000
--- a/x-pack/plugins/visualization_editor/index.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import * as Joi from 'joi';
-import { resolve } from 'path';
-import { PLUGIN_ID } from './common';
-
-export function visualizationEditor(kibana: any) {
-  return new kibana.Plugin({
-    id: PLUGIN_ID,
-    configPrefix: `xpack.${PLUGIN_ID}`,
-    publicDir: resolve(__dirname, 'public'),
-    require: ['kibana', 'elasticsearch', 'xpack_main'],
-    uiExports: {
-      app: {
-        title: 'Visualization Editor',
-        description: 'Explore and visualize data.',
-        main: `plugins/${PLUGIN_ID}/index`,
-        icon: 'plugins/kibana/assets/visualize.svg',
-        euiIconType: 'visualizeApp',
-      },
-      styleSheetPaths: resolve(__dirname, 'public/index.scss'),
-    },
-
-    config(joi: Joi.Root) {
-      return joi
-        .object({
-          enabled: joi.boolean().default(true),
-        })
-        .default();
-    },
-  });
-}
\ No newline at end of file
diff --git a/x-pack/plugins/visualization_editor/common/constants.ts b/x-pack/plugins/visualization_lens/common/constants.ts
similarity index 83%
rename from x-pack/plugins/visualization_editor/common/constants.ts
rename to x-pack/plugins/visualization_lens/common/constants.ts
index b7607abedf84c..147784cce5cc1 100644
--- a/x-pack/plugins/visualization_editor/common/constants.ts
+++ b/x-pack/plugins/visualization_lens/common/constants.ts
@@ -4,4 +4,4 @@
  * you may not use this file except in compliance with the Elastic License.
  */
 
-export const PLUGIN_ID = 'visualization_editor';
+export const PLUGIN_ID = 'visualization_lens';
diff --git a/x-pack/plugins/visualization_editor/common/index.ts b/x-pack/plugins/visualization_lens/common/index.ts
similarity index 100%
rename from x-pack/plugins/visualization_editor/common/index.ts
rename to x-pack/plugins/visualization_lens/common/index.ts
diff --git a/x-pack/plugins/visualization_lens/index.ts b/x-pack/plugins/visualization_lens/index.ts
new file mode 100644
index 0000000000000..accf5e80b7f26
--- /dev/null
+++ b/x-pack/plugins/visualization_lens/index.ts
@@ -0,0 +1,73 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import * as Joi from 'joi';
+import { Server } from 'hapi';
+import { resolve } from 'path';
+
+import { PLUGIN_ID } from './common';
+
+const NOT_INTERNATIONALIZED_PRODUCT_NAME = 'Lens Visualizations';
+
+export const visualizationLens = (kibana: any) => {
+  return new kibana.Plugin({
+    id: PLUGIN_ID,
+    configPrefix: `xpack.${PLUGIN_ID}`,
+    require: ['kibana', 'elasticsearch', 'xpack_main', 'interpreter'],
+    publicDir: resolve(__dirname, 'public'),
+
+    uiExports: {
+      app: {
+        title: NOT_INTERNATIONALIZED_PRODUCT_NAME,
+        description: 'Explore and visualize data.',
+        main: `plugins/${PLUGIN_ID}/app`,
+        icon: 'plugins/kibana/assets/visualize.svg',
+        euiIconType: 'visualizeApp',
+        order: 8950, // Uptime is 8900
+      },
+      styleSheetPaths: resolve(__dirname, 'public/index.scss'),
+    },
+
+    config: () => {
+      return Joi.object({
+        enabled: Joi.boolean().default(true),
+      }).default();
+    },
+
+    init(server: Server) {
+      server.plugins.xpack_main.registerFeature({
+        id: PLUGIN_ID,
+        name: NOT_INTERNATIONALIZED_PRODUCT_NAME,
+        icon: 'visualizeApp',
+        navLinkId: PLUGIN_ID,
+        app: [PLUGIN_ID, 'kibana'],
+        catalogue: [PLUGIN_ID],
+        privileges: {
+          all: {
+            api: [PLUGIN_ID],
+            catalogue: [PLUGIN_ID],
+            savedObject: {
+              all: [],
+              read: [],
+            },
+            ui: ['show'],
+          },
+          read: {
+            api: [PLUGIN_ID],
+            catalogue: [PLUGIN_ID],
+            savedObject: {
+              all: [],
+              read: [],
+            },
+            ui: ['show'],
+          },
+        },
+      });
+    },
+  });
+};
+
+export { editorFrame } from './public';
diff --git a/x-pack/plugins/visualization_editor/package.json b/x-pack/plugins/visualization_lens/package.json
similarity index 68%
rename from x-pack/plugins/visualization_editor/package.json
rename to x-pack/plugins/visualization_lens/package.json
index 34cd4146856c0..371152435e413 100644
--- a/x-pack/plugins/visualization_editor/package.json
+++ b/x-pack/plugins/visualization_lens/package.json
@@ -1,11 +1,11 @@
 {
   "author": "Elastic",
-  "name": "visualization_editor",
+  "name": "visualization_lens",
   "version": "7.0.0",
   "private": true,
   "license": "Elastic-License",
   "devDependencies": {},
   "dependencies": {
-    "@elastic/charts": "^3.11.0"
+    "@elastic/charts": "^4.0.0"
   }
 }
\ No newline at end of file
diff --git a/x-pack/plugins/visualization_editor/public/index.tsx b/x-pack/plugins/visualization_lens/public/app.tsx
similarity index 54%
rename from x-pack/plugins/visualization_editor/public/index.tsx
rename to x-pack/plugins/visualization_lens/public/app.tsx
index e65e404ec4133..e3ffa0447d07c 100644
--- a/x-pack/plugins/visualization_editor/public/index.tsx
+++ b/x-pack/plugins/visualization_lens/public/app.tsx
@@ -5,23 +5,42 @@
  */
 
 import { I18nProvider } from '@kbn/i18n/react';
-import React from 'react';
+import { IScope } from 'angular';
+import React, { useCallback } from 'react';
 import { render, unmountComponentAtNode } from 'react-dom';
 import chrome from 'ui/chrome';
+
 import { PLUGIN_ID } from '../common';
 
-// TODO: Convert this to the "new platform" way of doing UI
-function App($scope: any, $element: Element[]) {
-  const el = $element[0];
+import { editorFrame } from '.';
 
-  $scope.$on('$destroy', () => unmountComponentAtNode(el));
+// Side effect of loading this is to register
+import './indexpattern_datasource';
+
+function Lens() {
+  const renderFrame = useCallback(node => {
+    if (node !== null) {
+      editorFrame.render(node);
+    }
+  }, []);
 
-  return render(
+  return (
     <I18nProvider>
-      <h1>Visualization Editor</h1>
-    </I18nProvider>,
-    el
+      <div>
+        <h1>Lens</h1>
+
+        <div ref={renderFrame} />
+      </div>
+    </I18nProvider>
   );
 }
 
+// TODO: Convert this to the "new platform" way of doing UI
+function App($scope: IScope, $element: JQLite) {
+  const el = $element[0];
+  $scope.$on('$destroy', () => unmountComponentAtNode(el));
+
+  return render(<Lens />, el);
+}
+
 chrome.setRootController(PLUGIN_ID, App);
diff --git a/x-pack/plugins/visualization_lens/public/editor_frame.tsx b/x-pack/plugins/visualization_lens/public/editor_frame.tsx
new file mode 100644
index 0000000000000..8534eb3d3e375
--- /dev/null
+++ b/x-pack/plugins/visualization_lens/public/editor_frame.tsx
@@ -0,0 +1,70 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React, { useCallback } from 'react';
+import { render } from 'react-dom';
+import { Datasource, Visualization, EditorFrameAPI } from './types';
+
+function EditorFrameComponent(props: {
+  datasources: Array<Datasource<unknown>>;
+  visualizations: Array<Visualization<unknown>>;
+}) {
+  const renderDatasource = (datasource: Datasource<unknown>) => {
+    return useCallback(
+      node => {
+        datasource.renderDataPanel({
+          domElement: node,
+        });
+      },
+      [datasource]
+    );
+  };
+
+  return (
+    <div>
+      <h2>Editor Frame</h2>
+
+      {props.datasources.map((datasource, index) => (
+        <div key={index} ref={renderDatasource(datasource)} />
+      ))}
+    </div>
+  );
+}
+
+class EditorFrame {
+  constructor() {}
+
+  private datasources: Array<Datasource<unknown>> = [];
+  private visualizations: Array<Visualization<unknown>> = [];
+
+  public setup(): EditorFrameAPI {
+    return {
+      render: (domElement: Element) => {
+        render(
+          <EditorFrameComponent
+            datasources={this.datasources}
+            visualizations={this.visualizations}
+          />,
+          domElement
+        );
+      },
+      registerDatasource: (datasource: Datasource<unknown>) => {
+        this.datasources.push(datasource);
+      },
+      registerVisualization: (visualization: Visualization<unknown>) => {
+        this.visualizations.push(visualization);
+      },
+    };
+  }
+
+  public stop() {
+    return {};
+  }
+}
+
+export { EditorFrame };
+
+export const editorFrame = new EditorFrame().setup();
diff --git a/x-pack/plugins/visualization_editor/public/index.scss b/x-pack/plugins/visualization_lens/public/index.scss
similarity index 100%
rename from x-pack/plugins/visualization_editor/public/index.scss
rename to x-pack/plugins/visualization_lens/public/index.scss
diff --git a/x-pack/plugins/visualization_lens/public/index.ts b/x-pack/plugins/visualization_lens/public/index.ts
new file mode 100644
index 0000000000000..a48e0c74bb81f
--- /dev/null
+++ b/x-pack/plugins/visualization_lens/public/index.ts
@@ -0,0 +1,8 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export * from './editor_frame';
+export * from './types';
diff --git a/x-pack/plugins/visualization_lens/public/indexpattern_datasource/index.ts b/x-pack/plugins/visualization_lens/public/indexpattern_datasource/index.ts
new file mode 100644
index 0000000000000..d996045cb3156
--- /dev/null
+++ b/x-pack/plugins/visualization_lens/public/indexpattern_datasource/index.ts
@@ -0,0 +1,14 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+// TODO: Figure out how to separate this out into another plugin
+import { editorFrame } from '../../';
+
+import { indexPatternDatasource } from './indexpattern';
+
+editorFrame.registerDatasource(indexPatternDatasource);
+
+export * from './indexpattern';
diff --git a/x-pack/plugins/visualization_lens/public/indexpattern_datasource/indexpattern.tsx b/x-pack/plugins/visualization_lens/public/indexpattern_datasource/indexpattern.tsx
new file mode 100644
index 0000000000000..32c80aeb78c5a
--- /dev/null
+++ b/x-pack/plugins/visualization_lens/public/indexpattern_datasource/indexpattern.tsx
@@ -0,0 +1,67 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { render } from 'react-dom';
+import { Datasource, Operation, DataType } from '../';
+
+interface IndexPatternPrivateState {
+  query: object;
+}
+
+class IndexPatternDatasource implements Datasource<IndexPatternPrivateState> {
+  private state?: IndexPatternPrivateState;
+
+  constructor(state?: IndexPatternPrivateState) {
+    if (state) {
+      this.state = state;
+    }
+  }
+
+  toExpression() {
+    return '';
+  }
+
+  renderDataPanel({ domElement }: { domElement: Element }) {
+    render(<div>Index Pattern Data Source</div>, domElement);
+  }
+
+  getPublicAPI() {
+    return {
+      getTableSpec: () => [],
+      getOperationForColumnId: () => ({
+        id: '',
+        // User-facing label for the operation
+        label: '',
+        dataType: 'string' as DataType,
+        // A bucketed operation has many values the same
+        isBucketed: false,
+      }),
+
+      // Called by dimension
+      getDimensionPanelComponent: (props: any) => (
+        domElement: Element,
+        operations: Operation[]
+      ) => {},
+
+      removeColumnInTableSpec: (columnId: string) => [],
+      moveColumnTo: (columnId: string, targetIndex: number) => {},
+      duplicateColumn: (columnId: string) => [],
+    };
+  }
+
+  getDatasourceSuggestionsForField() {
+    return [];
+  }
+
+  getDatasourceSuggestionsFromCurrentState() {
+    return [];
+  }
+}
+
+export { IndexPatternDatasource };
+
+export const indexPatternDatasource = new IndexPatternDatasource();
diff --git a/x-pack/plugins/visualization_lens/public/types.ts b/x-pack/plugins/visualization_lens/public/types.ts
new file mode 100644
index 0000000000000..7cb1c1af69a31
--- /dev/null
+++ b/x-pack/plugins/visualization_lens/public/types.ts
@@ -0,0 +1,176 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export interface EditorFrameAPI {
+  render: (domElement: Element) => void;
+  registerDatasource: (datasource: Datasource<unknown>) => void;
+  registerVisualization: (visualization: Visualization<unknown>) => void;
+}
+
+export interface EditorFrameState {
+  visualizations: { [id: string]: object };
+  datasources: { [id: string]: object };
+
+  activeDatasourceId: string;
+  activeVisualizationId: string;
+}
+
+// Hints the default nesting to the data source. 0 is the highest priority
+export type DimensionPriority = 0 | 1 | 2;
+
+// For switching between visualizations and correctly matching columns
+export type DimensionRole =
+  | 'splitChart'
+  | 'series'
+  | 'primary'
+  | 'secondary'
+  | 'color'
+  | 'size'
+  | string; // Some visualizations will use custom names that have other meaning
+
+export interface TableMetaInfo {
+  columnId: string;
+  operation: Operation;
+}
+
+export interface DatasourceSuggestion<T> {
+  state: T;
+  tableMetas: TableMetaInfo[];
+}
+
+/**
+ * Interface for the datasource registry
+ */
+export interface Datasource<T> {
+  // For initializing from saved object
+  // initialize: (state?: T) => Promise<T>;
+
+  renderDataPanel: (props: DatasourceDataPanelProps) => void;
+
+  toExpression: (state: T) => string;
+
+  getDatasourceSuggestionsForField: (state: T) => Array<DatasourceSuggestion<T>>;
+  getDatasourceSuggestionsFromCurrentState: (state: T) => Array<DatasourceSuggestion<T>>;
+
+  getPublicAPI: (state: T, setState: (newState: T) => void) => DatasourcePublicAPI;
+  // publicAPI: {
+  //   [key in keyof DatasourcePublicAPI]: (
+  //     state: T,
+  //     setState: (newState: T) => void
+  //   ) => DatasourcePublicAPI[key]
+  // };
+}
+
+/**
+ * This is an API provided to visualizations by the frame, which calls the publicAPI on the datasource
+ */
+export interface DatasourcePublicAPI {
+  getTableSpec: () => TableSpec;
+  getOperationForColumnId: () => Operation;
+
+  // Called by dimension
+  getDimensionPanelComponent: (
+    props: DatasourceDimensionPanelProps
+  ) => (domElement: Element, operations: Operation[]) => void;
+
+  removeColumnInTableSpec: (columnId: string) => TableSpec;
+  moveColumnTo: (columnId: string, targetIndex: number) => void;
+  duplicateColumn: (columnId: string) => TableSpec;
+}
+
+export interface DatasourceDataPanelProps {
+  domElement: Element;
+}
+
+// The only way a visualization has to restrict the query building
+export interface DatasourceDimensionPanelProps {
+  // If no columnId is passed, it will render as empty
+  columnId?: string;
+
+  // Visualizations can restrict operations based on their own rules
+  filterOperations: (operation: Operation) => boolean;
+
+  // Visualizations can hint at the role this dimension would play, which
+  // affects the ordering of the query
+  suggestedPriority?: DimensionPriority;
+}
+
+export interface DatasourceValidationError {
+  type: 'error';
+}
+
+export interface DatasourceValidationValid {
+  type: 'valid';
+}
+
+export type DataType = 'string' | 'number' | 'date' | 'boolean';
+
+// An operation does not represent a column in the datatable
+export interface Operation {
+  // Operation ID is a reference to the operation
+  id: string;
+  // User-facing label for the operation
+  label: string;
+  dataType: DataType;
+  // A bucketed operation has many values the same
+  isBucketed: boolean;
+
+  // Extra meta-information like cardinality, color
+}
+
+export interface TableSpecColumn {
+  // Column IDs are the keys for internal state in data sources and visualizations
+  columnId: string;
+}
+
+// TableSpec is managed by visualizations
+export type TableSpec = TableSpecColumn[];
+
+export type VisualizationTableRequest = Array<{
+  dataType: 'string' | 'number';
+  isBucketed: boolean;
+}>;
+
+export interface VisualizationProps<T> {
+  datasource: DatasourcePublicAPI;
+  state: T;
+  setState: (newState: T) => void;
+}
+
+export interface VisualizationSuggestion<T> {
+  score: number;
+  title: string;
+  state: T;
+  datasourceSuggestionId: string;
+}
+
+export interface Visualization<T> {
+  // Used to switch to this visualization from another
+  getInitialStateFromOtherVisualization: (
+    options: {
+      roles: DimensionRole[];
+      datasource: DatasourcePublicAPI;
+      state?: T;
+    }
+  ) => T[];
+
+  renderConfigPanel: (props: VisualizationProps<T>) => void;
+
+  toExpression: (state: T, datasource: DatasourcePublicAPI) => string;
+
+  // For use in transitioning from one viz to another
+  getMappingOfTableToRoles: (state: T, datasource: DatasourcePublicAPI) => DimensionRole[];
+
+  // Filter suggestions from datasource to good suggestions, used for suggested visualizations
+  // Can be used to switch to a better visualization given the data table
+  getSuggestionsFromTableSpecs: (
+    options: {
+      roles: DimensionRole[];
+      tableMetas: { [datasourceSuggestionId: string]: TableMetaInfo };
+      state?: T; // State is only passed if the visualization is active
+    }
+  ) => Array<VisualizationSuggestion<T>>;
+}
diff --git a/x-pack/tsconfig.json b/x-pack/tsconfig.json
index 979d0737d03a9..20f95464c5867 100644
--- a/x-pack/tsconfig.json
+++ b/x-pack/tsconfig.json
@@ -26,6 +26,9 @@
       "plugins/spaces/*": [
         "x-pack/plugins/spaces/public/*"
       ],
+      "plugins/visualization_lens": [
+        "x-pack/plugins/visualization_lens/public/*"
+      ],
       "test_utils/*": [
         "x-pack/test_utils/*"
       ]
diff --git a/yarn.lock b/yarn.lock
index 5cabe828eb0ca..74142439021e8 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1317,10 +1317,10 @@
     lodash "^4.17.11"
     to-fast-properties "^2.0.0"
 
-"@elastic/charts@^3.11.0":
-  version "3.11.3"
-  resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-3.11.3.tgz#5a7f00f620020593d7124774471833eafdac200b"
-  integrity sha512-rssmYs3IwjbBNMFaCfplt9Nub0mqO7Bjq0A7C1iF/E51P1F5ST3HxPI7nLSFWILfpGk5Jx4sqO+61Q6rEehbVg==
+"@elastic/charts@^4.0.0":
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-4.0.0.tgz#321313873985deb69106d479ee6a827eb81c890a"
+  integrity sha512-j/DfpdsKOx/QEbWJ6CvLlLP6XUYWqAHyuho3+38HngnoZSPzLGLte/ymW1CnaNYthQGTS9/4a47aZCkvQ6EdBw==
   dependencies:
     "@types/d3-shape" "^1.3.1"
     "@types/luxon" "^1.11.1"