Understanding ctools_modal_form_wrapper
I found a better explanation here so I'm not going to explain much about the $form_state itself here. 

To present a form, you have to use drupal_get_form() function that returns a render-able array of the form. 
To build the form, you need to give a form ID (to get the form API arrays) and the state of the form. Form State ($form_state) becomes handy when you need to store arguments, previous step values, and many more (see the linked post above). 

Ctools modal forms has many basic features. 


Detecting whether JavaScript is available in the user's browser. 
Falling back to normal HTML forms if JS is not enabled in the browser. 
Keep form validation and submit functions working in the popup form. 
Executing certain functions when the form is submitted. 


Here is an example of a full Modal form menu router item. Note that I'm not using %ctools_js menu loaders to make this simple: 

function quotes_editform_ajax($form, &amp;$form_state, $quote){
  ctools_include('ajax');
  ctools_include('modal');
  $form_state = array(
    'ajax' =&gt; true,
    'title' =&gt; t('Edit quote'), 
    'is_ajax_update' =&gt; TRUE,
    'quote' =&gt; $quote,
  );

  $output = ctools_modal_form_wrapper('quotes_editform', $form_state);

  if (!empty($form_state['executed'])) {

    // Add the responder javascript, required by ctools
    ctools_add_js('ajax-responder');

    // Create ajax command array, dismiss the modal window.
    $output = array();
    $output[] = ctools_modal_command_dismiss();
    $output[] = ctools_ajax_command_reload();
  }

  print ajax_render($output);
  exit();
}


Explanation:

  ctools_include('ajax');
  ctools_include('modal');


These functions will include specific ctools plugins for our use. 



  $form_state = array(
    'ajax' =&gt; true,
    'title' =&gt; t('Edit quote'), 
    'is_ajax_update' =&gt; TRUE,
    'quote' =&gt; $quote,
  );


Here we build the $form_state to pass to the form builder function (drupal_get_form(). ctools_modal_form_wrapper() calls drupal_get_form()). 



$output = ctools_modal_form_wrapper('quotes_editform', $form_state);


Here, we build renderable array of the form. But the difference between drupal_get_form() is that it's actually in Ajax response form. 
quotes_editform is a function that returns a form array. 

function quotes_editform($form, &amp;$form_state) {
  $form['name'] = array(
    '#title' =&gt; t('Name'),
    '#type' =&gt; 'textfield',
    '#default_value' =&gt; !empty($form_state['quote']-&gt;title) 
       ? $form_state['quote']-&gt;title
       : '',
  );
  return $form;
}


In this $form_state array, ajax and title keys are ctools-specific. The title will be the popup's title and ajax is required to Ajax-ify the form. 
Pay attention to the #default_value of the above snippet. If we are going to show an edit form, we need to know the existing values. So we send whatever we have to the form builder function. 

Node forms are a little complex that there is a base form and child forms for each form. 
This form ID is same as what you receive as the third parameter in hook_form_alter($form, $form_state, $form_id) hooks. 

You are free to store whatever in this $form_state array. 
$form_state array is passed to submit and validation functions so any of those functions can make use of those data.