mirror of
https://github.com/tcsenpai/autogpt-gui.git
synced 2025-06-02 15:30:04 +00:00
Initial commit
This commit is contained in:
commit
cc7498a96a
23
.cleanthat/cleanthat.yaml
Normal file
23
.cleanthat/cleanthat.yaml
Normal file
@ -0,0 +1,23 @@
|
||||
syntax_version: "2023-01-09"
|
||||
meta:
|
||||
labels:
|
||||
- "cleanthat"
|
||||
refs:
|
||||
protected_patterns:
|
||||
- "refs/heads/develop"
|
||||
- "refs/heads/main"
|
||||
- "refs/heads/master"
|
||||
full_clean_on_configuration_change: false
|
||||
can_edit_not_protected_branches: true
|
||||
source_code:
|
||||
encoding: "UTF-8"
|
||||
line_ending: "GIT"
|
||||
engines:
|
||||
- engine: "spotless"
|
||||
skip: false
|
||||
source_code: {}
|
||||
steps:
|
||||
- id: "spotless"
|
||||
skip: false
|
||||
parameters:
|
||||
configuration: "repository:/.cleanthat/spotless.yaml"
|
26
.cleanthat/spotless.yaml
Normal file
26
.cleanthat/spotless.yaml
Normal file
@ -0,0 +1,26 @@
|
||||
syntax_version: "2023-01-09"
|
||||
encoding: "UTF-8"
|
||||
git:
|
||||
core_eol: "native"
|
||||
line_ending: "GIT_ATTRIBUTES"
|
||||
formatters:
|
||||
- format: "json"
|
||||
steps:
|
||||
- id: "jackson"
|
||||
skip: false
|
||||
parameters:
|
||||
features:
|
||||
ORDER_MAP_ENTRIES_BY_KEYS: true
|
||||
yaml_features:
|
||||
QUOTE_FIELD_NAMES: false
|
||||
- format: "markdown"
|
||||
steps:
|
||||
- id: "flexmark"
|
||||
skip: false
|
||||
parameters:
|
||||
version: "0.62.2"
|
||||
- id: "freshmark"
|
||||
skip: false
|
||||
parameters:
|
||||
properties:
|
||||
k1: "v1"
|
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
package-lock.json
|
||||
node_modules
|
||||
.env
|
||||
output.txt
|
52
README.md
Normal file
52
README.md
Normal file
@ -0,0 +1,52 @@
|
||||
# AutoGPT GUI
|
||||
|
||||
WARNING: Currently discontinued, feel free to fork and work on this version but don't lean on it for production
|
||||
|
||||
## A graphical user interface to AutoGPT
|
||||
|
||||

|
||||
|
||||
|
||||
### Status
|
||||
|
||||
*Alpha has been tested with simple tasks, remember it will probably contains errors and please open issues about them*
|
||||
|
||||
*NOTE: Currently only continuous mode is supported*
|
||||
|
||||
***Current Version:*** Alpha Version (13 April 2023)
|
||||
|
||||
- [x] Code architecture definition
|
||||
- [x] All needed elements are in GUI
|
||||
- [x] Defining the best way to integrate autogpt
|
||||
- [x] Actual integeration of autogpt
|
||||
- [x] Alpha Version Release
|
||||
- [ ] Ability to work in non continuous mode
|
||||
- [ ] Debug of Alpha (issues are welcomed!)
|
||||
- [ ] Beta Version Release
|
||||
|
||||
### Usage
|
||||
|
||||
git clone https://github.com/thecookingsenpai/autogpt-gui
|
||||
cd autogpt-gui
|
||||
npm install
|
||||
|
||||
Then, place autogpt-gui in your autogpt folder (e.g. AutoGPT/autogpt_gui)
|
||||
|
||||
Finally, in your autogpt folder:
|
||||
|
||||
cd autogpt-gui
|
||||
npm start
|
||||
|
||||
**Important:** please take a moment to read [autogpt instructions](https://github.com/Torantulino/Auto-GPT#usage) to avoid risks and to learn the meaning of the various options.
|
||||
|
||||
### Credits
|
||||
|
||||
The original AutoGPT is by Torantulino and can be found [HERE](https://github.com/Torantulino/Auto-GPT).
|
||||
|
||||
All the credits included in the original AutoGPT are valid for this project as long as the single components are used.
|
||||
|
||||
This project is by TheCookingSenpai.
|
||||
|
||||
### License
|
||||
|
||||
Distributed under the CC-BY-NC 4.0 License
|
BIN
assets/gui.png
Normal file
BIN
assets/gui.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 168 KiB |
BIN
assets/icon.png
Normal file
BIN
assets/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.5 KiB |
66
index.html
Normal file
66
index.html
Normal file
@ -0,0 +1,66 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
|
||||
<meta http-equiv="Content-Security-Policy"
|
||||
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'">
|
||||
<link href="./styles.css" rel="stylesheet">
|
||||
<title>AutoGPT GUI</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h3 class="centered expand">AutoGPT Graphical User Interface</h3>
|
||||
<h5 class="small centered expand">AutoGPT created by Torantulino - GUI created by TheCookingSenpai</h5>
|
||||
<div class="centered">
|
||||
<div class="card tilt-top" id="settings">
|
||||
<div class="oneliner">
|
||||
<h4>Choose your AI personality (e.g. an AI that can write essays)</h4>
|
||||
<h5 class="sameline">Your AI is: </h5>
|
||||
<input class="sameline wide" type="text" id="zone_personality">
|
||||
<h5 class="sameline"> And is named: </h5>
|
||||
<input class="sameline" type="text" id="zone_name">
|
||||
</div>
|
||||
<div class="halfcard">
|
||||
<h4>Define up to 5 goals for your AI</h4>
|
||||
<div class="oneliner">
|
||||
<h5 class="sameline">Goal 1</h5>
|
||||
<input class="sameline" type="text" id="zone_goal_1">
|
||||
<h5 class="sameline">Goal 2</h5>
|
||||
<input class="sameline" type="text" id="zone_goal_2">
|
||||
</div>
|
||||
<div class="oneliner">
|
||||
<h5 class="sameline">Goal 3</h5>
|
||||
<input class="sameline" type="text" id="zone_goal_3">
|
||||
<h5 class="sameline">Goal 4</h5>
|
||||
<input class="sameline" type="text" id="zone_goal_4">
|
||||
</div>
|
||||
<div class="oneliner">
|
||||
<h5 class="sameline">Goal 5</h5>
|
||||
<input class="sameline" type="text" id="zone_goal_5">
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="oneliner">
|
||||
<input class="sameline" type="checkbox" id="cfg_continuous" unchecked>Contiuous Mode</input>
|
||||
<input class="sameline" type="checkbox" id="cfg_debug" unchecked>Debug Mode</input>
|
||||
<input class="sameline" type="checkbox" id="cfg_speak" unchecked>Speak Mode</input>
|
||||
<input class="sameline" type="checkbox" id="cfg_save" unchecked>Save output to file</input>
|
||||
</div>
|
||||
<br>
|
||||
<div class="hidden red" id="zone_error"></div>
|
||||
<button class="centered" id="cmd_execute">Go!</button>
|
||||
<br>
|
||||
</div>
|
||||
<div class="output_space card tilt-top" id="output">
|
||||
<h4>Output</h4>
|
||||
<div class="output_space scrollable output_text" id="zone_output"></div>
|
||||
</div>
|
||||
<button class="centered hidden" id="cmd_stop">Stop</button>
|
||||
</div>
|
||||
<!-- You can also require other files to run in this process -->
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
40
main.js
Normal file
40
main.js
Normal file
@ -0,0 +1,40 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const {app, BrowserWindow, screen} = require('electron')
|
||||
const path = require('path')
|
||||
var width;
|
||||
var height;
|
||||
|
||||
function createWindow () {
|
||||
let sizes = screen.getPrimaryDisplay().workAreaSize
|
||||
width = sizes.width
|
||||
height = sizes.height
|
||||
// Create the browser window.
|
||||
const mainWindow = new BrowserWindow({
|
||||
icon: path.join(__dirname, 'assets/icon.png'),
|
||||
width: width,
|
||||
height: height,
|
||||
webPreferences: {
|
||||
// Enabling nodejs
|
||||
nodeIntegration: true,
|
||||
contextIsolation: false
|
||||
}
|
||||
})
|
||||
|
||||
// and loading the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS it's common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||
})
|
||||
})
|
||||
|
||||
// Quit when all windows are closed
|
||||
app.on('window-all-closed', function () {
|
||||
app.quit()
|
||||
})
|
22
package.json
Normal file
22
package.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "electron-quick-start",
|
||||
"version": "1.0.0",
|
||||
"description": "A minimal Electron application",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"start": "electron ."
|
||||
},
|
||||
"repository": "https://github.com/electron/electron-quick-start",
|
||||
"keywords": [
|
||||
"Electron",
|
||||
"quick",
|
||||
"start",
|
||||
"tutorial",
|
||||
"demo"
|
||||
],
|
||||
"author": "GitHub",
|
||||
"license": "CC0-1.0",
|
||||
"devDependencies": {
|
||||
"electron": "^23.2.1"
|
||||
}
|
||||
}
|
173
script.js
Normal file
173
script.js
Normal file
@ -0,0 +1,173 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path')
|
||||
const { spawn } = require('child_process');
|
||||
const { error } = require('console');
|
||||
var child_autogpt = null
|
||||
var first_input = false
|
||||
let save_output = false
|
||||
|
||||
|
||||
// ANCHOR Getting GUI elements needed
|
||||
// Actions
|
||||
const cmd_execute = document.getElementById('cmd_execute')
|
||||
const cmd_stop = document.getElementById('cmd_stop')
|
||||
// Configurations
|
||||
const cfg_debug = document.getElementById('cfg_debug')
|
||||
const cfg_continuous = document.getElementById('cfg_continuous')
|
||||
const cfg_speak = document.getElementById('cfg_speak')
|
||||
const cfg_save = document.getElementById('cfg_save')
|
||||
// Utilities
|
||||
const util_installDeps = document.getElementById('util_installDeps')
|
||||
// Zones
|
||||
const zone_personality = document.getElementById('zone_personality')
|
||||
const zone_name = document.getElementById('zone_name')
|
||||
const zone_output = document.getElementById('zone_output')
|
||||
const zone_error = document.getElementById('zone_error')
|
||||
|
||||
// Variables
|
||||
var is_running = false
|
||||
|
||||
// NOTE Initial configuration
|
||||
async function init() {
|
||||
// Setting up listeners
|
||||
cmd_execute.addEventListener('click', async () => {
|
||||
console.log("Execute button clicked")
|
||||
if (is_running) return // Avoid multiple executions
|
||||
// Executing autogpt on click on the Go button
|
||||
console.log('Executing')
|
||||
zone_output.innerHTML = ''
|
||||
let args = await get_args_from_gui()
|
||||
console.log(args)
|
||||
is_running = true
|
||||
await execute_autogpt(args)
|
||||
is_running = false
|
||||
});
|
||||
|
||||
cmd_stop.addEventListener('click', async () => {
|
||||
console.log("Stop button clicked")
|
||||
if (child_autogpt) {
|
||||
child_autogpt.kill()
|
||||
cmd_stop.classList.add('disabled')
|
||||
zone_output.scrollTop = zone_output.scrollHeight
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// NOTE Gives back the arguments from the GUI
|
||||
async function get_args_from_gui() {
|
||||
// Configuration
|
||||
let _args = {
|
||||
name: zone_name.value,
|
||||
personality: zone_personality.value,
|
||||
goals: [],
|
||||
debug: cfg_debug.checked,
|
||||
continuous: cfg_continuous.checked,
|
||||
speak: cfg_speak.checked,
|
||||
save: cfg_save.checked
|
||||
}
|
||||
// Fetching goals
|
||||
for (let i = 1; i <= 5; i++) {
|
||||
let goal = document.getElementById(`zone_goal_${i}`).value
|
||||
_args.goals.push(goal)
|
||||
}
|
||||
return _args
|
||||
}
|
||||
|
||||
async function execute_autogpt(args) {
|
||||
if (!zone_error.classList.contains('hidden')) {
|
||||
zone_error.classList.add('hidden')
|
||||
}
|
||||
zone_error.innerHTML = ''
|
||||
// Sanity check
|
||||
if (args.goals[0] == '') {
|
||||
if (zone_error.classList.contains('hidden')) zone_error.classList.remove('hidden')
|
||||
zone_error.innerHTML = 'You need to specify at least one goal'
|
||||
return
|
||||
}
|
||||
if (args.personality == '') {
|
||||
if (zone_error.classList.contains('hidden')) zone_error.classList.remove('hidden')
|
||||
zone_error.innerHTML = 'You need to specify a personality'
|
||||
return
|
||||
}
|
||||
if (args.name == '') {
|
||||
args.name = 'Autogpt'
|
||||
}
|
||||
// TODO write the settings to ai_settings.yaml
|
||||
let settings = "ai_goals: \n"
|
||||
for (let i = 0; i < args.goals.length; i++) {
|
||||
settings += `- ${args.goals[i]}\n`
|
||||
}
|
||||
settings += "ai_name: " + args.name + "\n"
|
||||
settings += "ai_role: " + args.personality + "\n"
|
||||
fs.writeFileSync('../ai_settings.yaml', settings)
|
||||
// Define the arguments
|
||||
let additionals = []
|
||||
if (args.debug) {
|
||||
additionals.push('--debug')
|
||||
}
|
||||
if (args.continuous) {
|
||||
additionals.push('--continuous')
|
||||
}
|
||||
if (args.speak) {
|
||||
additionals.push('--speak')
|
||||
}
|
||||
if (args.save) {
|
||||
save_output = true
|
||||
}
|
||||
// REVIEW Run ../scripts/main.py and redirect all the output to a variable live in the GUI
|
||||
// Set up the command
|
||||
let cmd = 'python'
|
||||
let args_cmd = ['scripts/main.py']
|
||||
// Pushing the arguments
|
||||
args_cmd.push(...additionals)
|
||||
// Executing
|
||||
child_autogpt = spawn(cmd, args_cmd, {cwd: path.join(__dirname, '..')})
|
||||
if (child_autogpt.pid) {
|
||||
console.log('Child process started with PID ${child_autogpt.pid}')
|
||||
cmd_stop.classList.remove('hidden')
|
||||
}
|
||||
// INFO Setting up listeners
|
||||
child_autogpt.stdout.on('data', (data) => {
|
||||
console.log(`stdout: ${data}`);
|
||||
if (data.includes('Thinking...')) {
|
||||
if (zone_output.innerHTML.includes('Thinking...') ){
|
||||
data = "."
|
||||
}
|
||||
}
|
||||
// Go to the next line if the last character is thinking
|
||||
if (data.includes('Thinking...')) {
|
||||
zone_output.innerHTML += '<br>'
|
||||
}
|
||||
// Try to detect new lines
|
||||
if (data.includes('\n')) {
|
||||
zone_output.innerHTML += '<br>|>|> '
|
||||
}
|
||||
zone_output.innerHTML += data
|
||||
// Scroll to the bottom
|
||||
zone_output.scrollTop = zone_output.scrollHeight
|
||||
// NOTE if specified, save the output to a file
|
||||
if (save_output) {
|
||||
fs.appendFileSync(path.join(__dirname, 'output.txt'), data)
|
||||
}
|
||||
// NOTE If the first input is required, send a 'y' to the child process to read from ai_settings.yaml
|
||||
if (data.includes('(y/n)')) {
|
||||
if (!first_input) {
|
||||
first_input = true
|
||||
child_autogpt.stdin.write('y\n')
|
||||
}
|
||||
}
|
||||
});
|
||||
child_autogpt.stderr.on('data', (data) => {
|
||||
console.error(`stderr: ${data}`);
|
||||
zone_output.innerHTML += '<br><span class"red">' + data + '</span>'
|
||||
});
|
||||
child_autogpt.on('close', (code) => {
|
||||
console.log(`child process exited with code ${code}`);
|
||||
zone_output.innerHTML += '<br><p class"red">child process exited with code ' + code + '</p>'
|
||||
cmd_stop.classList.add('hidden')
|
||||
});
|
||||
}
|
||||
|
||||
(async () => {
|
||||
await init()
|
||||
}) ();
|
212
styles.css
Normal file
212
styles.css
Normal file
@ -0,0 +1,212 @@
|
||||
/* styles.css */
|
||||
body {
|
||||
background-color: #000000;
|
||||
color: #02cc53;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 21px;
|
||||
line-height: 1.42857143;
|
||||
margin: 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
input {
|
||||
border-radius: 20px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: #000000;
|
||||
color: #02cc53;
|
||||
border: 1px solid #02cc53;
|
||||
border-radius: 15px;
|
||||
font-size: 24px;
|
||||
padding: 10px;
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
button:hover
|
||||
{
|
||||
background-color: #02cc53;
|
||||
color: #000000;
|
||||
}
|
||||
/* Element Styles */
|
||||
|
||||
.centered {
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.rounded {
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
.card {
|
||||
border: 1px solid #02cc53;
|
||||
border-radius: 15px;
|
||||
padding: 5px;
|
||||
margin: 25px;
|
||||
margin-bottom: 10px !important;
|
||||
box-shadow: 0 0 10px #02cc53;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
|
||||
.halfcard {
|
||||
border: 1px solid #000;
|
||||
border-radius: 15px;
|
||||
padding: 5px;
|
||||
box-shadow: 0 0 10px #000;
|
||||
width: 70%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
|
||||
.oneliner {
|
||||
white-space: nowrap;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.sameline {
|
||||
display: inline-block;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.wide {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.output_space {
|
||||
height: fit-content !important;
|
||||
border-radius: 5px !important;
|
||||
}
|
||||
|
||||
.output_text {
|
||||
border: 1px solid #02cc53 !important;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.scrollable {
|
||||
overflow-y: scroll !important;
|
||||
height: 75% !important;
|
||||
}
|
||||
|
||||
.red {
|
||||
color: #ff0000 !important;
|
||||
}
|
||||
|
||||
.small {
|
||||
font-size: 10px !important;
|
||||
}
|
||||
/* Animations */
|
||||
/* ----------------------------------------------
|
||||
* Generated by Animista on 2023-4-11 20:26:10
|
||||
* Licensed under FreeBSD License.
|
||||
* See http://animista.net/license for more info.
|
||||
* w: http://animista.net, t: @cssanimista
|
||||
* ---------------------------------------------- */
|
||||
|
||||
.tilt-top {
|
||||
-webkit-animation: tilt-in-top-1 0.6s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
|
||||
animation: tilt-in-top-1 0.6s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
|
||||
}
|
||||
|
||||
.pop-up {
|
||||
-webkit-animation: text-pop-up-top 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
|
||||
animation: text-pop-up-top 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
|
||||
}
|
||||
|
||||
.expand {
|
||||
-webkit-animation: tracking-in-expand 0.7s cubic-bezier(0.215, 0.610, 0.355, 1.000) both 0.5s;
|
||||
animation: tracking-in-expand 0.7s cubic-bezier(0.215, 0.610, 0.355, 1.000) both 0.5s;
|
||||
}
|
||||
|
||||
@-webkit-keyframes tracking-in-expand {
|
||||
0% {
|
||||
letter-spacing: -0.5em;
|
||||
opacity: 0;
|
||||
}
|
||||
40% {
|
||||
opacity: 0.6;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
@keyframes tracking-in-expand {
|
||||
0% {
|
||||
letter-spacing: -0.5em;
|
||||
opacity: 0;
|
||||
}
|
||||
40% {
|
||||
opacity: 0.6;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@-webkit-keyframes text-pop-up-top {
|
||||
0% {
|
||||
-webkit-transform: translateY(0);
|
||||
transform: translateY(0);
|
||||
-webkit-transform-origin: 50% 50%;
|
||||
transform-origin: 50% 50%;
|
||||
text-shadow: none;
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: translateY(-50px);
|
||||
transform: translateY(-50px);
|
||||
-webkit-transform-origin: 50% 50%;
|
||||
transform-origin: 50% 50%;
|
||||
text-shadow: 0 1px 0 #cccccc, 0 2px 0 #cccccc, 0 3px 0 #cccccc, 0 4px 0 #cccccc, 0 5px 0 #cccccc, 0 6px 0 #cccccc, 0 7px 0 #cccccc, 0 8px 0 #cccccc, 0 9px 0 #cccccc, 0 50px 30px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
}
|
||||
@keyframes text-pop-up-top {
|
||||
0% {
|
||||
-webkit-transform: translateY(0);
|
||||
transform: translateY(0);
|
||||
-webkit-transform-origin: 50% 50%;
|
||||
transform-origin: 50% 50%;
|
||||
text-shadow: none;
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: translateY(-50px);
|
||||
transform: translateY(-50px);
|
||||
-webkit-transform-origin: 50% 50%;
|
||||
transform-origin: 50% 50%;
|
||||
text-shadow: 0 1px 0 #cccccc, 0 2px 0 #cccccc, 0 3px 0 #cccccc, 0 4px 0 #cccccc, 0 5px 0 #cccccc, 0 6px 0 #cccccc, 0 7px 0 #cccccc, 0 8px 0 #cccccc, 0 9px 0 #cccccc, 0 50px 30px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes tilt-in-top-1 {
|
||||
0% {
|
||||
-webkit-transform: rotateY(30deg) translateY(-300px) skewY(-30deg);
|
||||
transform: rotateY(30deg) translateY(-300px) skewY(-30deg);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotateY(0deg) translateY(0) skewY(0deg);
|
||||
transform: rotateY(0deg) translateY(0) skewY(0deg);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
@keyframes tilt-in-top-1 {
|
||||
0% {
|
||||
-webkit-transform: rotateY(30deg) translateY(-300px) skewY(-30deg);
|
||||
transform: rotateY(30deg) translateY(-300px) skewY(-30deg);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotateY(0deg) translateY(0) skewY(0deg);
|
||||
transform: rotateY(0deg) translateY(0) skewY(0deg);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user